OC與swift
1.協(xié)議
OC:主要用來(lái)傳值
swift:不僅可以用來(lái)傳值,swift中的協(xié)議可以定義屬性方法,并且其協(xié)議可以進(jìn)行擴(kuò)展,在擴(kuò)展中還可以有自己的默認(rèn)實(shí)現(xiàn),這個(gè)特性使其可以面向協(xié)議的時(shí)候非常強(qiáng)大。
例:
//如果遵守了swift中的協(xié)議,那么里邊的非擴(kuò)展方法必須實(shí)現(xiàn)
protocol AnimationProtocol {
//最大年齡(屬性方法)
var maxAge: Int {get}
//動(dòng)物都有自己的名字
func name()
}
//swift中的協(xié)議支持?jǐn)U展,并且可以再擴(kuò)展中直接實(shí)現(xiàn)具體內(nèi)容(擴(kuò)展中不可以定義屬性方法),似乎跟OC中的繼承一樣
extension AnimationProtocol {
func eat() {
print("eat");
}
}
class Dog: AnimationProtocol {
//maxAge必須實(shí)現(xiàn)
var maxAge: Int {
get {
return 20
}
}
//name必須實(shí)現(xiàn)
func name() {
print("name: dog")
}
//可以實(shí)現(xiàn)也可以省略(類似繼承中的復(fù)寫(xiě))
func eat() {
print("eat shit")
}
}
class Cat: AnimationProtocol {
var maxAge: Int {
get {
return 10
}
}
func name() {
print("name: cat")
}
}
使用繼承很容易出現(xiàn)父類越來(lái)越臃腫特別是多重繼承時(shí),最終變成方法垃圾場(chǎng)的情況;
但是利用swift的協(xié)議,可以實(shí)現(xiàn)類似于繼承的功能,但是比繼承更加靈活;當(dāng)某幾個(gè)類有共同特性的時(shí)候可以抽出一個(gè)協(xié)議,使用的時(shí)候遵守此協(xié)議即可,可以解放父類。
2.泛型
泛型在很多功能上看似可以用多態(tài)實(shí)現(xiàn),但還是有很多區(qū)別的。
自己目前為止的看法,如下是使用泛型的例子:
static func set<T>(_ key: String, value: T) {
let stdDefaults = UserDefaults.standard
stdDefaults.set(_T<Any>.cast(value), forKey: key)
stdDefaults.synchronize()
}
static func get<T>(_ key: String) -> T? {
let stdDefaults = UserDefaults.standard
let value: Any? = stdDefaults.value(forKey: key)
return _T<T>.cast(value)
}
那么如果將泛型改為多態(tài),如下:
static func set(_ key: String, value: Any) {
let stdDefaults = UserDefaults.standard
stdDefaults.set(value, forKey: key)
stdDefaults.synchronize()
}
static func get(_ key: String) -> Any? {
let stdDefaults = UserDefaults.standard
let value: Any? = stdDefaults.value(forKey: key)
return value
}
會(huì)有什么問(wèn)題呢?
一個(gè)簡(jiǎn)單的例子,如果我獲取的是一個(gè)model,那么如果是多態(tài),使用應(yīng)該是這樣的:
let model = Model()
SDB.set("model", value: model)
let md = SDB.get("model") as? Model //使用了as?說(shuō)明這是類型轉(zhuǎn)換
如果是泛型,使用應(yīng)該是這樣的:
SDB_T.set("model", value: model)
let md_t: Model? = SDB_T.get("model") //前邊添加類型,屬于泛型的特征類型推斷
//static func get<T>(_ key: String) -> T?
類型推斷是swift特有的,比如說(shuō)let str = "",swift可以推斷出str為String類型
下邊是一個(gè)項(xiàng)目中很有用的自定義去重算法:
//去重算法 Equatable 判等協(xié)議
func removalAlgorithm<T: Equatable>(a: [T], b:T) -> [T] {
var items = a
for i in 0..<a.count {
let item = a[i]
if item == b {
items.remove(at: i)
}
}
return items
}
而mode中所要實(shí)現(xiàn)的協(xié)議如下:
class Model: Equatable {
var mId: Int?
var a: String?
static func == (lhs: Model, rhs: Model) -> Bool {
if lhs.mId == rhs.mId {
return true
}
return false
}
}
上邊的方法,如果不用泛型,想使用可能就比較麻煩了,需要各種類型轉(zhuǎn)換。
3.結(jié)構(gòu)體和類
oc和swift中結(jié)構(gòu)體何磊的類型是相同的,即結(jié)構(gòu)體是值類型,class是指針類型。
但是swift中結(jié)構(gòu)體更強(qiáng)大,可以實(shí)現(xiàn)很多類似于類的功能,目前swift中的Array,Dictory,String均為結(jié)構(gòu)體,因此這些常用的數(shù)據(jù)類型用法有比較大的差異。
String為例:
OC中兩個(gè)字符串對(duì)象是不可以直接用==進(jìn)行比較的,但是swift就可以(數(shù)組,字典同理)。
既然是值類型,那么有些運(yùn)算符就可以直接使用,如+:
func test() {
var arr1 = [1]
let arr2 = [2]
arr1 = arr1 + arr2
print(arr1 == arr2)
}
4.?&!
swift是類型確定型語(yǔ)言,對(duì)類型是否有值有嚴(yán)格要求,因此引入了?和!來(lái)對(duì)值進(jìn)行明確。
oc中如下:
- (NSString *)test {
return nil;
}
這樣寫(xiě)在oc中是完全沒(méi)有問(wèn)題的,但是使用者可能就比較麻煩了,因?yàn)橥獠渴褂谜卟⒉荒艽_定這個(gè)有沒(méi)有值,因此每個(gè)使用此方法的人都需要去判斷返回值是否符合自己預(yù)期;
swift中如下:
func test() ->String {
//錯(cuò)誤的寫(xiě)法,編譯器會(huì)報(bào)錯(cuò)
return nil
}
這樣寫(xiě)在swift中是會(huì)報(bào)錯(cuò)的,因?yàn)槟愕姆祷刂礢tring沒(méi)有帶?因此默認(rèn)是一個(gè)非空的,所以此函數(shù)的作者就需要去考慮如果這兒是空或者這兒的類型不是我想要的,我要做哪些補(bǔ)救措施,其實(shí)就是從源頭上對(duì)一些錯(cuò)誤特別是野指針問(wèn)題做了預(yù)防。
那么在swift中怎么正確使用這一特性呢?
1.在某些場(chǎng)景下,你確定此函數(shù)會(huì)返回一個(gè)有效值,那么你就可以在返回值后邊加!或者默認(rèn)不加;
func test() ->String {
return ""
}
2.有時(shí)候我們就是要告訴外邊,這個(gè)不一定是有效的,需要外部使用者自己處理,那就在返回值后便加?;
func test() ->String? {
return nil
}
5.??
swift中多了一種??判斷符,它的作用類似三元運(yùn)算符,但是使用場(chǎng)景比較多的地方是對(duì)一個(gè)為空的值做詢問(wèn),如果為空怎么怎么樣,如下:
func test(_ a :String?) ->String? {
//如果a為空,則返回空字符串(其實(shí)這樣寫(xiě),返回值已經(jīng)不可能為空了)
return a ?? ""
}