日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

naarray查询 swift_Swift 4最全的新特性详细解析(推荐)

發(fā)布時間:2024/1/23 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 naarray查询 swift_Swift 4最全的新特性详细解析(推荐) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

引言

Swift,蘋果于2014年WWDC(蘋果開發(fā)者大會)發(fā)布的新開發(fā)語言,可與Objective-C共同運行于Mac OS和iOS平臺,用于搭建基于蘋果平臺的應(yīng)用程序。Swift吸收了眾多現(xiàn)代編程語言的優(yōu)點,盡力的提供簡潔的編程語言和強大的功能。

WWDC 2017 給大家?guī)砹撕芏囿@喜。Swift 4 也伴隨著 Xcode 9 測試版來到了我們的面前,很多強大的新特性非常值得我們期待在正式項目中去使用它。因為 Swift 4 是開源的,如果你關(guān)注 swift-evolution 這個項目的話,就應(yīng)該已經(jīng)提前了解到它的新特性了。本文參考了 WWDC 2017 以及各種資料,,從語法、字符串、標準庫、構(gòu)建過程等方面,把 Swift 4 的這些新特性一一列舉出來做介紹和分析,讓他們毫無保留地展現(xiàn)在你眼前,下面話不多說了,來隨著小編一起看看詳細的介紹吧。

一、語法改進

extension 中可以訪問 private 的屬性

考慮以下代碼:

struct Date: Equatable, Comparable {

private let secondsSinceReferenceDate: Double

static func ==(lhs: Date, rhs: Date) -> Bool {

return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate

}

static func Bool {

return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate

}

}

上面代碼定義了一個 Date 結(jié)構(gòu)體,并實現(xiàn) Equatable 和 Comparable 協(xié)議。為了讓代碼更清晰,可讀性更好,一般會把對協(xié)議的實現(xiàn)放在單獨的 extension 中,這也是一種非常符合 Swift 風格的寫法,如下:

struct Date {

private let secondsSinceReferenceDate: Double

}

extension Date: Equatable {

static func ==(lhs: Date, rhs: Date) -> Bool {

return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate

}

}

extension Date: Comparable {

static func Bool {

return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate

}

}

但是在 Swift 3 中,編譯就報錯了,因為 extension 中無法獲取到 secondsSinceReferenceDate 屬性,因為它是 private 的。于是在 Swift 3 中,必須把 private 改為 fileprivate。

struct Date {

fileprivate let secondsSinceReferenceDate: Double

}

...

但是如果用 fileprivate,屬性的作用域就會比我們需要的更大,可能會不小心造成屬性的濫用。

在 Swift 4 中,private 的屬性的作用域擴大到了 extension 中,并且被限定在了 struct 和 extension 內(nèi)部,這樣就不需要再改成 fileprivate 了,這是最好的結(jié)果。

類型和協(xié)議的組合類型

考慮以下代碼:

protocol Shakeable {

func shake()

}

extension UIButton: Shakeable { /* ... */ }

extension UISlider: Shakeable { /* ... */ }

func shakeEm(controls: [???]) {

for control in controls where control.state.isEnabled {

}

control.shake()

}

在 Swift 3 中,這里的 ??? 應(yīng)該寫什么呢?如果寫 UIControl,那么 control.shake() 就會報錯;如果寫 Shakeable,那么 control.state.isEnabled 就會報錯。其實我們也可以這樣寫:

func shakeEm(controls: [UIControl]) {

for control in controls where control.isEnabled {

if control is Shakeable {

(control as! Shakeable).shake()

}

}

}

這樣寫雖然可以跑通了,但是很丑陋。

在 Swift 4 中,可以把類型和協(xié)議用 & 組合在一起作為一個類型使用,就可以像下面這樣寫了:

protocol Shakeable {

func shake()

}

extension UIButton: Shakeable { /* ... */ }

extension UISlider: Shakeable { /* ... */ }

