单身模式和正确使用Alamofire的URLRequestConvertible

时间:2015-07-08 07:52:09

标签: swift alamofire

这是一个2部分问题,第一个问题与此问题类似:Proper usage of the 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的新人,所以请耐心等待> _<)我看到用户对象的操作;他们正在创建一个用户,更新用户等...所以,如果我的模型对象是人,公司,我的模型层中的位置,我会为每个模型对象创建一个路由器吗?

2)当与API大量交互时,我习惯于创建一个"网络管理员" singleton抽象出网络层并保存该API的标头和baseurl。 alamofire有一个"经理"这里描述:

  

Alamofire.request等顶级便捷方法使用Alamofire.Manager的共享实例,该实例配置了默认的NSURLSessionConfiguration。因此,以下两个陈述是等效的:

Alamofire.request(.GET, "http://httpbin.org/get")

let manager = Alamofire.Manager.sharedInstance
manager.request(NSURLRequest(URL: NSURL(string: "http://httpbin.org/get")))

这位经理应该使用什么作为我的单身人士?如果是这样,我如何在经理上设置baseurl?另外,如果我使用这个管理器,它/可以和上面显示的路由器结构一起工作(每个模型对象设置它的baseurl和NSURLRquest)吗?如果是这样,你能提供一个简单的例子吗?

我是Alamofire图书馆的新手并且很快。所以,我知道我的理解中有很多漏洞,但我只是想尽力了解最好的东西!任何信息都有帮助感谢。

1 个答案:

答案 0 :(得分:32)

这些是一些非常好的问题。让我试着依次回答每一个。

  

我是否为模型层中的每个模型创建了一个实现URLRequestConvertible的枚举路由器?

这是一个很好的问题,遗憾的是没有一个完美的答案。肯定有一些方法可以扩展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构建所有路径。如果他们不能,这个设计可能不起作用。最后一个问题是,您无法将baseURLOAuthToken直接存储在Router枚举中。遗憾的是,通用枚举中尚不支持静态和存储属性。

无论如何,这肯定是避免为每个模型对象创建Router的有效方法。

  

Alamofire.Manager.sharedInstance是否应该用作我的单身NetworkManager实例?

当然可以这种方式使用。这实际上取决于您的使用案例以及您如何设计网络访问权限。它还取决于您需要多少种不同类型的会话。如果您需要后台会话和默认会话,那么您可能仍需要包含每个自定义NetworkManager实例的Manager概念。但是,如果您只是使用默认会话访问网络,则sharedInstance可能就足够了。

  

baseURL单身的Alamofire如何与Router模式结合使用?

好问题......下面的代码是如何完成的一个例子。

Alamofire Manager扩展程序

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
    }
}

希望这有助于解决问题。祝你好运!