我读过几本教程,也读过@mattt的自述,但我还是搞不懂几件事。
>
第二个问题很可能是由于缺乏使用Swift语言的经验引起的。我不明白为什么要用
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)
和(假设用户有4个参数)
case CreateUser(String, String, String, String)
case ReadUser(String)
case UpdateUser(String, String, String, String, String)
case DestroyUser(String)
@mattt在示例中使用的是第一个。但这将导致在路由器外部(例如在UIViewControllers中)“硬编码”参数名称。参数名称中的错误可能会导致错误。br>其他人使用的是第二个选项,但在这种情况下,每个参数表示什么根本就不明显。br>正确的方法是什么?
你为什么不试着用SweetRouter。它将帮助您删除所有的样板,当您声明一个路由器,它还支持像多个环境这样的东西,您的代码将是真正可读的。
null
struct Api: EndpointType {
enum Environment: EnvironmentType {
case localhost
case test
case production
var value: URL.Environment {
switch self {
case .localhost: return .localhost(8080)
case .test: return .init(IP(126, 251, 20, 32))
case .production: return .init(.https, "myproductionserver.com", 3000)
}
}
}
enum Route: RouteType {
case auth, me
case posts(for: Date)
var route: URL.Route {
switch self {
case .me: return .init(at: "me")
case .auth: return .init(at: "auth")
case let .posts(for: date):
return URL.Route(at: "posts").query(("date", date), ("userId", "someId"))
}
}
}
static let current: Environment = .localhost
}
下面是你如何使用它:
Alamofire.request(Router<Api>(at: .me))
Alamofire.request(Router<Api>(.test, at: .auth))
Alamofire.request(Router<Api>(.production, at: .posts(for: Date())))
下面是Swift3中最新的
import Alamofire
enum Router: URLRequestConvertible
{
case createUser(parameters: Parameters)
case readUser(username: String)
case updateUser(username: String, parameters: Parameters)
case destroyUser(username: String)
static let baseURLString = "https://example.com"
var method: 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)"
}
}
// MARK: URLRequestConvertible
func asURLRequest() throws -> URLRequest
{
let url = try Router.baseURLString.asURL()
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
urlRequest.httpMethod = method.rawValue
switch self {
case .createUser(let parameters):
urlRequest = try URLEncoding.default.encode(urlRequest, with: parameters)
case .updateUser(_, let parameters):
urlRequest = try URLEncoding.default.encode(urlRequest, with: parameters)
default:
break
}
return urlRequest
}
}
null
在真实世界的API中,URLRequestConvertible的正确用法是什么?
是否应该为每个端点创建一个路由器?
绝对不能。这将破坏使用
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
}
注意:如果没有很多属性或函数可以打开事例,那么枚举并不比结构具有太多优势。这只是一种具有不同句法糖的替代方法。
枚举可以最大化状态和代码重用。相关联的值还允许您做一些非常强大的事情,比如对有些相似,但有着难以置信的不同需求的对象进行分组。。。。例如
为枚举事例构造参数以提高可读性的正确方法是什么?(不得不把这个捣碎)
这是个很棒的问题。你已经提出了两个可能的选择。让我补充第三条,也许更适合你的需要。
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的发布,
问题内容: 我试图了解Java 8中API 的方法。 我有简单的逻辑: 但这会导致编译错误: 我当然可以做这样的事情: 但这就像混乱的支票一样。 如果我将代码更改为此: 代码变得越来越脏,这让我想到了回到旧支票。 有任何想法吗? 问题答案: 需要作为参数。您正在向其传递类型为void的表达式。因此,它不会编译。 使用者应被实现为lambda表达式: 甚至更简单,使用方法参考: 这基本上与 想法是仅
问题内容: 我正在尝试了解的语义,以及实体管理器对未保存的瞬态实例的确切含义。我要实现的只是向会话添加一个新的临时实例,并在刷新会话时让Hibernate执行一个。 我发现如果持久保存一个新实例,然后在同一会话中对其进行修改,则实体管理器将同时生成和语句,这可能会导致约束冲突。 例如,假设我有一个带有列 栏 和以下服务方法的实体关系 Foo 。 __ 尽管我们为提供了一个值,但是执行此代码将违反数
问题内容: 什么时候应该从而不是从中导出例外? 不必在方法的子句中声明A ,因为它不一定要专门列出,否则可能是 好 方法,也可能是 不好的, 因为显式声明方法的异常是一种好习惯。 有什么想法吗? 问题答案: 来自未经检查的异常- 争议 : 如果可以合理预期客户端会从异常中恢复,请将其设置为已检查的异常。如果客户端无法采取任何措施来从异常中恢复,请将其设置为未经检查的异常。 请注意,未检查的异常是从
问题内容: 我现在正在开发应用程序,并进行全局切换。我想包装起来以方便使用。 然后,我在Firefox控制台中得到此结果。 如果我想使用被呼叫的行号登录该怎么办? 问题答案: 这是一个古老的问题,提供的所有答案都太过分了,存在跨浏览器的重大问题,并且没有提供任何超级有用的东西。该解决方案可在每种浏览器中使用,并完全按需报告所有控制台数据。无需黑客,只需一行代码即可签出codepen。 像这样创建开
问题内容: 这个想法是使用更少的连接和更好的性能。连接是否随时终止? 对于另一个问题,是否打开新连接? 问题答案: 不,多路复用器不会过期。没有GetDatabase不会打开新连接。basics.md涵盖了所有内容 -特别是: 从GetDatabase返回的对象是便宜的直通对象,不需要存储。
我有一个使用jquery mobile的应用程序,它由几个html页面组成,每个页面中都有几个jquery页面元素。在桌面浏览器上,一切正常,但当我把它加载到我的android设备(运行2.3)上时,第一个页面看起来很好,但只要你点击一个链接(比如从index.html)- 那么,是否有正确的方法在不同的html页面之间移动呢?我没有得到任何浏览器错误,所以一切似乎都工作正常,但没有jqm的样式或