Swift4.2 語(yǔ)法新特性(轉(zhuǎn)了自己看)

CaseInterable協(xié)議

  • SE-0194介紹了在Swift 4.2中新增的一個(gè)新的CaseIterable協(xié)議
  • 定義的枚舉遵循CaseIterable協(xié)議后, 編譯時(shí)Swift 會(huì)自動(dòng)合成一個(gè)allCases屬性,是包含枚舉的所有case項(xiàng)的數(shù)組
enum NetState: CaseIterable {
    case wifi
    case hotWifi
    case mobile
    case none
}

之后我們?cè)谄渌胤秸{(diào)用改枚舉時(shí)就可以獲取到allCase屬性, 如下

print(NetState.allCases)
print("case個(gè)數(shù): " + "\(NetState.allCases.count)")

for item in NetState.allCases {
    print(item)
}

// 輸出結(jié)果:
[__lldb_expr_9.NetState.wifi, __lldb_expr_9.NetState.hotWifi, __lldb_expr_9.NetState.mobile, __lldb_expr_9.NetState.none]

case個(gè)數(shù): 4

wifi
hotWifi
mobile
none

這個(gè)allCases的自動(dòng)合成僅替換沒(méi)有參數(shù)的case值, 但是如果需要你需要所有case值, 可以重寫(xiě)allCases屬性自己添加

enum FoodKind: CaseIterable {
    //此處, 必須重寫(xiě)allCases屬性, 否則報(bào)錯(cuò)
    static var allCases: [FoodKind] {
        return [.apple, .pear, .orange(look: false)]
    }

    case apple
    case pear
    case orange(look: Bool)
}

for item in FoodKind.allCases {
    print(item)
}

/*
 * 輸出結(jié)果:
 apple
 pear
 orange(look: false)
*/

如果有枚舉項(xiàng)標(biāo)記為unavailable,則默認(rèn)無(wú)法合成allCases,只能依靠自己來(lái)手動(dòng)合成

enum CarKind: CaseIterable {
    //當(dāng)有unavailable修飾的case值, 也必須重寫(xiě)allCase屬性
    static var allCases: [CarKind] {
        return [.bwm, .ford]
    }

    case bwm
    case ford

    @available(*, unavailable)
    case toyota
}

for item in CarKind.allCases {
    print(item)
}

/*
 輸出結(jié)果:
 bwm
 ford
 */

#warning#error編譯指令

  • SE-0196介紹新的編譯指令來(lái)強(qiáng)制Xcodebuild時(shí)生成警告或錯(cuò)誤信息
  • 這兩個(gè)指令是#warning#error,前者會(huì)強(qiáng)制Xcode在生成你的代碼時(shí)發(fā)出一個(gè)警告,后者會(huì)發(fā)出一個(gè)編譯錯(cuò)誤這樣你的代碼就完全不能編譯
  • #warning主要用于提醒你或者別人一些工作還沒(méi)有完成,Xcode模板常使用#warning標(biāo)記一些你需要替換成自己代碼的方法存根(method stubs)。
  • #error主要用于如果你發(fā)送一個(gè)庫(kù),需要其他開(kāi)發(fā)者提供一些數(shù)據(jù)。比如,一個(gè)網(wǎng)絡(luò) API的認(rèn)證密碼,你需要用戶輸入它們自己的密碼,就使用#error在繼續(xù)之前強(qiáng)制他們更改這行代碼

[圖片上傳失敗...(image-4ee780-1537237237181)]

#warning#error可以和已存的#if編譯指令共同使用,并且只有在條件為true時(shí)才會(huì)激活。例如:

#if os(macOS)
#error("MyLibrary is not supported on macOS.")
#endif

動(dòng)態(tài)成員查找

  • SE-0195介紹了一個(gè)方法,讓Swift更接近類(lèi)似Python的腳本語(yǔ)言, 讓Swift可以以屬性訪問(wèn)的方式調(diào)用下標(biāo)操作
  • 這讓我們可以像Python一樣來(lái)訪問(wèn)字典值,不過(guò)是以類(lèi)型安全的方式, 其核心在于:
    • @dynamicMemberLookup: 可以讓Swift以一種下標(biāo)方法去進(jìn)行屬性訪問(wèn)
    • subscript(dynamicMember:):可以通過(guò)所請(qǐng)求屬性的字符串名得到,并且可以返回你想要的任何值
  • 我們可以創(chuàng)建一個(gè)Titan結(jié)構(gòu),并且從一個(gè)字典讀取它的值
struct Titan {
    subscript(dynamicMember member: String) -> String {
        let properties = ["name": "Titanjun", "city": "Hang"]
        return properties[member, default: "0"] //默認(rèn)值
    }
}

  • 可以看到上述代碼按字符串接收成員名字,并返回一個(gè)字符串。
  • 從內(nèi)部看它只是在一個(gè)字典中查找這個(gè)成員名字并返回它的值
  • 即使取不到對(duì)應(yīng)的值, 也會(huì)以默認(rèn)值的形式返回, 上述結(jié)構(gòu)的代碼可以這么寫(xiě)
let titan = Titan()

print(titan.name)
print(titan.city)
print(titan.age)

// 輸出:
Titanjun
Hang
0

處理多種不同的類(lèi)型

  • 上述subscript(dynamicMember:) 方法必須返回一串字符,這體現(xiàn)了Swift的類(lèi)型安全性
  • 如果你想要多種不同的類(lèi)型, 就執(zhí)行不同的subscript(dynamicMember:)方法
@dynamicMemberLookup
struct Titan {
    subscript(dynamicMember member: String) -> String {
        let properties = ["name": "Titanjun", "city": "Hang"]
        return properties[member, default: "0"] //默認(rèn)值
    }

    subscript(dynamicMember member: String) -> Int {
        let properties = ["age": 20, "source": 99]
        return properties[member, default: 0] //默認(rèn)值
    }
}

需要注意的是: 這里取值的時(shí)候, 必須注明所取得值的類(lèi)型

let titan = Titan()
let name: String = titan.name
let city: String = titan.city
let age: Int = titan.age
let jun: String = titan.jun

print(jun)
print("name = \(name), city = \(city), age = \(age)")

//輸出:
0
name = Titanjuun, city = Hang, age = 20

增強(qiáng)的條件一致性

條件一致性在Swift 4.1中引入,一個(gè)類(lèi)型的所有元素如果符合Hashable協(xié)議,則類(lèi)型自動(dòng)符合Hashable協(xié)議

//定義Purchaseable協(xié)議
protocol Purchaseable {
    func buy()
}

//定義一個(gè)符合該協(xié)議的結(jié)構(gòu)體
struct Book: Purchaseable {
    func buy() {
        print("You bought a book")
    }
}

//數(shù)組遵循該協(xié)議, 并且每一個(gè)元素也遵循該協(xié)議
extension Array: Purchaseable where Element: Purchaseable {
    func buy() {
        for item in self {
            item.buy()
        }
    }
}

下面我們?cè)赟wift 4.1中運(yùn)行如下代碼, 會(huì)發(fā)現(xiàn)崩潰