func shakeEm(controls: [UIControl & Shakeable]) {

for control in controls where control.state.isEnabled {

control.shake()

}// Objective-C API

@interface NSCandidateListTouchBarItem : NSTouchBarItem

@property (nullable, weak) NSView *client;

@end

}

把它聲明為了 UIControl & Shakeable 類型。OK,圓滿解決。

PS:

這個代碼例子是 WWDC 2017 的 PPT 中的,上面的代碼有點問題,control.state.isEnabled 這句代碼中,state 是沒有 isEnabled 這個屬性的,改為 control.isEnabled 就可以了。看來蘋果的工程師做 PPT 有時候還是不太嚴謹。

另外,iOS SDK 中的 API 也用這個特性做了優(yōu)化,例如:

// Objective-C API

@interface NSCandidateListTouchBarItem : NSTouchBarItem

@property (nullable, weak) NSView *client;

@end

這個 API 的 Objective-C 版本是沒有問題的,可以知道 client 屬性既是一個 NSView,又符合 NSTextInputClient 協(xié)議。然而它對應(yīng)的 Swift 3 版本為:

class NSCandidateListTouchBarItem : NSTouchBarItem {

var client: NSView?

}

僅僅是一個 NSView 類型 /(ㄒoㄒ)/~~

在 Swift 4 中,這類 API 做了優(yōu)化,改成了:

class NSCandidateListTouchBarItem : NSTouchBarItem {

var client: (NSView & NSTextInputClient)?

}

這樣類型的聲明就更加嚴謹了。

Associated Type 可以追加 Where 約束語句

在 Swift 4 中可以在 associatedtype 后面聲明的類型后追加 where 語句

associatedtype Element where

看下面是 Swift 4 標準庫中 Sequence 中 Element 的聲明:

protocol Sequence {

associatedtype Element where Self.Element == Self.Iterator.Element

// ...

}

它限定了 Sequence 中 Element 這個類型必須和 Iterator.Element 的類型一致。

通過 where 語句可以對類型添加更多的約束,使其更嚴謹,避免在使用這個類型時做多余的類型判斷。

新的 Key Paths 語法

先來看看 Swift 3 中 Key Paths 的寫法:

@objcMembers class Kid: NSObject {

dynamic var nickname: String = ""

dynamic var age: Double = 0.0

dynamic var friends: [Kid] = []

}

var ben = Kid(nickname: "Benji", age: 5.5)

let kidsNameKeyPath = #keyPath(Kid.nickname)

let name = ben.valueForKeyPath(kidsNameKeyPath)

ben.setValue("Ben", forKeyPath: kidsNameKeyPath)

Swift 4 中創(chuàng)建一個 KeyPath 用 `` 作為開頭:

\Kid.nickname

當編譯器可以推導出類型時,可以省略基礎(chǔ)類型部分:

\.nickname

上面的代碼在 Swift 4 中就可以這樣寫:

struct Kid {

var nickname: String = ""

var age: Double = 0.0

var friends: [Kid] = []

}

var ben = Kid(nickname: "Benji", age: 8, friends: [])

let name = ben[keyPath: \Kid.nickname]

ben[keyPath: \Kid.nickname] = "BigBen"

相比 Swift 3,Swift 4 的 Key Paths 具有以下優(yōu)勢:

類型可以定義為 class、struct

定義類型時無需加上 @objcMembers、dynamic 等關(guān)鍵字

性能更好

類型安全和類型推斷,例如 ben.valueForKeyPath(kidsNameKeyPath) 返回的類型是 Any,ben[keyPath: \Kid.nickname] 直接返回 String 類型

可以在所有值類型上使用

下標支持泛型

有時候會寫一些數(shù)據(jù)容器,Swift 支持通過下標來讀寫容器中的數(shù)據(jù),但是如果容器類中的數(shù)據(jù)類型定義為泛型,以前的下標語法就只能返回 Any,在取出值后需要用 as? 來轉(zhuǎn)換類型。Swift 4 定義下標也可以使用泛型了。

