iOS開發(fā) - Swift中的Codable, Hashable, CaseIterable, Identifiable.....

去gayhub上瀏覽大佬的代碼

struct Landmark: Hashable, Codable, Identifiable {
  ...
}

此時萌新的表情是這樣的


0.jpeg

奧不對夕凝,是這樣的

1.jpeg

今天我們就仔細分析下這幾個秕硝。。往扔。是干啥用的

首先 - Hashable

You can use any type that conforms to the Hashable protocol in a set or as a dictionary key.
只有遵循了Hashable 協(xié)議 才能被添加到 Set 中 或者用作 Dictionary 的 key 值

舉個例子

// 假如我們有一個Person類
struct Person {
    var name: String
    var age: Int
}

// 假如我們有兩位同學 小明 和 小紅
let ming = Person(name: "ming", age: 10)
let hong = Person(name: "hong", age: 11)

// 現(xiàn)在我們有一個需求 1.把他加入到一個Set中  2. 用作Dictionary的key

// 我們這樣寫
var set: Set<Person> = []      //報錯 Type 'Person' does not conform to protocol 'Hashable' 
set.insert(ming)
set.insert(hong)
print(set)

var dic: [Person: String] = [:]      //報錯 Type 'Person' does not conform to protocol 'Hashable'
dic[ming] = ming.name              //報錯 Referencing subscript 'subscript(_:)' on 'Dictionary' requires that 'Person' conform to 'Hashable'
dic[hong] = hong.name             //報錯 Referencing subscript 'subscript(_:)' on 'Dictionary' requires that 'Person' conform to 'Hashable'
print(dic)

// 由于我們的Person并沒有遵循Hashable協(xié)議旋膳,所以以上代碼會報錯
// 接下來 我們修改Person 
struct Person: Hashable {
    var name: String
    var age: Int
}

// 修改之后 澎语,以上報錯會消失
// 打印結(jié)果為 set ---- [Test0.Person(name: "hong", age: 11), Test0.Person(name: "ming", age: 10)]
// dic --- [Test0.Person(name: "ming", age: 10): "ming", Test0.Person(name: "hong", age: 11): "hong"]
  • 拓展
// 假如我們的Person是一個Class而不是Struct,就必須要實現(xiàn)Hashable的協(xié)議方法
class Person: Hashable {
    // Hashable 繼承自 Equatable,  此方法為Equatable的協(xié)議方法验懊, 用來比較兩個對象是否協(xié)議相等擅羞, 返回true的話 在Set或者Dictionary中都會被認為是同一個對象(在Set中會被去重, 在Dictionary中覆蓋之前的值)
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name && lhs.age == rhs.age
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(age)
    }
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    var name: String
    var age: Int
}

舉個栗子

// 還是之前的小明和小紅
let ming = Person(name: "ming", age: 10)
let hong = Person(name: "hong", age: 11)

var set: Set<Person> = []
set.insert(ming)
set.insert(hong)
print(set)              // [Test0.Person, Test0.Person]

var dic: [Person: String] = [:]
dic[ming] = ming.name
dic[hong] = hong.name
print(dic)              // [Test0.Person: "hong", Test0.Person: "ming"]

// 因為ming1.name == ming.name && ming1.age == ming.age Person 的 static func == (lhs: Person, rhs: Person) -> Bool 方法成立 ming1 會覆蓋之前的 ming
let ming1 = Person(name: "ming", age: 10)
set.insert(ming1)
dic[ming1] = ming1.name
print(set)              // [Test0.Person, Test0.Person]
print(dic)              // [Test0.Person: "hong", Test0.Person: "ming"]

// // 因為ming2.name == ming1.name && ming2.age == ming1.age Person 的 static func == (lhs: Person, rhs: Person) -> Bool 方法不成立 ming2 不會會覆蓋之前的 1ming
let ming2 = Person(name: "ming", age: 20)
set.insert(ming2)
dic[ming2] = ming2.name
print(set)              // [Test0.Person, Test0.Person, Test0.Person]
print(dic)              // [Test0.Person: "hong", Test0.Person: "ming", Test0.Person: "ming"]

假如我們對Person進行修改 , 年齡相同就當做同一個人

class Person: Hashable {
    static func == (lhs: Person, rhs: Person) -> Bool {
//        return lhs.name == rhs.name && lhs.age == rhs.age
        return lhs.age == rhs.age
    }
    
    func hash(into hasher: inout Hasher) {
//        hasher.combine(name)
        hasher.combine(age)
    }
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    var name: String
    var age: Int
}

// 還是之前的小明和小紅
let ming = Person(name: "ming", age: 10)
let hong = Person(name: "hong", age: 11)

var set: Set<Person> = []
set.insert(ming)
set.insert(hong)
print(set)              // [Test0.Person, Test0.Person]

var dic: [Person: String] = [:]
dic[ming] = ming.name
dic[hong] = hong.name
print(dic)              // [Test0.Person: "hong", Test0.Person: "ming"]

// 因為ming1.age == ming.age Person 的 static func == (lhs: Person, rhs: Person) -> Bool 方法成立 ming1 會覆蓋之前的 ming
let ming1 = Person(name: "ming", age: 10)
set.insert(ming1)
dic[ming1] = ming1.name
print(set)              // [Test0.Person, Test0.Person]
print(dic)              // [Test0.Person: "hong", Test0.Person: "ming"]