let items: Any = [Book(), Book(), Book()]

if let books = items as? Purchaseable {
    books.buy()
}

  • 如果你收到一種類(lèi)型的數(shù)據(jù),想要檢查它是否可以被轉(zhuǎn)化為一個(gè)條件一致性協(xié)議, 這種在Swift 4.1中是不支持的, 但是在Swift 4.2中卻可以很好的解決
  • 另外, 對(duì)Hashable一致性自動(dòng)合并的支持在Swift 4.2被大幅提高,來(lái)自Swift 標(biāo)準(zhǔn)庫(kù)的幾個(gè)內(nèi)置類(lèi)型,包括optionals, arrays, dictionariesranges, 現(xiàn)在當(dāng)他們的元素符合Hashable時(shí)會(huì)自動(dòng)符合Hashable 協(xié)議

本地集合元素移除

SE-0197介紹一個(gè)新的removeAll(where:)方法, 高效地執(zhí)行根據(jù)條件刪除操作

var pythons = ["John", "Michael", "Graham", "Terry", "Eric", "Terry"]
pythons.removeAll { $0.hasPrefix("Terry") }
print(pythons)

//輸出: ["John", "Michael", "Graham", "Eric"]

對(duì)比filter過(guò)濾方法

var python2 = ["John", "Michael", "Graham", "Terry", "Eric", "Terry"]
python2 = python2.filter { !$0.hasPrefix("Terry") }
print(python2)

這并不是非常有效地使用內(nèi)存,它指定了你不想要的東西,而不是你想要的東西

隨機(jī)數(shù)字的生成和洗牌

  • SE-0202Swift引入了新的隨機(jī)數(shù)API
  • 可以通過(guò)調(diào)用random()隨機(jī)數(shù)方法來(lái)生成一個(gè)隨機(jī)數(shù), 只需提供一個(gè)隨機(jī)數(shù)范圍即可
let ranInt = Int.random(in: 0..<5)
let ranFloat = Float.random(in: 0..<5)
let ranDouble = Double.random(in: 0..<5)
let ranCGFloat = CGFloat.random(in: 0..<5)
let ranBOOL = Bool.random()

