【问题标题】:Singleton pattern and proper use of Alamofire's URLRequestConvertible单例模式和正确使用 Alamofire 的 URLRequestConvertible
【发布时间】:2015-09-26 00:10:31
【问题描述】:

这是一个由两部分组成的问题,第一部分与此处的问题类似: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 进行大量交互时,我习惯于创建一个“网络管理器”单例来抽象网络层并保存该 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 库的新手,而且速度很快。所以,我知道我的理解有很多漏洞,但我只是想尽我所能去理解!任何信息都有帮助。谢谢。

【问题讨论】:

    标签: swift alamofire


    【解决方案1】:

    这些都是一些非常好的问题。让我试着逐一回答。

    我是否创建一个枚举路由器来为我的模型层中的每个模型实现 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 实例吗?

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

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

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

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

    希望这有助于阐明一些问题。祝你好运!

    【讨论】:

    • 嘿@cnoon!这很有帮助,谢谢!但是,这种设置方式是否可以执行func readObjectPath(identifier: String) -&gt; String { return "\(rootPath)/\(identifier)/?randomParameter=true" } 之类的操作。我尝试了这个,但是当将 URL 转换为 mutableURLRequest 时,它会将问号格式化为:%3F
    • 没关系,我通过更改它来修复它,以便将路径附加到URL内的baseURLString,而不是mutableURLRequest
    猜你喜欢
    • 2015-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    相关资源
    最近更新 更多