// // 因為 ming2.age == ming1.age Person 的 static func == (lhs: Person, rhs: Person) -> Bool 方法成立 ming2 會覆蓋之前的 1ming
let ming2 = Person(name: "aming", age: 10)
set.insert(ming2)
dic[ming2] = ming2.name
print(set)              // [Test0.Person, Test0.Person, Test0.Person]
print(dic)              // [Test0.Person: "hong", Test0.Person: "aming"]

其次 - Codable

在swift4之前义图,swift中數(shù)據(jù)解析的方式大都采用OC的KVC機制减俏,swift4后可以采用Codable直接將json轉(zhuǎn)成對象
先看定義

public typealias Codable = Decodable & Encodable

json轉(zhuǎn)對象

struct Person: Codable {
    var name: String
    var age: Int
}

let jsonStr = "{\"name\" : \"ming\", \"age\" : 10}"
guard let jsonData = jsonStr.data(using: .utf8) else {
    exit(0)
}

let decoder = JSONDecoder()
guard let obj = try? decoder.decode(Person.self, from: jsonData) else {
    exit(0)
}

print(obj.name)    // ming
print(obj.age)     // 10

當json中的key值與我們定義的屬性名對應(yīng)時可以采用上述簡單的方法, 如果不對應(yīng)的話就需要借助CodingKeys來實現(xiàn)

// 修改Person
struct Person: Codable {
    var name: String
    var age: Int
    
    enum CodingKeys: String, CodingKey {
        case name = "a_name"
        case age = "age" //如果前后一致的話 可以省略=以及后邊的部分 如 case age, 如果有需要忽略的key, 則不寫到此處便可
    }
}

let decoder = JSONDecoder()
let jsonStr1 = "{\"a_name\" : \"ming\", \"age\" : 10}"
guard let jsonData1 = jsonStr1.data(using: .utf8) else {
    exit(0)
}

guard let obj1 = try? decoder.decode(Person.self, from: jsonData1) else {
    exit(0)
}

print(obj1.name)   // ming
print(obj1.age)    // 10

第三 - CaseIterable

swift4.2之后引進CaseIterable, 用于合成簡單枚舉類型的allCases靜態(tài)屬性
舉個栗子

enum Week: CaseIterable {
    case Sun
    case Mon
    case Tue
    case Wen
    case Thu
    case Fri
    case Sat
}

print(Week.allCases)  // [Test0.Week.Sun, Test0.Week.Mon, Test0.Week.Tue, Test0.Week.Wen, Test0.Week.Thu, Test0.Week.Fri, Test0.Week.Sat]

我們也可以重寫allCases方法 例如

enum Week: CaseIterable {
    case Sun
    case Mon
    case Tue
    case Wen
    case Thu
    case Fri
    case Sat
    
    static var allCases: [Week] {
        return [.Mon, .Tue, .Wen, .Thu, .Fri, Sat, Sun]
    }
}

print(Week.allCases) //[Test0.Week.Mon, Test0.Week.Tue, Test0.Week.Wen, Test0.Week.Thu, Test0.Week.Fri, Test0.Week.Sat, Test0.Week.Sun]
ming

至于 - Identifiable

1.jpeg

完全沒搞懂呀, 僅僅是遵循了這個協(xié)議之后就必須有一個名為id的屬性嗎碱工?然后呢娃承。。怕篷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末历筝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子匙头,更是在濱河造成了極大的恐慌漫谷,老刑警劉巖仔雷,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹂析,死亡現(xiàn)場離奇詭異,居然都是意外死亡碟婆,警方通過查閱死者的電腦和手機电抚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來竖共,“玉大人蝙叛,你說我怎么就攤上這事」” “怎么了借帘?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵蜘渣,是天一觀的道長。 經(jīng)常有香客問我肺然,道長蔫缸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任际起,我火速辦了婚禮拾碌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘街望。我一直安慰自己校翔,他們只是感情好,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布灾前。 她就那樣靜靜地躺著防症,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哎甲。 梳的紋絲不亂的頭發(fā)上告希,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音烧给,去河邊找鬼燕偶。 笑死,一個胖子當著我的面吹牛础嫡,可吹牛的內(nèi)容都是我干的指么。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼榴鼎,長吁一口氣:“原來是場噩夢啊……” “哼伯诬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起巫财,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盗似,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后平项,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赫舒,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年闽瓢,在試婚紗的時候發(fā)現(xiàn)自己被綠了接癌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡扣讼,死狀恐怖缺猛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤荔燎,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布耻姥,位于F島的核電站,受9級特大地震影響有咨,放射性物質(zhì)發(fā)生泄漏咏闪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一摔吏、第九天 我趴在偏房一處隱蔽的房頂上張望鸽嫂。 院中可真熱鬧,春花似錦征讲、人聲如沸据某。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽癣籽。三九已至,卻和暖如春滤祖,著一層夾襖步出監(jiān)牢的瞬間筷狼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工匠童, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留埂材,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓汤求,卻偏偏與公主長得像俏险,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子扬绪,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容