正确使用Alamofire的URLRequestConvertable [英] Proper usage of the Alamofire's URLRequestConvertible
问题描述
我已经从@Mattt阅读了几个教程和自述文件,但弄不懂几个东西。
URLRequestConvertible
在现实API中的正确用法是什么?看起来如果我要通过为所有API实现URLRequestConvertible
协议来创建一台路由器-它将几乎不可读。我应该为每个终结点创建一台路由器吗?第二个问题很可能是由于缺乏使用SWIFT语言的经验引起的。我搞不懂为什么要用
enum
来构建路由器?为什么我们不将类与静电方法一起使用呢? 以下是一个示例(摘自AlamoFire的自述文件)enum Router: URLRequestConvertible { static let baseURLString = "http://example.com" static let perPage = 50 case Search(query: String, page: Int) // MARK: URLRequestConvertible var URLRequest: NSURLRequest { let (path: String, parameters: [String: AnyObject]?) = { switch self { case .Search(let query, let page) where page > 1: return ("/search", ["q": query, "offset": Router.perPage * page]) case .Search(let query, _): return ("/search", ["q": query]) } }() let URL = NSURL(string: Router.baseURLString)! let URLRequest = NSURLRequest(URL: URL.URLByAppendingPathComponent(path)) let encoding = Alamofire.ParameterEncoding.URL return encoding.encode(URLRequest, parameters: parameters).0 } }
传递参数有两种方式:
case CreateUser([String: AnyObject]) case ReadUser(String) case UpdateUser(String, [String: AnyObject]) case DestroyUser(String)
AND(假设用户有4个参数)
case CreateUser(String, String, String, String) case ReadUser(String) case UpdateUser(String, String, String, String, String) case DestroyUser(String)
@Mattt在示例中使用第一个。但这将导致在路由器外部对参数名称进行"硬编码"(例如,在UIViewController中)。 参数名称中的拼写错误可能会导致错误。
其他人正在使用第二个选项,但在这种情况下,每个参数表示的含义一点也不明显。
做这件事的正确方法是什么?
推荐答案
好问题。让我们逐一分析一下。
在真实API中URLRequestConverable的正确用法是什么?
URLRequestConvertible
协议是一种轻量级方法,可确保给定对象可以创建有效的NSURLRequest
。实际上并没有一套严格的规则或指导方针强迫您以任何特定方式使用此协议。它只是一个方便的协议,允许其他对象存储正确创建NSURLRequest
所需的状态。有关AlamoFire的更多信息,请参阅here。
是否应该为每个终结点创建一台路由器?
绝对不是。这将违背使用Enum
的全部目的。SWIFT枚举对象的功能非常强大,允许您共享大量常见状态,并打开实际不同的部分。能够用下面这样简单的东西创建一个NSURLRequest
,真是太强大了!
let URLRequest: NSURLRequest = Router.ReadUser("cnoon")
使用枚举是因为它是在公共接口下表示多个相关对象的更简明的方式。所有的方法都是在所有案例之间共享的。如果您使用静电方法,则必须为每个方法的每个案例使用一个静电方法。否则,您必须在对象内使用Obj-C样式的枚举。这里有一个简单的例子来说明我的意思。我搞不懂为什么要使用枚举来构建路由器?为什么我们不将类与静电方法一起使用?
enum Router: URLRequestConvertible {
static let baseURLString = "http://example.com"
case CreateUser([String: AnyObject])
case ReadUser(String)
case UpdateUser(String, [String: AnyObject])
case DestroyUser(String)
var method: Alamofire.HTTPMethod {
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)"
}
}
}
若要获取任何不同终结点的方法,您可以调用相同的方法,而无需传入任何参数来定义您要查找的终结点类型,它已由您选择的案例处理。
let createUserMethod = Router.CreateUser.method
let updateUserMethod = Router.UpdateUser.method
或者,如果您要获取路径,请使用相同类型的调用。
let updateUserPath = Router.UpdateUser.path
let destroyUserPath = Router.DestroyUser.path
现在让我们使用静电方法尝试相同的方法。
struct Router: URLRequestConvertible {
static let baseURLString = "http://example.com"
static var method: Method {
// how do I pick which endpoint?
}
static func methodForEndpoint(endpoint: String) -> Method {
// but then I have to pass in the endpoint each time
// what if I use the wrong key?
// possible solution...use an Obj-C style enum without functions?
// best solution, merge both concepts and bingo, Swift enums emerge
}
static var path: String {
// bummer...I have the same problem in this method too.
}
static func pathForEndpoint(endpoint: String) -> String {
// I guess I could pass the endpoint key again?
}
static var pathForCreateUser: String {
// I've got it, let's just create individual properties for each type
return "/create/user/path"
}
static var pathForUpdateUser: String {
// this is going to get really repetitive for each case for each method
return "/update/user/path"
}
// This approach gets sloppy pretty quickly
}
注意:如果您没有很多属性或函数来打开大小写,那么枚举与结构相比不会有太多优势。这只是一种不同句法糖的替代方法。枚举可以最大化状态和代码重用。关联的值还允许您执行一些非常强大的操作,如对相似但要求截然不同的对象进行分组.例如
NSURLRequest
创建。
为枚举案例构造参数以提高可读性的正确方法是什么?(必须将这一块捣碎)
这是一个很棒的问题。您已经列出了两种可能的选择。让我添加第三个可能更适合您的需求。
case CreateUser(username: String, firstName: String, lastName: String, email: String)
case ReadUser(username: String)
case UpdateUser(username: String, firstName: String, lastName: String, email: String)
case DestroyUser(username: String)
在有关联值的情况下,我认为为元组中的所有值添加显式名称会很有帮助。这确实有助于构建上下文。缺点是您必须在Switch语句中重新声明这些值,如下所示。
static var method: String {
switch self {
case let CreateUser(username: username, firstName: firstName, lastName: lastName, email: email):
return "POST"
default:
return "GET"
}
}
虽然这为您提供了一个良好的、一致的上下文,但它变得相当冗长。这是您目前在SWIFT中的三个选项,哪一个是正确的取决于您的使用案例。
更新
随着🔥🔥Alamofire 4.0🔥🔥的发布,URLRequestConvertible
现在可以更智能,也可以抛出。我们在Alamofire中添加了对处理无效请求和通过响应处理程序生成明显错误的完全支持。此新系统详细记录在我们的README中。
这篇关于正确使用Alamofire的URLRequestConvertable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!