SolarNetwork-優雅的Swift網路封裝

wyhazq發表於2018-02-24

GitHub: SolarNetwork

前言

剛開始寫Swift專案時,用到網路請求時,毫無疑問,選擇了Moya。但隨著專案的增大,介面越來越多,TargetType檔案也越來越大,尋找某一個介面的引數和其他配置時,就要在各種Switch中跳來跳去,感到十分煩惱,就算分了多個TargetType,也還是存在這個問題,於是就乾脆借鑑Moya的優點,基於Alamofire重新封裝了一個簡單易用的網路庫,保留了TargetType的服務配置功能,並將介面配置分離成各個獨立的Request,形成一個新的網路庫SolarNetwork


目錄


設計

SolarNetwork包括以前幾個類:

  • SLNetwork 對應一個SessionManager,負責Request的傳送,Progress和Response的回撥。
  • SLTarget 對應一個Host或者一系列具有相同配置請求的配置。
  • SLRequest, SLDownloadRequest, SLUploadRequest 分別對應Data, Download和Upload,是這3種請求的配置。
  • SLProgress 下載和上傳進度的回撥。
  • SLResponse 是一個已處理過的Response,你可以進一步選擇轉換為JsonObject或者Model。
  • SLPlugin 提供了兩個切入點,分別用來在請求傳送前修改請求的willSend 和 接收到網路回撥後修改回撥內容的 didReceive
  • SLReflection 負責將SLRequest的子類屬性反射為Alamofire.Parameters。

所以一個網路請求的具體流程為:

SLNetwork(SLTarget).request(SLRequest).willSend(SLRequest)
                   .progressClosure(SLProgress)
                   .reponseData(OriginalResponse)
                   .didReceive(SLResponse).decodeTo(Dictionary)
                   .completionClosure(SLResponse)
                   .decodeTo(Model: Decodable).dealWithError
複製程式碼

大多數情況下,你只需要關心的是:

SLNetwork(SLTarget).request(SLRequest)
                   .progressClosure(SLProgress)
                   .completionClosure(SLResponse)
複製程式碼

特性

  • 靈活的多服務配置(baseURL, Header, ParameterEncoding, URLSessionConfiguration, TSL…...)
  • 完整的資料請求方法
  • 完整的下載和斷點下載方法(意外退出也能恢復)
  • 完整的上傳方法:File, Data, InputStream, FormData
  • 上傳和下載的進度回撥
  • 網路狀態Reachability回撥
  • 保留Alamofire的對外API
  • 修改Request和Response的Plugin
  • Swift4下利用Decodable將JSON轉為Model
  • 完整的日誌列印

更多內容請直接到GitHub檢視。


要求

  • iOS 8.0+
  • Xcode 9+
  • Swift 4+

使用

配置服務

import SolarNetwork

struct HTTPBinTarget: SLTarget {
    var baseURLString: String { return "https://httpbin.org" }
}

let HTTPBinNetwork = SLNetwork(HTTPBinTarget())
複製程式碼

傳送一個請求

import SolarNetwork

//Mark: - GET
class HTTPBinGETRequest: SLRequest {
    
    override func loadRequest() {
        super.loadRequest()
        
        self.path = "/get"
    }
    
}

HTTPBinNetwork.request(HTTPBinGETRequest()) { (response) in
    if let dictionary = response.dataDictionary {
                        
    }
    else if let error = response.error {
        //show error
    }
}

//Mark: - POST
class HTTPBinPOSTRequest: SLRequest {
    
    override func loadRequest() {
        super.loadRequest()
        
        self.method = .post
        self.path = "/post"
    }
    
    /**
     利用反射,將屬性自動轉換為Parameters,不需要自己組裝了
     ["userName": "myUserName",
      "password": "myPassword"]
     */
    let userName = "myUserName"
    let password = "myPassword"

}

HTTPBinNetwork.request(HTTPBinPOSTRequest()) { (response) in
    if let dictionary = response.dataDictionary {
                        
    }
    else if let error = response.error {
        //show error
    }
}
複製程式碼

下載和斷點續傳

import SolarNetwork

class GitHubDownloadRequest: SLDownloadRequest {
    
    override func loadRequest() {
        super.loadRequest()
		
        self.URLString = "http://cdnvue.com/video/rzGHzRA19L/64tBZo"
    }
}

let downloadRequest = GitHubDownloadRequest()
GitHubNetwork.download(downloadRequest, progressClosure: { (progress) in
                    
}) { (response) in
                    
}

//如果需要斷點下載此檔案,請設定該屬性為true
downloadRequest.isResume = true

//自定義檔案下載完成後的存放路徑,預設為"/Library/Caches/SLNetwork/Destination/(requestID)"
downloadRequest.destinationURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
複製程式碼

上傳

import SolarNetwork

class HTTPBinUploadRequest: SLUploadRequest {
    
    override func loadRequest() {
        super.loadRequest()
        
        self.path = "/post"
    }
    
}

let uploadRequest = HTTPBinUploadRequest()
uploadRequest.data = data //data to upload
HTTPBinNetwork.upload(uploadRequest, progressClosure: { (progress) in
                            
}) { (response) in
                            
}
複製程式碼

Decode

Swift 4下,利用Decodable將Json轉為Model

import SolarNetwork

struct User: Decodable { //Swift 4 Codable
    var id: Int
    var name: String
    var token: String
}

HTTPBinNetwork.request(UserRequest()) { (response) in
    if let user = response.decode(to: User.self) {
                        
    }
    else if let error = response.error {
        //show error
    }
}
複製程式碼
更多內容,Demo和交流請到GitHub

相關文章