struct GenericDictionary {

private var data: [Key: Value]

init(data: [Key: Value]) {

self.data = data

}

subscript(key: Key) -> T? {

return data[key] as? T

}

}

let dictionary = GenericDictionary(data: ["Name": "Xiaoming"])

let name: String? = dictionary["Name"] // 不需要再寫 as? String

二、字符串

Unicode 字符串在計算 count 時的正確性改善

在 Unicode 中,有些字符是由幾個其它字符組成的,比如 é 這個字符,它可以用 \u{E9} 來表示,也可以用 e 字符和上面一撇字符組合在一起表示 \u{65}\u{301}。

考慮以下代碼:

var family = "👩"

family += "\u{200D}👩"

family += "\u{200D}👧"

family += "\u{200D}👦"

print(family)

print(family.characters.count)

這個 family 是一個由多個字符組合成的字符,打印出來的結(jié)果為 👩?👩?👧?👦。上面的代碼在 Swift 3 中打印的 count 數(shù)是 4,在 Swift 4 中打印出的 count 是 1。

更快的字符處理速度

Swift 4 的字符串優(yōu)化了底層實現(xiàn),對于英語、法語、德語、西班牙語的處理速度提高了 3.5 倍。

對于簡體中文、日語的處理速度提高了 2.5 倍。

去掉 characters

Swift 3 中的 String 需要通過 characters 去調(diào)用的屬性方法,在 Swift 4 中可以通過 String 對象本身直接調(diào)用,例如:

let values = "one,two,three..."

var i = values.characters.startIndex

while let comma = values.characters[i...

if values.characters[i..

print("found it!")

}

i = values.characters.index(after: comma)

}

Swift 4 可以把上面代碼中的所有的 characters 都去掉,修改如下:

let values = "one,two,three..."

var i = values.startIndex

while let comma = values[i...

if values[i..

print("found it!")

}

i = values.index(after: comma)

}

One-sided Slicing

Swift 4 新增了一個語法糖 ... 可以對字符串進行單側(cè)邊界取子串。

Swift 3:

let values = "abcdefg"

let startSlicingIndex = values.index(values.startIndex, offsetBy: 3)

