swift 可以定義模板函數(shù),如:
func testFunc<T>(datas: [T]) -> T{
//處理
}
這里有個(gè)T居夹,使用指代類型的,這個(gè)方法定義出來(lái)劫扒,可以用來(lái)處理任意的數(shù)組:
let names = [String]()
testFunc(names)
let names2 = [Int]()
testFunc(names)
傳入String
的數(shù)組狸膏,T就是String;傳入Int
的數(shù)組,T就是Int.這個(gè)方法就像是一個(gè)模板贤旷,有了它砾脑,可以復(fù)刻出許多個(gè)不同的版本韧衣。
問(wèn)題1:我想要這個(gè)T是具有某個(gè)特定方法的
舉個(gè)常用的例子:
比如寫(xiě)一個(gè)用來(lái)找最小值的方法,func min<T>(datas: [T]) -> T?
氏淑,我肯定是希望它能處理數(shù)字硕噩、字符串、日期,甚至是自定義類的對(duì)象坑资,那就需要這個(gè)被排序的數(shù)組里的對(duì)象,必須得實(shí)現(xiàn)一個(gè)比較的函數(shù)袱贮, 這個(gè)我才能知道那個(gè)大那個(gè)小攒巍,才能排序。而且我只需要這個(gè)比較函數(shù)就可以對(duì)所有類通用了柒莉。
比如可以寫(xiě)成:
func min<T>(datas: [T]) -> T?{
if datas.count == 0 {
return nil
}
var min: T = datas.first!
for data in datas {
if data.compareTo(min) < 0{
min = data
}
}
return min
}
里面用了compareTo方法。我要怎么確定這個(gè)T一定是有這個(gè)方法的呢窿凤?
祭出法寶:protocol
聯(lián)想:一些人困惑協(xié)議有什么用雳殊?跟block/閉包有什么區(qū)別窗轩?這里的功能就是閉包無(wú)法替代協(xié)議的痢艺,其實(shí)協(xié)議和委托是可以不一起行動(dòng)的。
定義一個(gè)協(xié)議:
protocol Comparable : NSObjectProtocol{
/**
和其他對(duì)象比較
- parameter other: 其他對(duì)象
- returns: 0 相等 -1 小于 1 大于
*/
func compareTo(other: Self) -> Int
}
然后把方法定義修改為:
func min<T:Comparable>(datas: [T]) -> T?
T后面限定了類型衬潦,指定了這個(gè)T是遵循類Comparable這個(gè)協(xié)議的镀岛,那么也就具有了compareTo這個(gè)方法友驮。在我理解里,協(xié)議的核心就在這:表明某個(gè)類具有特定的方法/能力
問(wèn)題2:多個(gè)協(xié)議怎么辦走越?
假如我想處理的T類型是需要具有兩個(gè)不同的能力旨指,舉個(gè)現(xiàn)實(shí)的例子:一個(gè)榨汁機(jī)喳整,它接收的東西應(yīng)該同時(shí)具有可被碾碎和出水兩個(gè)特性框都,這兩個(gè)特性是分開(kāi)的,因?yàn)轱灨刹怀鏊鸵幽氩凰榘境摺?duì)應(yīng)到代碼粱哼,可悲碾碎是一個(gè)protocol里的一個(gè)方法皂吮,會(huì)出水是另一個(gè)protocol的方法。
多個(gè)協(xié)議只需要寫(xiě)成:
func min<T:protocol<testProtocol1,testProtocol2>>(datas: [T]) -> T?
把兩個(gè)協(xié)議用protocol關(guān)鍵字裝起來(lái)就好了需纳。
問(wèn)題3:如果我還想這個(gè)T是某個(gè)特定的類呢艺挪?
比如我想T是class1這個(gè)類的對(duì)象麻裳,同時(shí)遵循testProtocol1和testProtocol2,怎么寫(xiě)妙蔗?
祭出法寶:where關(guān)鍵字
方法寫(xiě)成:
func findMinTemplateFunc<T : testCalss
where T :protocol<testProtocol1,testProtocol2>>(datas: [T]) -> T?
把協(xié)議的限定方法where里面去眉反,where還有其他用法寸五,我也沒(méi)太用過(guò),就不說(shuō)了梳杏。
這個(gè)需求看起來(lái)好像很難發(fā)生十性,但只需要想一個(gè)東西就有了:抽象類劲适。swift/OC里沒(méi)強(qiáng)掉這個(gè)概念,但是這個(gè)東西是存在的拢肆,比如CoreData里面的NSManageredObject,你會(huì)直接使用這個(gè)類來(lái)構(gòu)造對(duì)象嗎减响?肯定不會(huì),肯定要建自己的數(shù)據(jù)實(shí)體郭怪,也就是NSManageredObject的子類來(lái)操作了支示。
當(dāng)有了抽象類做父類的時(shí)候,你處理的都是子類鄙才,如果你寫(xiě)一個(gè)針對(duì)子類的模板方法颂鸿,有些子類實(shí)現(xiàn)了testProtocol1,有些實(shí)現(xiàn)了testProtocol2攒庵,有些沒(méi)有嘴纺。這時(shí),就必須類浓冒、協(xié)議同時(shí)限定才能達(dá)到效果栽渴。
最后貼段例子:
加入找出數(shù)組里最小值,每個(gè)值根據(jù)value1 \ value2 和rate做一段算法后的值來(lái)比較:
protocol testProtocol1: NSObjectProtocol {
func value1() -> Int;
}
protocol testProtocol2: NSObjectProtocol {
func value2() -> Int;
}
//類似虛類的東西稳懒,比如NSManagedObject這種類闲擦,是不可能直接使用它來(lái)構(gòu)建對(duì)象的墅冷,肯定是要配合自己建的CoreData實(shí)體
class testCalss: NSObject {
var rate: Int? = 1
}
func findMinTemplateFunc<T : testCalss
where T :protocol<testProtocol1,testProtocol2>>(datas: [T]) -> T?{
if datas.count == 0 {
return nil
}
var min : T = datas.first!
var minRealValue = min.value1() * 10 + min.value2() * 100
if let rate = min.rate {
minRealValue *= minRealValue * rate
}
for data in datas {
var realValue = data.value1() * 10 + data.value2() * 100
if let rate = data.rate {
realValue *= realValue * rate
}
if realValue < minRealValue {
min = data
minRealValue = realValue
}
}
return min
}
//例子
class subClass1: testCalss, testProtocol1, testProtocol2 {
func value1() -> Int {
return Int(arc4random() % 10)
}
func value2() -> Int {
return Int(arc4random() % 20)
}
}
class subClass2: testCalss, testProtocol1, testProtocol2 {
func value1() -> Int {
return Int(arc4random() % 100)
}
func value2() -> Int {
return Int(arc4random() % 200)
}
}
func runTest(){
var array1 = [subClass1]()
for _ in 0...99 {
array1.append(subClass1())
}
findMinTemplateFunc(array1)
var array2 = [subClass2]()
for _ in 0...99 {
array2.append(subClass2())
}
findMinTemplateFunc(array1)
}
runTest()