對(duì)數(shù)組進(jìn)行重新洗牌

SE-0202還支持使用新方法shuffle()shuffled()方法對(duì)數(shù)組元素進(jìn)行重新隨機(jī)排序

var albums = ["Red", "1989", "Reputation"]

// 沒(méi)有返回值
albums.shuffle()

// 有返回值, 重新返回一個(gè)數(shù)組
let shuffled = albums.shuffled()

獲取數(shù)組中的一個(gè)隨機(jī)元素

randomElement(): 數(shù)組的一個(gè)新方法, 如果數(shù)組部位空, 則返回?cái)?shù)組中的一個(gè)隨機(jī)元素, 否則返回nil

if let random = albums.randomElement() {
    print("The random album is \(random).")
}

更簡(jiǎn)單,更安全的哈希

  • SE-0206介紹了在Swift 4.1中簡(jiǎn)化了我們使自定義類(lèi)型符合Hashable協(xié)議的方式
  • Swift 4.2引入了一個(gè)新的Hasher結(jié)構(gòu),它提供了一個(gè)隨機(jī)播種的通用散列函數(shù)
struct iPad: Hashable {
    var serialNumber: String
    var capacity: Int

    func hash(into hasher: inout Hasher) {
        hasher.combine(serialNumber)
    }
}

  • 可以通過(guò)combine()重復(fù)調(diào)用將更多屬性添加到散列,并且添加屬性的順序會(huì)影響完成的散列值。
  • 還可以將其Hasher用作獨(dú)立散列發(fā)生器:只要提供您想散列的任何值,然后調(diào)用finalize()以生成最終值
let first = iPad(serialNumber: "12345", capacity: 256)
let second = iPad(serialNumber: "54321", capacity: 512)

var hasher = Hasher()
hasher.combine(first)
hasher.combine(second)
let hash = hasher.finalize()

  • Hasher每次散列對(duì)象時(shí)都會(huì)使用隨機(jī)種子,這意味著任何對(duì)象的散列值在您的應(yīng)用運(yùn)行之間有效地保證是不同的
  • 這又意味著您添加到集合或字典中的元素很可能在您每次運(yùn)行應(yīng)用程序時(shí)都有不同的順序

檢查序列元素是否符合條件

SE-0207提供了allSatisfy()一種檢查序列中的所有元素是否滿足條件的新方法

//判斷數(shù)組的所有元素是否全部大于85
let scores = [86, 88, 95, 92]
//返回一個(gè)BOOL
let passed = scores.allSatisfy({ $0 > 85 })
print(passed)

//輸出: true

布爾切換

SE-0199引入了一種新的toggle()方法, 可以將布爾值取反, 實(shí)現(xiàn)代碼如下:

extension Bool {
   mutating func toggle() {
      self = !self
   }
}

測(cè)試代碼

var isSwift = true
//toggle函數(shù)沒(méi)有返回值
isSwift.toggle()
print(isSwift)

  • SE-0204介紹了數(shù)組中的獲取滿足條件的數(shù)組中的最后一個(gè)元素或者索引值
  • Swift 4.1中我們只能取得first值, 卻無(wú)法獲取數(shù)組中的最后一個(gè)值(或者要用大量代碼實(shí)現(xiàn))
  • Swift 4.2中提供了last(where:)lastIndex(where:)方法來(lái)獲取數(shù)組中滿足條件的最后的元素和索引值
//獲取滿足條件的數(shù)組中的第一個(gè)值
let a = [20, 30, 10, 40, 20, 30, 10, 40, 20]
print(a.first(where: { $0 > 25 }))  
print(a.index(where: { $0 > 25 }))
print(a.index(of: 10))

//輸出:
30
1
2

Swift 4.2中新增的last函數(shù)

//在Swift4.1中
print((a.reversed().index(where: { $0 > 25 })?.base).map({ a.index(before: $0) }))
//輸出: 7

//Swift 4.2
//獲取滿足條件的元素
print(a.last(where: { $0 > 25 }))   //40
//獲取滿足條件的元素的索引
print(a.lastIndex(where: { $0 > 25 }))   //7

展望Swift 5.0

  • 蘋(píng)果形容Swift 4.2為”為了實(shí)現(xiàn)Swift 5中ABI穩(wěn)定性的中繼點(diǎn)”, 想必Swift 4.1Swift 4.2的發(fā)布也是為了Swift 5.0做一個(gè)鋪墊
  • 最后還是期待Swift 5.0能夠帶來(lái)更加穩(wěn)定的API

作者:ShmilyCoder
鏈接:http://www.itdecent.cn/p/86ca289a6e47

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容