泛型(generic)可以使我們在程序代碼中定義一些可變的部分县爬,在運(yùn)行的時候指定耳高。使用泛型可以最大限度地重用代碼陆蟆、保護(hù)類型的安全以及提高性能。
舉個栗子:
要比較兩個Int值是否相等缕题,寫了下面這個函數(shù)
func compareIntValue(_ a: Int, b: Int) -> Bool {
return a == b
}
要比較兩個Double值是否相等墅诡,修改一下上面的函數(shù)
func compareDoubleValue(_ a: Double, b: Double) -> Bool {
return a == b
}
如果再想有一個比較字符串是否相等的函數(shù)呢酵使,我們不禁要想有沒有一個函數(shù)實現(xiàn)多種比較呢悦穿?
泛型函數(shù)
指定一個或多個類型占位符栗柒,類型暫時不確定逛钻,等具體調(diào)用的時候再確定
func compareValue<T: Comparable>(_ a: T, b: T) -> Bool {
return a == b
}
現(xiàn)在我們可以用它來比較字符串了
let result = compareValue("123", b: "456")
是不是很方便,減少了重復(fù)代碼的書寫,更加靈活淋纲。
網(wǎng)絡(luò)請求
提到APP開發(fā),網(wǎng)絡(luò)請求是必不可少的一部分放祟。發(fā)起網(wǎng)絡(luò)請求鳍怨,將返回數(shù)據(jù)封裝成Model,交給Controller最終顯示在相應(yīng)的View上跪妥,MVC的開發(fā)模式基本如此鞋喇。下面是使用泛型優(yōu)化網(wǎng)絡(luò)請求的一次嘗試,先看看原來的網(wǎng)絡(luò)請求:
//原網(wǎng)絡(luò)請求
static func postNormalUrl(_ url: String, params: [String: String]?, completion: @escaping (_ data: Any?, _ error: Error?) -> ()) {
let requestUrl = BaseUrl + url
Alamofire.request(requestUrl, method: .post, parameters: params, encoding: URLEncoding.default, headers: nil).responseJSON { (response) in
if response.result.isSuccess {
completion(response.result.value, nil)
} else {
completion(nil, response.result.error)
}
}
}
//發(fā)起網(wǎng)絡(luò)請求
NetworkManager.postNormalUrl("topic/info/58f821feee07cf0007f3bafb", params: params) { (data, error) in
if let getData = data {
let json = JSON(getData)
let status = json["status"].intValue
if status == 1 {
//封裝model
} else {
print(json["msg"].stringValue)
}
} else {
print(error!)
}
}
上面的請求只是進(jìn)行了簡單的封裝眉撵,網(wǎng)絡(luò)請求成功返回數(shù)據(jù)侦香,失敗返回error,在回調(diào)中判斷并進(jìn)行處理执桌,不難看出存在以下問題:
???1鄙皇、if判斷每個請求里面都要寫,存在大量重復(fù)代碼仰挣;
???2伴逸、status和msg沒有進(jìn)行封裝,需要通過key-value進(jìn)行取值膘壶;
???3错蝴、有沒有可能直接返回封裝好的model洲愤;
了解問題之后,我們嘗試進(jìn)行改造:
首先聲明一個BaseModel顷锰,包含兩個屬性status和msg柬赐,在這里使用了SwiftyJSON和ObjectMapper分別進(jìn)行映射,選擇適合自己的就好官紫;
import UIKit
import SwiftyJSON
import ObjectMapper
class BaseModel: Mappable {
var status: Int?
var msg: String?
required init?(map: Map) {
}
func mapping(map: Map) {
status <- map["status"]
msg <- map["msg"]
}
// required init(json: JSON) {
// status = json["status"].int
// msg = json["msg"].string
// }
}
看一下修改之后的網(wǎng)絡(luò)請求肛宋,使用到了泛型,傳入BaseModel類或其子類束世,成功后就會返回對應(yīng)的model;
static func postUrl<T: BaseModel>(_ url: String, params: [String: String]?, success: @escaping (_ model: T?) -> (), failure: @escaping (_ msg: String?) -> (), error: @escaping (_ error: Error?) -> ()) {
let requestUrl = BaseUrl + url
Alamofire.request(requestUrl, method: .post, parameters: params, encoding: URLEncoding.default, headers: nil).responseJSON { (response) in
if response.result.isSuccess {
if let getData = response.result.value {
// let json = JSON(getData)
// let model = T(json: json)
let getModel = Mapper<T>().map(JSONObject: getData)
if getModel?.status == 1 {
success(getModel)
} else {
failure(getModel?.msg)
}
}
} else {
error(response.result.error)
}
}
}
NetworkManager.postUrl("topic/info/58f821feee07cf0007f3bafb", params: params, success: { (model: BaseModel?) in
print(model?.msg)
}, failure: { (msg) in
print(msg)
}) { (error) in
print(error)
}
通過改造解決了上面存在的問題:
???1酝陈、對各種狀態(tài)只會在一處進(jìn)行判斷,減少了重復(fù)代碼毁涉;
???2沉帮、將status和msg放入了BaseModel中;
???3贫堰、直接返回對應(yīng)的Model穆壕,可在回調(diào)中直接使用;
對于第三條可能上面的例子不是很明顯其屏,再創(chuàng)建一個Model繼承自BaseModel喇勋;
import UIKit
import SwiftyJSON
import ObjectMapper
//class TestModel: BaseModel {
// var contentStr: String?
// var replyArray: [ReplyModel]?
// var recommendArray: [RecommendModel]?
//
// required init(json: JSON) {
// super.init(json: json)
// if status == 1 {
// let data = json["data"].dictionaryValue
// contentStr = data["content"]?.string
// let replies = data["replies"]?.array
// let recommend = data["recommend"]?.array
// if let reply = replies {
// if reply.count > 0 {
// replyArray = [ReplyModel]()
// for data in reply {
// let replyModel = ReplyModel(json: data)
// replyArray?.append(replyModel)
// }
// }
// }
// if let recom = recommend {
// if recom.count > 0 {
//
// }
// }
// }
// }
//}
class TestModel: BaseModel {
var contentStr: String?
required init?(map: Map) {
super.init(map: map)
}
override func mapping(map: Map) {
status <- map["status"]
msg <- map["msg"]
contentStr <- map["data.content"]
}
}
NetworkManager.postUrl("topic/info/58f821feee07cf0007f3bafb", params: params, success: { (testModel: TestModel?) in
print(testModel?.contentStr)
}, failure: { (msg) in
print(msg)
}) { (error) in
print(error)
}
在上面的例子中,通過泛型傳入的實際類型是TestModel漫玄,在回調(diào)中直接獲取到了TestModel對象茄蚯,可以直接拿來用,是不是很方便睦优。
OC版本的沒有具體實現(xiàn),可以看這篇文章文章鏈接
參考鏈接
Swift泛型和泛型函數(shù)
Swift學(xué)習(xí)之泛型