swift - Singleton pattern and proper use of Alamofire's URLRequestConvertible -
this 2 part question first similar question here: proper usage of alamofire's urlrequestconvertible. need little more help!
1) create enum router implements urlrequestconvertible each model in model layer?
the alamofire github page provides example of router i've copied here:
enum router: urlrequestconvertible { static let baseurlstring = "http://example.com" static var oauthtoken: string? case createuser([string: anyobject]) case readuser(string) case updateuser(string, [string: anyobject]) case destroyuser(string) var method: alamofire.method { switch self { case .createuser: return .post case .readuser: return .get case .updateuser: return .put case .destroyuser: return .delete } } var path: string { switch self { case .createuser: return "/users" case .readuser(let username): return "/users/\(username)" case .updateuser(let username, _): return "/users/\(username)" case .destroyuser(let username): return "/users/\(username)" } } // mark: urlrequestconvertible var urlrequest: nsurlrequest { let url = nsurl(string: router.baseurlstring)! let mutableurlrequest = nsmutableurlrequest(url: url.urlbyappendingpathcomponent(path)) mutableurlrequest.httpmethod = method.rawvalue if let token = router.oauthtoken { mutableurlrequest.setvalue("bearer \(token)", forhttpheaderfield: "authorization") } switch self { case .createuser(let parameters): return alamofire.parameterencoding.json.encode(mutableurlrequest, parameters: parameters).0 case .updateuser(_, let parameters): return alamofire.parameterencoding.url.encode(mutableurlrequest, parameters: parameters).0 default: return mutableurlrequest } } }
when @ (i'm new @ swift please bear me >_<) see operations on user object; creating user, updating user etc... so, if had model objects person, company, location in model layer, create router each model object?
2) when interacting heavily api, i'm used creating "network manager" singleton abstract away network layer , hold headers , baseurl api. alamofire has "manager" described here:
top-level convenience methods alamofire.request use shared instance of alamofire.manager, configured default nsurlsessionconfiguration. such, following 2 statements equivalent:
alamofire.request(.get, "http://httpbin.org/get") let manager = alamofire.manager.sharedinstance manager.request(nsurlrequest(url: nsurl(string: "http://httpbin.org/get")))
is manager should using singleton? if so, how set baseurl on manager? also, if use manager / can work router construct shown above (with each model object setting it's baseurl , nsurlrquest)? if can provide simple example?
i'm new alamofire library , swift. so, know there lot of holes in understanding i'm trying understand best can! info helps. thanks.
these questions. let me attempt answer each 1 in turn.
do create enum router implements urlrequestconvertible each model in model layer?
this great question , unfortunately there's no 1 perfect answer. there ways extend router
pattern accommodate multiple object types. first option add more cases support object type. however, gets hairy pretty when more 6 or 7 cases. switch statements start out-of-control. therefore, wouldn't recommend approach.
another way approach problem introducing generics router
.
routerobject protocol
protocol routerobject { func createobjectpath() -> string func readobjectpath(identifier: string) -> string func updateobjectpath(identifier: string) -> string func destroyobjectpath(identifier: string) -> string }
model objects
struct user: routerobject { let rootpath = "/users" func createobjectpath() -> string { return rootpath } func readobjectpath(identifier: string) -> string { return "\(rootpath)/\(identifier)" } func updateobjectpath(identifier: string) -> string { return "\(rootpath)/\(identifier)" } func destroyobjectpath(identifier: string) -> string { return "\(rootpath)/\(identifier)" } } struct company: routerobject { let rootpath = "/companies" func createobjectpath() -> string { return rootpath } func readobjectpath(identifier: string) -> string { return "\(rootpath)/\(identifier)" } func updateobjectpath(identifier: string) -> string { return "\(rootpath)/\(identifier)" } func destroyobjectpath(identifier: string) -> string { return "\(rootpath)/\(identifier)" } } struct location: routerobject { let rootpath = "/locations" func createobjectpath() -> string { return rootpath } func readobjectpath(identifier: string) -> string { return "\(rootpath)/\(identifier)" } func updateobjectpath(identifier: string) -> string { return "\(rootpath)/\(identifier)" } func destroyobjectpath(identifier: string) -> string { return "\(rootpath)/\(identifier)" } }
router
let baseurlstring = "http://example.com" var oauthtoken: string? enum router<t t: routerobject>: urlrequestconvertible { case createobject(t, [string: anyobject]) case readobject(t, string) case updateobject(t, string, [string: anyobject]) case destroyobject(t, string) var method: alamofire.method { switch self { case .createobject: return .post case .readobject: return .get case .updateobject: return .put case .destroyobject: return .delete } } var path: string { switch self { case .createobject(let object, _): return object.createobjectpath() case .readobject(let object, let identifier): return object.readobjectpath(identifier) case .updateobject(let object, let identifier, _): return object.updateobjectpath(identifier) case .destroyobject(let object, let identifier): return object.destroyobjectpath(identifier) } } // mark: urlrequestconvertible var urlrequest: nsmutableurlrequest { let url = nsurl(string: baseurlstring)! let mutableurlrequest = nsmutableurlrequest(url: url.urlbyappendingpathcomponent(path)) mutableurlrequest.httpmethod = method.rawvalue if let token = oauthtoken { mutableurlrequest.setvalue("bearer \(token)", forhttpheaderfield: "authorization") } switch self { case .createobject(_, let parameters): return alamofire.parameterencoding.json.encode(mutableurlrequest, parameters: parameters).0 case .updateobject(_, _, let parameters): return alamofire.parameterencoding.url.encode(mutableurlrequest, parameters: parameters).0 default: return mutableurlrequest } } }
example usage
func exampleusage() { let urlrequest = router.createobject(location(), ["address": "1234 road of awesomeness"]).urlrequest alamofire.request(urlrequest) .response { request, response, data, error in print(request) print(response) print(data) print(error) } }
now there few tradeoffs have make here. first off, model objects need conform routerobject
protocol. otherwise router
has no idea use path. also, you'll need make sure paths can constructed single identifier
. if cannot, design might not work. last issue cannot store baseurl
or oauthtoken
directly inside router
enum. unfortunately, static , stored properties not yet supported in generic enumerations.
regardless, valid way avoid having create router
every model object.
should
alamofire.manager.sharedinstance
used singletonnetworkmanager
instance?
it used in fashion. depends upon use case , how have designed network access. depends on how many different types of sessions need. if need background sessions , default sessions, still need concept of networkmanager
contains each custom manager
instance. however, if hitting network default session, sharedinstance
sufficient.
how
baseurl
ofalamofire
singleton used in conjunctionrouter
pattern?
good question...the code below 1 example of how done.
alamofire manager extension
extension manager { static let baseurlstring = "http://example.com" static var oauthtoken: string? }
router urlrequestconvertible updates
var urlrequest: nsmutableurlrequest { let url = nsurl(string: alamofire.manager.baseurlstring)! let mutableurlrequest = nsmutableurlrequest(url: url.urlbyappendingpathcomponent(path)) mutableurlrequest.httpmethod = method.rawvalue if let token = alamofire.manager.oauthtoken { mutableurlrequest.setvalue("bearer \(token)", forhttpheaderfield: "authorization") } switch self { case .createobject(_, let parameters): return alamofire.parameterencoding.json.encode(mutableurlrequest, parameters: parameters).0 case .updateobject(_, _, let parameters): return alamofire.parameterencoding.url.encode(mutableurlrequest, parameters: parameters).0 default: return mutableurlrequest } }
hopefully helps shed light. best of luck!
Comments
Post a Comment