Swift:NetworkController

本篇主要介绍如何建一个networkController进行API Call。首先是APIRequestConfigure

protocol APIRequestConfigure {
    var url: String { get }
    var cachePolicy: URLRequest.CachePolicy? { get }
    var timeoutInterval: TimeInterval? { get }
    var header: [String:String]? { get }
    var httpBody: Data? { get }
    var httpMethod: String? { get }
}

extension APIRequestConfigure {
    func makeRequest() throws -> URLRequest {
        guard let url = URL(string: url) else { throw NetworkError.invalidURL }
        var request = URLRequest(url: url, cachePolicy: cachePolicy ?? URLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval: timeoutInterval ?? 10)
        request.allHTTPHeaderFields = header
        request.httpBody = httpBody
        request.httpMethod = httpMethod
        return request
    }
}

这个APIRequestConfigure主要是对API Request进行一个封装。这里除了URL,其他的parameter都是optional。
接下来是APIRequestLoader

class APIRequestLoader {
    let apiRequest: APIRequestConfigure
    let urlSession: Session
    
    init(apiRequest: APIRequestConfigure, urlSession: Session = URLSession.shared) {
        self.apiRequest = apiRequest
        self.urlSession = urlSession
    }
    
    func loadRequest<T: Codable>(completionHandler: @escaping ((T?, Error?) -> Void)) {
        guard let request = try? apiRequest.makeRequest() else {
            completionHandler(nil, NetworkError.invalidRequest)
            return
        }
        urlSession.getData(with: request) { (data, error) in
            guard error == nil else {
                completionHandler(nil, error)
                return
            }
            guard let data = data else {
                completionHandler(nil, NetworkError.noData)
                return
            }
            do {
                let decodedData = try JSONDecoder().decode(T.self, from: data)
                completionHandler(decodedData, nil)
            } catch {
                completionHandler(nil, NetworkError.invalidJSONData)
            }
        }
    }
}

这个就是比较常规的用URLSession进行APICal了。在初始化中我把default的session设置为URLSession.share,方便如果需要用其他的framework的话,可以在这里进行插入。接下来是Session。

protocol Session {
    func getData(with url: URL, completionHandler: @escaping (Data?, Error?) -> Void)
    func getData(with request: URLRequest, completionHandler: @escaping(Data?, Error?) -> Void)
}

extension URLSession: Session {
    func getData(with request: URLRequest, completionHandler: @escaping (Data?, Error?) -> Void) {
        self.dataTask(with: request) { (data, _, error) in
            completionHandler(data, error)
        }.resume()
    }
    
    func getData(with url: URL, completionHandler: @escaping (Data?, Error?) -> Void) {
        self.dataTask(with: url) { (data, _, error) in
            completionHandler(data, error)
        }.resume()
    }
}

这里用Protocol作为一个abstract方便之后的使用,并把它作为subclass添加到了URLSession里,这样在使用URLSession的时候,也可以getData进行APICall。最后是NetworkRequestConfigure。

struct NetworkRequestConfigure: APIRequestConfigure {
    var url: String
    
    var cachePolicy: URLRequest.CachePolicy?
    
    var timeoutInterval: TimeInterval?
    
    var header: [String : String]?
    
    var httpBody: Data?
    
    var httpMethod: String?
}

用之前的APIRequestConfigure作为subclass,代入后就可以用这个NetworkRequestConfigure作为一个abstract方便之后的使用。
最后来看我是如何使用它的

   private var apiRequestLoader: APIRequestLoader
    
    init(apiRequestLoader: APIRequestLoader? = nil) {
        if let apiRequestLoader = apiRequestLoader {
            self.apiRequestLoader = apiRequestLoader
        } else {
            let ituneRssRequestConfig: APIRequestConfigure = ItunesRssRequestConfig()
            let apiRequestLoader = APIRequestLoader(apiRequest: ituneRssRequestConfig)
            self.apiRequestLoader = apiRequestLoader
        }
    }

在ViewModel里创建一个apiRequestLoader,然后在初始化里把它设置成optional。再用if let进行optional binding。如果在初始化里有apiRequestLoader,就等于它。如果没有,就等于我设置的这个viewModel该需要的ituneRssRequestConfig(这个ituneRss有APIRequestConfigure里多加了一个需要使用的URL)。下面是github

https://github.com/grm121616/NetworkController/tree/master/NetworkController

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
接着分析 (result (type_ident (component id='Bool' bind=Swift.(file).Bool))) (brace_stmt range=[re.swift:1:59 - line:14:1] (pattern_binding_decl range=[re.swift:2:5 - line:2:33] (pattern_named type='[UInt8]' 'b') Original init: (call_expr type='[UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:33] nothrow (constructor_ref_call_expr type='(String.UTF8View) -> [UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:19] nothrow (declref_expr implicit type='(Array<UInt8>.Type) -> (String.UTF8View) -> Array<UInt8>' location=re.swift:2:19 range=[re.swift:2:19 - line:2:19] decl=Swift.(file).Array extension.init(_:) [with (substitution_map generic_signature=<Element, S where Element == S.Element, S : Sequence> (substitution Element -> UInt8) (substitution S -> String.UTF8View))] function_ref=single) (argument_list implicit (argument (type_expr type='[UInt8].Type' location=re.swift:2:13 range=[re.swift:2:13 - line:2:19] typerepr='[UInt8]')) )) (argument_list (argument (member_ref_expr type='String.UTF8View' location=re.swift:2:29 range=[re.swift:2:21 - line:2:29] decl=Swift.(file).String extension.utf8 (declref_expr type='String' location=re.swift:2:21 range=[re.swift:2:21 - line:2:21] decl=re.(file).check(_:_:).encoded@re.swift:1:14 function_ref=unapplied))) )) Processed init: (call_expr type='[UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:33] nothrow (constructor_ref_call_expr type='(String.UTF8View) -> [UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:19] nothrow (declref_expr implicit type='(Array<UInt8>.Type) -> (String.UTF8View) -> Array<UInt8>' location=re.swift:2:19 range=[re.swift:2:19 - line:2:19] decl=Swift.(file).Array extension.init(_:) [with (substitution_map generic_signature=<Element, S where Element == S.Element, S : Sequence> (substitution Element -> UInt8) (substitution S -> String.UTF8View))] function_ref=single) (argument_list implicit (argument (type_expr type='[UInt8].Type' location=re.swift:2:13 range=[re.swift:2:13 - line:2:19] typerepr='[UInt8]')) )) (argument_list (argument (member_ref_expr type='String.UTF8View' location=re.swift:2:29 range=[re.swift:2:21 - line:2:29] decl=Swift.(file).String extension.utf8 (declref_expr type='String' location=re.swift:2:21 range=[re.swift:2:21 - line:2:21] decl=re.(file).check(_:_:).encoded@re.swift:1:14 function_ref=unapplied))) ))) (var_decl range=[re.swift:2:9 - line:2:9] "b" type='[UInt8]' interface type='[UInt8]' access=private readImpl=stored writeImpl=stored readWriteImpl=stored)
最新发布
06-10

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值