let subvalues = values[startSlicingIndex..

// defg

Swift 4:

let values = "abcdefg"

let startSlicingIndex = values.index(values.startIndex, offsetBy: 3)

let subvalues = values[startSlicingIndex...] // One-sided Slicing

// defg

String 當做 Collection 來用

Swift 4 中 String 可以當做 Collection 來用,并不是因為 String 實現(xiàn)了 Collection 協(xié)議,而是 String 本身增加了很多 Collection 協(xié)議中的方法,使得 String 在使用時看上去就是個 Collection。例如:

翻轉(zhuǎn)字符串:

let abc: String = "abc"

print(String(abc.reversed()))

// cba

遍歷字符:

let abc: String = "abc"

for c in abc {

print(c)

}

/*

a

b

c

*/

Map、Filter、Reduce:

// map

let abc: String = "abc"

_ = abc.map {

print($0.description)

}

// filter

let filtered = abc.filter { $0 == "b" }

// reduce

let result = abc.reduce("1") { (result, c) -> String in

print(result)

print(c)

return result + String(c)

}

print(result)

Substring

在 Swift 中,String 的背后有個 Owner Object 來跟蹤和管理這個 String,String 對象在內(nèi)存中的存儲由內(nèi)存其實地址、字符數(shù)、指向 Owner Object 指針組成。Owner Object 指針指向 Owner Object 對象,Owner Object 對象持有 String Buffer。當對 String 做取子字符串操作時,子字符串的 Owner Object 指針會和原字符串指向同一個對象,因此子字符串的 Owner Object 會持有原 String 的 Buffer。當原字符串銷毀時,由于原字符串的 Buffer 被子字符串的 Owner Object 持有了,原字符串 Buffer 并不會釋放,造成極大的內(nèi)存浪費。

在 Swift 4 中,做取子串操作的結(jié)果是一個 Substring 類型,它無法直接賦值給需要 String 類型的地方。必須用 String() 包一層,系統(tǒng)會通過復制創(chuàng)建出一個新的字符串對象,這樣原字符串在銷毀時,原字符串的 Buffer 就可以完全釋放了。

let big = downloadHugeString()

let small = extractTinyString(from: big)

mainView.titleLabel.text = small // Swift 4 編譯報錯

mainView.titleLabel.text = String(small) // 編譯通過

多行字符串字面量

Swift 3 中寫很長的字符串只能寫在一行。

func tellJoke(name: String, character: Character) {

let punchline = name.filter { $0 != character }

let n = name.count - punchline.count

let joke = "Q: Why does \(name) have \(n) \(character)'s in their name?\nA: I don't know, why does \(name) have \(n) \(character)'s in their name?\nQ: Because otherwise they'd be called \(punchline)."

print(joke)

}

tellJoke(name: "Edward Woodward", character: "d")

字符串中間有換行只能通過添加 \n 字符來代表換行。

Swift 4 可以把字符串寫在一對 """ 中,這樣字符串就可以寫成多行。

func tellJoke(name: String, character: Character) {

let punchline = name.filter { $0 != character }

let n = name.count - punchline.count

let joke = """

Q: Why does \(name) have \(n) \(character)'s in their name?

A: I don't know, why does \(name) have \(n) \(character)'s in their name?

Q: Because otherwise they'd be called \(punchline).

"""

print(joke)

}

tellJoke(name: "Edward Woodward", character: "d")

三、Swift 標準庫

Encoding and Decoding

當需要將一個對象持久化時,需要把這個對象序列化,往常的做法是實現(xiàn) NSCoding 協(xié)議,寫過的人應(yīng)該都知道實現(xiàn) NSCoding 協(xié)議的代碼寫起來很痛苦,尤其是當屬性非常多的時候。幾年前有一個工具能自動生成 Objective-C 的實現(xiàn) NSCoding 協(xié)議代碼,當時用著還不錯,但后來這個工具已經(jīng)沒有人維護很久了,而且不支持 Swift。

Swift 4 中引入了 Codable 幫我們解決了這個問題。

struct Language: Codable {

var name: String

var version: Int

}

我們想將這個 Language 對象的實例持久化,只需要讓 Language 符合 Codable 協(xié)議即可,Language 中不用寫別的代碼。符合了 Codable 協(xié)議以后,可以選擇把對象 encode 成 JSON 或者 PropertyList。

Encode 操作如下:

let swift = Language(name: "Swift", version: 4)

if let encoded = try? JSONEncoder().encode(swift) {

// 把 encoded 保存起來

}

Decode 操作如下:

if let decoded = try? JSONDecoder().decode(Language.self, from: encoded) {

print(decoded.name)

}

Sequence 改進

Swift 3:

protocol Sequence {

associatedtype Iterator: IteratorProtocol

func makeIterator() -> Iterator

}

Swift 4:

protocol Sequence {

associatedtype Element

associatedtype Iterator: IteratorProtocol where Iterator.Element == Element

func makeIterator() -> Iterator

}

由于 Swift 4 中的 associatedtype 支持追加 where 語句,所以 Sequence 做了這樣的改進。

Swift 4 中獲取 Sequence 的元素類型可以不用 Iterator.Element,而是直接取 Element。

SubSequence 也做了修改:

protocol Sequence {

associatedtype SubSequence: Sequence

where SubSequence.SubSequence == SubSequence,

SubSequence.Element == Element

}

通過 where 語句的限定,保證了類型正確,避免在使用 Sequence 時做一些不必要的類型判斷。

Collection 也有一些類似的修改。

Protocol-oriented integers

整數(shù)類型符合的協(xié)議有修改,新增了 FixedWidthInteger 等協(xié)議,具體的協(xié)議繼承關(guān)系如下:

+-------------+ +-------------+

+------>+ Numeric | | Comparable |

| | (+,-,*) | | (==,,...)|

| +------------++ +---+---------+

| ^ ^

+-------+------------+ | |

| SignedNumeric | +-+-------+-----------+

| (unary -) | | BinaryInteger |

+------+-------------+ |(words,%,bitwise,...)|

^ ++---+-----+----------+

| +-----------^ ^ ^---------------+

| | | |

+------+---------++ +---------+---------------+ +--+----------------+

| SignedInteger | | FixedWidthInteger | | UnsignedInteger |

| | |(endianness,overflow,...)| | |

+---------------+-+ +-+--------------------+--+ +-+-----------------+

^ ^ ^ ^

| | | |

| | | |

++--------+-+ +-+-------+-+

|Int family |-+ |UInt family|-+

+-----------+ | +-----------+ |

+-----------+ +-----------+

Dictionary and Set enhancements

這里簡單列一下 Dictionary 和 Set 增強了哪些功能:

通過 Sequence 來初始化

可以包含重復的 Key

Filter 的結(jié)果的類型和原類型一致

Dictionary 的 mapValues 方法

Dictionary 的默認值

Dictionary 可以分組

Dictionary 可以翻轉(zhuǎn)

NSNumber bridging and Numeric types

let n = NSNumber(value: 999)

let v = n as? UInt8 // Swift 4: nil, Swift 3: 231

在 Swift 4 中,把一個值為 999 的 NSNumber 轉(zhuǎn)換為 UInt8 后,能正確的返回 nil,而在 Swift 3 中會不可預料的返回 231。

MutableCollection.swapAt(::)

MutableCollection 現(xiàn)在有了一個新方法 swapAt(::) 用來交換兩個位置的值,例如:

var mutableArray = [1, 2, 3, 4]

mutableArray.swapAt(1, 2)

print(mutableArray)

// 打印結(jié)果:[1, 3, 2, 4]

四、構(gòu)建過程改進

New Build System

Xcode 9 引入了 New Build System,可在 Xcode 9 的 File -> Project Settings... 中選擇開啟。

預編譯 Bridging Headers 文件

對于 Swift 和 Objective-C 混合的項目,Swift 調(diào)用 Objective-C 時,需要建立一個 Bridging Headers 文件,然后把 Swift 要調(diào)用的 Objective-C 類的頭文件都寫在里面,編譯器會讀取 Bridging Headers 中的頭文件,然后生成一個龐大的 Swift 文件,文件內(nèi)容是這些頭文件內(nèi)的 API 的 Swift 版本。然后編譯器會在編譯每一個 Swift 文件時,都要編譯一遍這個龐大的 Swift 文件的內(nèi)容。

有了預編譯 Bridging Headers 以后,編譯器會在預編譯階段把 Bridging Headers 編譯一次,然后插入到每個 Swift 文件中,這樣就大大提高了編譯速度。

蘋果宣稱 Xcode 9 和 Swift 4 對于 Swift 和 Objective-C 混合編譯的速度提高了 40%。

Indexing 可以在編譯的同時進行

用 Swift 開發(fā)項目時,近幾個版本的 Xcode 進行 Indexing 的速度慢的令人發(fā)指。Xcode 9 和 Swift 4 在這方面做了優(yōu)化,可以在編譯的同時進行 Indexing,一般編譯結(jié)束后 Indexing 也會同時完成。

COW Existential Containers

Swift 中有個東西叫 Existential Containers,它用來保存未知類型的值,它的內(nèi)部是一個 Inline value buffer,如果 Inline value buffer 中的值占用空間很大時,這個值會被分配在堆上,然而在堆上分配內(nèi)存是一個性能比較慢的操作。

Swift 4 中為了優(yōu)化性能引入了 COW Existential Containers,這里的 COW 就代表 "Copy-On-Write",當存在多個相同的值時,他們會共用 buffer 上的空間,直到某個值被修改時,這個被修改的值才會被拷貝一份并分配內(nèi)存空間。

移除未調(diào)用的協(xié)議實現(xiàn)

struct Date {

private let secondsSinceReferenceDate: Double

}

extension Date: Equatable {

static func ==(lhs: Date, rhs: Date) -> Bool {

return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate

}

}

extension Date: Comparable {

static func Bool {

return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate

}

}

看上面例子,Date 實現(xiàn)了 Equatable 和 Comparable 協(xié)議。編譯時如果編譯器發(fā)現(xiàn)沒有任何地方調(diào)用了對 Date 進行大小比較的方法,編譯器會移除 Comparable 協(xié)議的實現(xiàn),來達到減小包大小的目的。

減少隱式 @objc 自動推斷

在項目中想把 Swift 寫的 API 暴露給 Objective-C 調(diào)用,需要增加 @objc。在 Swift 3 中,編譯器會在很多地方為我們隱式的加上 @objc,例如當一個類繼承于 NSObject,那么這個類的所有方法都會被隱式的加上 @objc。

class MyClass: NSObject {

func print() { ... } // 包含隱式的 @objc

func show() { ... } // 包含隱式的 @objc

}

這樣很多并不需要暴露給 Objective-C 也被加上了 @objc。大量 @objc 會導致二進制文件大小的增加。

在 Swift 4 中,隱式 @objc 自動推斷只會發(fā)生在很少的當必須要使用 @objc 的情況,比如:

復寫父類的 Objective-C 方法

符合一個 Objective-C 的協(xié)議

其它大多數(shù)地方必須手工顯示的加上 @objc。

減少了隱式 @objc 自動推斷后,Apple Music app 的包大小減少了 5.7%。

五、 Exclusive Access to Memory

在遍歷一個 Collection 的時候可以去修改每一個元素的值,但是在遍歷時如果去添加或刪除一個元素就可能會引起 Crash。

例如為 MutableCollection 擴展一個 modifyEach 方法來修改每個元素的值,代碼如下:

extension MutableCollection {

mutating func modifyEach(_ body: (inout Element) -> ()) {

for index in self.indices {

body(&self[index])

}

}

}

假如在調(diào)用 modifyEach 時去刪除元素:

var numbers = [1, 2, 3]

numbers.modifyEach { element in

element *= 2

numbers.removeAll()

}

就會在運行時 Crash。Swift 4 中引入了 Exclusive Access to Memory,使得這個錯誤可以在編譯時被檢查出來。

六、 兼容性

Xcode 9 中同時集成了 Swift 3.2 和 Swift 4。

Swift 3.2 完全兼容 Swift 3.1,并會在過時的語法或函數(shù)上報告警告。

Swift 3.2 具有 Swift 4 的一些寫法,但是性能不如 Swift 4。

Swift 3.2 和 Swift 4 可以混合編譯,可以指定一部分模塊用 Swift 3.2 編譯,一部分用 Swift 4 編譯。

遷移到 Swift 4 后能獲得 Swift 4 所有的新特性,并且性能比 Swift 3.2 好。

總結(jié):當 Xcode 正式版發(fā)布后,現(xiàn)有的 Swift 代碼可以直接升級到 Swift 3.2 而不用做任何改動,后續(xù)可以再遷移到 Swift 4。或者直接遷移到 Swift 4 也可以,Swift 4 相比 Swift 3 的 API 變化還是不大的,很多第三方庫都可以直接用 Swift 4 編譯。Swift 1 到 2 和 Swift 2 到 3 的遷移的痛苦在 3 到 4 的遷移上已經(jīng)大大改善了。

七、參考資料

WWDC 2017 Session 402 《What's New in Swift》

WWDC 2017 Session 212 《What's New in Foundation》

WWDC 2017 Session 102 《Platforms State of the Union》

《Swift Language Programming (Swift 4.0)》

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

總結(jié)

以上是生活随笔為你收集整理的naarray查询 swift_Swift 4最全的新特性详细解析(推荐)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。