单例模式和正确使用 Alamofire 的 URLRequestConvertible
Singleton pattern and proper use of Alamofire's URLRequestConvertible
这是一个由两部分组成的问题,第一部分类似于此处的这个问题:。但我需要更多帮助!
1) 我是否创建一个枚举路由器来为我的模型层中的每个模型实现 URLRequestConvertible?
alamofire github 页面提供了我在此处复制的路由器示例:
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
}
}
}
当我看到这个时(我是 swift 的新手所以请耐心等待 >_<)我看到了对用户 object 的操作;他们正在创建一个用户,更新一个用户等等...所以,如果我在我的模型层中有模型 object 的人、公司、位置,我会为每个模型 object 创建一个路由器吗?
2) 当与 API 大量交互时,我习惯于创建一个 "network manager" 单例来抽象出网络层并保存 headers 和它的 baseurl API。 alamofire 有一个 "Manager" 描述在这里:
Top-level convenience methods like Alamofire.request use a shared instance of Alamofire.Manager, which is configured with the default NSURLSessionConfiguration. As such, the following two statements are equivalent:
Alamofire.request(.GET, "http://httpbin.org/get")
let manager = Alamofire.Manager.sharedInstance
manager.request(NSURLRequest(URL: NSURL(string: "http://httpbin.org/get")))
这个管理器是我应该用作我的单身人士吗?如果是这样,我如何在经理上设置 baseurl?另外,如果我使用这个管理器,它是否/可以与上面显示的路由器构造一起工作(每个模型 object 设置它的 baseurl 和 NSURLRquest)?如果可以,您能提供一个简单的例子吗?
我是 Alamofire 库的新手 swift。所以,我知道我的理解有很多漏洞,但我只是想尽我所能去理解!任何信息都有帮助。谢谢
这些都是一些非常好的问题。让我尝试依次回答每个问题。
Do I create an enum router which implements URLRequestConvertible for each model in my model layer?
这是一个很好的问题,遗憾的是没有一个完美的答案。当然有一些方法可以扩展 Router
模式以适应多种对象类型。第一个选项是添加更多案例以支持另一种对象类型。但是,当您收到超过 6 或 7 个案例时,这很快就会变得棘手。您的 switch 语句刚刚开始失控。因此,我不推荐这种方法。
解决该问题的另一种方法是将泛型引入 Router
。
RouterObject 协议
protocol RouterObject {
func createObjectPath() -> String
func readObjectPath(identifier: String) -> String
func updateObjectPath(identifier: String) -> String
func destroyObjectPath(identifier: String) -> String
}
模型对象
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)" }
}
路由器
let baseURLString = "http://example.com"
var OAuthToken: String?
enum Router<T where 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
}
}
}
示例用法
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)
}
}
现在您必须在这里做出一些权衡。首先,您的模型对象需要符合 RouterObject
协议。否则 Router
不知道该路径使用什么。此外,您需要确保所有路径都可以使用单个 identifier
构建。如果不能,则此设计可能行不通。最后一个问题是您不能将 baseURL
或 OAuthToken
直接存储在 Router
枚举中。不幸的是,通用枚举尚不支持静态和存储属性。
无论如何,这肯定是避免为每个模型对象创建 Router
的有效方法。
Should the Alamofire.Manager.sharedInstance
be used as my singleton NetworkManager
instance?
当然可以这样使用。这实际上取决于您的用例以及您如何设计网络访问。它还取决于您需要多少不同类型的会话。如果您需要后台会话和默认会话,那么您可能仍然需要包含每个自定义 Manager
实例的 NetworkManager
的概念。但是,如果您只是使用默认会话访问网络,那么 sharedInstance
可能就足够了。
How could the baseURL
of the Alamofire
singleton be used in conjunction with the Router
pattern?
好问题...下面的代码是如何完成的一个示例。
Alamofire 管理器扩展
extension Manager {
static let baseURLString = "http://example.com"
static var OAuthToken: String?
}
路由器 URLRequestConvertible 更新
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
}
}
希望这有助于阐明一些问题。祝你好运!
这是一个由两部分组成的问题,第一部分类似于此处的这个问题:
1) 我是否创建一个枚举路由器来为我的模型层中的每个模型实现 URLRequestConvertible?
alamofire github 页面提供了我在此处复制的路由器示例:
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
}
}
}
当我看到这个时(我是 swift 的新手所以请耐心等待 >_<)我看到了对用户 object 的操作;他们正在创建一个用户,更新一个用户等等...所以,如果我在我的模型层中有模型 object 的人、公司、位置,我会为每个模型 object 创建一个路由器吗?
2) 当与 API 大量交互时,我习惯于创建一个 "network manager" 单例来抽象出网络层并保存 headers 和它的 baseurl API。 alamofire 有一个 "Manager" 描述在这里:
Top-level convenience methods like Alamofire.request use a shared instance of Alamofire.Manager, which is configured with the default NSURLSessionConfiguration. As such, the following two statements are equivalent:
Alamofire.request(.GET, "http://httpbin.org/get")
let manager = Alamofire.Manager.sharedInstance
manager.request(NSURLRequest(URL: NSURL(string: "http://httpbin.org/get")))
这个管理器是我应该用作我的单身人士吗?如果是这样,我如何在经理上设置 baseurl?另外,如果我使用这个管理器,它是否/可以与上面显示的路由器构造一起工作(每个模型 object 设置它的 baseurl 和 NSURLRquest)?如果可以,您能提供一个简单的例子吗?
我是 Alamofire 库的新手 swift。所以,我知道我的理解有很多漏洞,但我只是想尽我所能去理解!任何信息都有帮助。谢谢
这些都是一些非常好的问题。让我尝试依次回答每个问题。
Do I create an enum router which implements URLRequestConvertible for each model in my model layer?
这是一个很好的问题,遗憾的是没有一个完美的答案。当然有一些方法可以扩展 Router
模式以适应多种对象类型。第一个选项是添加更多案例以支持另一种对象类型。但是,当您收到超过 6 或 7 个案例时,这很快就会变得棘手。您的 switch 语句刚刚开始失控。因此,我不推荐这种方法。
解决该问题的另一种方法是将泛型引入 Router
。
RouterObject 协议
protocol RouterObject {
func createObjectPath() -> String
func readObjectPath(identifier: String) -> String
func updateObjectPath(identifier: String) -> String
func destroyObjectPath(identifier: String) -> String
}
模型对象
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)" }
}
路由器
let baseURLString = "http://example.com"
var OAuthToken: String?
enum Router<T where 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
}
}
}
示例用法
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)
}
}
现在您必须在这里做出一些权衡。首先,您的模型对象需要符合 RouterObject
协议。否则 Router
不知道该路径使用什么。此外,您需要确保所有路径都可以使用单个 identifier
构建。如果不能,则此设计可能行不通。最后一个问题是您不能将 baseURL
或 OAuthToken
直接存储在 Router
枚举中。不幸的是,通用枚举尚不支持静态和存储属性。
无论如何,这肯定是避免为每个模型对象创建 Router
的有效方法。
Should the
Alamofire.Manager.sharedInstance
be used as my singletonNetworkManager
instance?
当然可以这样使用。这实际上取决于您的用例以及您如何设计网络访问。它还取决于您需要多少不同类型的会话。如果您需要后台会话和默认会话,那么您可能仍然需要包含每个自定义 Manager
实例的 NetworkManager
的概念。但是,如果您只是使用默认会话访问网络,那么 sharedInstance
可能就足够了。
How could the
baseURL
of theAlamofire
singleton be used in conjunction with theRouter
pattern?
好问题...下面的代码是如何完成的一个示例。
Alamofire 管理器扩展
extension Manager {
static let baseURLString = "http://example.com"
static var OAuthToken: String?
}
路由器 URLRequestConvertible 更新
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
}
}
希望这有助于阐明一些问题。祝你好运!