Swift 4.2 更新大全

1掌唾、Bool.toggle

struct Layer {
    var isHidden = false
}

struct View {
    var layer = Layer()
}

var view = View()

// Before:
view.layer.isHidden = !view.layer.isHidden
view.layer.isHidden

// Now:
view.layer.isHidden.toggle()


2面哼、對Sequence and Collection 新增一些方法

  • 新增allSatisfy 會根據(jù)closure中的謂詞進行判斷,只有全部為true才會返回true
let digits = 0...9
let areAllSmallerThanTen = digits.allSatisfy { $0 < 10 }
areAllSmallerThanTen // true

let areAllEven = digits.allSatisfy { $0 % 2 == 0 }
areAllEven    // false
  • 新增last(where:) 從后往前開始遍歷,直到找到滿足條件的第一個元素红淡,返回改元素
let digits = 0...9
let lastEvenDigit = digits.last { $0 % 2 == 0 }
lastEvenDigit //8
  • 新增 lastIndex(where:) 從后往前開始遍歷,直到找到滿足條件的第一個元素降铸,返回其Index
let text = "Vamos a la playa"
let lastWordBreak = text.lastIndex(where: { $0 == "l" })
let lastWord = lastWordBreak.map { text[text.index(after: $0)...] }
lastWord // aya
  • 新增lastIndex(of:)從后往前遍歷在旱,直到輸入的值和數(shù)組中的值相等,返回其Index
text.lastIndex(of: "l") == lastWordBreak //true
  • 移除index(of:)index(where:)推掸,分別用firstIndex(of:)firstIndex(where:) 代替
let text = "Vamos a la playa"
let firstWordBreak = text.firstIndex(where: { $0 == " " })
let firstWord = firstWordBreak.map { text[..<$0] }
firstWord //Vamos
  • 新增removeAll(where:) 刪除滿足條件的元素
var numbers = Array(1...10)
numbers.removeAll(where: { $0 % 2 == 0 })
numbers // 1 3 5 7 9


3桶蝎、新增協(xié)議 CaseIterable

協(xié)議大多用在enum中,添加了一個allCases屬性谅畅,該屬性是一個collection

3.1 簡單使用

enum Terrain: CaseIterable {
    case water
    case forest
    case desert
    case road
}

Terrain.allCases // [water,forest,desert,road]
Terrain.allCases.count // 4

3.2 這個屬性可以用在TableView Sections

enum TableSection: Int, CaseIterable {
    /// The section for the search field
    case search = 0
    /// Featured content
    case featured = 1
    /// Regular content cells
    case standard = 2
}

func numberOfSections(in tableView: UITableView) -> Int {
    return TableSection.allCases.count
}

override func tableView(_ tableView: UITableView,
    cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    let section = TableSection.allCases[indexPath.section]
    switch section {
    case .search: ...
    case .featured: ...
    case .standard: ...
    }
}

3.3 還可以在一個Enum中的case引用另外一個Enum登渣,但是必須重寫allCases

enum Intensity: CaseIterable {
    case light
    case medium
    case hard
}

enum Workout {
    case resting
    case running(Intensity)
    case cycling(Intensity)
}

extension Workout: CaseIterable {
    static var allCases: [Workout] {
        return [.resting]
            + Intensity.allCases.map(Workout.running)
            + Intensity.allCases.map(Workout.cycling)
    }
}

Workout.allCases
/*  .resting
    .running(.light)
    .running(.medium)
    .running(.hard)
    .cycling(.light)
    .cycling(.medium)
    .cycling(.hard) */
Workout.allCases.count // 7

3.4 為了防止在自定義的allCases中漏掉新增的case,可以在內(nèi)部新增一個方法毡泻,用于提示我們需要做一些改變

extension Workout: CaseIterable {
    static var allCases: [Workout] {
        /// Dummy function whose only purpose is to produce
        /// an error when a new case is added to Workout. Never call!
        @available(*, unavailable, message: "Only for exhaustiveness checking, don't call")
        func _assertExhaustiveness(of workout: Workout, never: Never) {
            switch workout {
            case .resting,
                 .running(.light), .running(.medium), .running(.hard),
                 .cycling(.light), .cycling(.medium), .cycling(.hard):
                break
            }
        }

        return [.resting]
            + Intensity.allCases.map(Workout.running)
            + Intensity.allCases.map(Workout.cycling)
    }
}

這樣子當我們新增了case胜茧,就會提示我們需要進行適配了。

這個動作就像我們在做單元測試一樣仇味,所以當新增了case呻顽,務(wù)必適配allCases

3.5 在其他的類型中使用 CaseInterable 協(xié)議,

除了普通的enum有著默認的實現(xiàn),其他的都需要自己去重寫allCases

  • Bool
extension Bool: CaseIterable {
    public static var allCases: [Bool] {
        return [false, true]
    }
}

Bool.allCases // → [false, true]
  • UInt8
extension UInt8: CaseIterable {
    public static var allCases: ClosedRange<UInt8> {
        return .min ... .max
    }
}

UInt8.allCases.count // → 256

這里官方還給出了建議丹墨,就是如果生成的時候很消耗資源廊遍,請考慮使用lazy,例如:

UInt8.allCases.lazy.count

3.6 如果allCases中有optional贩挣,那么必須定義 public typealias AllCases = [?],否則編譯器會報錯

extension Optional: CaseIterable where Wrapped: CaseIterable {
    public typealias AllCases = [Wrapped?]
    public static var allCases: AllCases {
        return [nil] + Wrapped.allCases.map { $0 }
    }
}
enum CompassDirection: CaseIterable {
    case north, south, east, west
}

CompassDirection.allCases // → [north, south, east, west]
CompassDirection.allCases.count // → 4
CompassDirection?.allCases // → [nil, north, south, east, west]
CompassDirection?.allCases.count // → 5


4昧碉、統(tǒng)一隨機數(shù)的接口

4.1數(shù)字類型

Int.random(in: 1...1000)
UInt8.random(in: .min ... .max)
Double.random(in: 0..<1)

4.2 Bool

Bool.random()

4.3 collection(集合)

  • 隨機取一個元素
let emotions = "??????????????????"
let randomEmotion = emotions.randomElement()! 
  • 打亂集合

    • let

      let numbers = 1...10
      let shuffled = numbers.shuffled()
      
    • var

      var mutableNumbers = Array(numbers)
      // Shuffles in place
      mutableNumbers.shuffle()    
      

4.4 重寫隨機數(shù)生成器

/// A dummy random number generator that just mimics `SystemRandomNumberGenerator`.
struct MyRandomNumberGenerator: RandomNumberGenerator {
    var base = SystemRandomNumberGenerator()
    mutating func next() -> UInt64 {
        // 如果有特殊的需求,就這這里進行處理
        return base.next()
    }
}

var customRNG = MyRandomNumberGenerator()
Int.random(in: 0...100, using: &customRNG)

4.5 為enum添加隨機函數(shù)

enum Suit: String, CaseIterable {
    case diamonds = "?"
    case clubs = "?"
    case hearts = "?"
    case spades = "?"

    static func random<T: RandomNumberGenerator>(using generator: inout T) -> Suit {
        // Using CaseIterable for the implementation
        return allCases.randomElement(using: &generator)!

    }

    static func random() -> Suit {
        // 如果不需要系統(tǒng)的隨機數(shù)生成揽惹,就把這個類型替換
        var rng = SystemRandomNumberGenerator()
        return Suit.random(using: &rng)
    }
}

let randomSuit = Suit.random()
randomSuit.rawValue 


5被饿、重新設(shè)計了Hashable

減少hash值碰撞

栗子:

struct Point {
    var x: Int { didSet { recomputeDistance() } }
    var y: Int { didSet { recomputeDistance() } }

    /// Cached. Should be ignored by Equatable and Hashable.
    private(set) var distanceFromOrigin: Double

    init(x: Int, y: Int) {
        self.x = x
        self.y = y
        self.distanceFromOrigin = Point.distanceFromOrigin(x: x, y: y)
    }

    private mutating func recomputeDistance() {
        distanceFromOrigin = Point.distanceFromOrigin(x: x, y: y)
    }

    private static func distanceFromOrigin(x: Int, y: Int) -> Double {
        return Double(x * x + y * y).squareRoot()
    }
}

extension Point: Equatable {
    static func ==(lhs: Point, rhs: Point) -> Bool {
        // Ignore distanceFromOrigin for determining equality
        return lhs.x == rhs.x && lhs.y == rhs.y
    }
}

extension Point: Hashable {
    func hash(into hasher: inout Hasher) {
        // Ignore distanceFromOrigin for hashing
        hasher.combine(x)
        hasher.combine(y)
    }
}

let p1 = Point(x: 3, y: 4)
p1.hashValue
let p2 = Point(x: 4, y: 3)
p2.hashValue
assert(p1.hashValue != p2.hashValue)

如果類/結(jié)構(gòu)體中的數(shù)據(jù)類型都是一種,比如Int搪搏,在采用return x ^ y這種算法狭握,就很容易發(fā)生碰撞,所以我們在重寫hash的時候一定要注意這個東西疯溺,要在性能和碰撞之間做平衡论颅。


6哎垦、動態(tài)映射的修改

func isEncodable(_ value: Any) -> Bool {
    return value is Encodable
}

// This would return false in Swift 4.1
let encodableArray = [1, 2, 3]
isEncodable(encodableArray)

// Verify that the dynamic check doesn't succeed when the conditional conformance criteria aren't met.
struct NonEncodable {}
let nonEncodableArray = [NonEncodable(), NonEncodable()]
isEncodable(nonEncodableArray)//false
assert(isEncodable(nonEncodableArray) == false)


7、擴展中的合成一致性

enum Either<Left, Right> {
    case left(Left)
    case right(Right)
}

// No code necessary
extension Either: Equatable where Left: Equatable, Right: Equatable {}
extension Either: Hashable where Left: Hashable, Right: Hashable {}

Either<Int, String>.left(42) == Either<Int, String>.left(42) //true


8恃疯、Range的修改

官方說道:CountableRangeCountableClosedRange還存在漏设,但是不應(yīng)該在之后的代碼中使用到他們了,這個是為了兼容之前的代碼

let integerRange: Range = 0..<5
// integer是一個collection今妄,所以可以調(diào)用map方法
let integerStrings = integerRange.map { String($0) }
integerStrings

let floatRange: Range = 0.0..<5.0
// 以為float不是一個collection郑口,所以不能調(diào)用map方法
//floatRange.map { String($0) } // error!


9、新增@dynamicMemberLookup

允許我們運行時盾鳞,動態(tài)查找屬性犬性,可以用來修飾class/struct/protocol/enum

使用@dynamicMemberLookup需要重寫如下代碼:

subscript(dynamicMember input: String) -> XX {
    get {
            guard let value = getenv(name) else { return nil }
            return xx
        }
    nonmutating set {
        if let value = newValue {
            setenv(name, value, /*overwrite:*/ 1)
        } else {
            unsetenv(name)
        }
    }
}
@dynamicMemberLookup
struct Uppercaser {
    subscript(dynamicMember input: String) -> String {
        return input.uppercased()
    }
}

Uppercaser().hello // → "HELLO"
// You can type anything, as long as Swift accepts it as an identifier.
Uppercaser().k?seso?e // → "K?SESOSSE"


10、guard let self = self

喜大奔普終于不用寫

guard let `self` = self ...


11腾仅、if let self = self { … }

也不用這樣子寫啦

if let weakself = self { … }


12乒裆、支持#warning#error

  • error

    #if MYLIB_VERSION < 3 && os(macOS)
    #error("MyLib versions < 3 are not supported on macOS")
    #endif
    
  • warning

    func doSomethingImportant() {
        #warning("TODO: missing implementation")
    }
    doSomethingImportant()
    


13、#if compiler version directive

#if compiler(>=4.2)
print("Using the Swift 4.2 compiler or greater in any compatibility mode")
print("swift編譯器大于等于4.2") //菜雞翻譯推励,如果不準鹤耍,煩請告知
#endif

#if swift(>=4.2)
print("Using the Swift 4.2 compiler or greater in Swift 4.2 or greater compatibility mode")
print("使用swift4.2編譯器編譯swift大于/等于4.2的版本") //菜雞翻譯,如果不準验辞,煩請告知
#endif

#if compiler(>=5.0)
print("Using the Swift 5.0 compiler or greater in any compatibility mode")
print("swift編譯器大于等于5.0") //菜雞翻譯稿黄,如果不準,煩請告知
#endif


14受神、MemoryLayout中新增offset(of:)方法

struct Point {
    var x: Float
    var y: Float
    var z: Float
}

MemoryLayout<Point>.offset(of: \Point.x) // 0
MemoryLayout<Point>.offset(of: \Point.y) // 4
MemoryLayout<Point>.offset(of: \Point.z) // 8

官方解釋:

許多圖形和數(shù)學庫接受任意輸入格式的輸入數(shù)據(jù)抛猖,用戶在設(shè)置輸入緩沖區(qū)時必須向API描述。例如鼻听,OpenGL允許您使用一系列glVertexAttribPointerAPI 調(diào)用來描述頂點緩沖區(qū)的布局财著。在C中,您可以使用標準offsetof宏來獲取結(jié)構(gòu)中字段的偏移量撑碴,允許您使用編譯器對類型布局的了解來填充這些函數(shù)調(diào)用:

//我們的一個頂點條目的布局
struct MyVertex {
   float position [ 4 ];
  float 正常 [ 4 ];
  uint16_t texcoord [ 2 ];
};

enum MyVertexAttribute {Position撑教,Normal,TexCoord};

glVertexAttribPointer(Position醉拓,4伟姐,GL_FLOAT,GL_FALSE亿卤,
                       sizeof(MyVertex)愤兵,(void *)offsetof(MyVertex,position));
glVertexAttribPointer(Normal排吴,4秆乳,GL_FLOAT,GL_FALSE,
                       sizeof(MyVertex)屹堰,(void *)offsetof(MyVertex肛冶,normal));
glVertexAttribPointer(TexCoord,2扯键,GL_UNSIGNED_BYTE睦袖,GL_TRUE,
                       sizeof(MyVertex)荣刑,(void *)offsetof(MyVertex馅笙,texcoord));

目前offsetof在Swift中沒有相同的功能,因此這些API的用戶必須在C中編寫代碼的這些部分嘶摊,或者在頭腦中執(zhí)行Swift內(nèi)存布局延蟹,如果他們更改了數(shù)據(jù)布局或Swift评矩,則容易出錯叶堆。編譯器實現(xiàn)更改其布局算法(它保留權(quán)利)。


15斥杜、新增兩個修飾符@inlinable@usableFromInline

  • @inlinable : 開發(fā)者可以將一些公共功能注釋為@inlinable虱颗。這給編譯器提供了優(yōu)化跨模塊邊界的泛型代碼的選項
@inlinable public func allEqual<T>(_ seq: T) -> Bool
    where T : Sequence, T.Element : Equatable {
  var iter = seq.makeIterator()
  guard let first = iter.next() else { return true }

  func rec(_ iter: inout T.Iterator) -> Bool {
    guard let next = iter.next() else { return true }
    return next == first && rec(&iter)
  }

  return rec(&iter)
}
  • usableFromInline: 使用@usableFromInline在你的“ABI-public”庫中進行某些內(nèi)部聲明,允許它們在可鏈接函數(shù)中使用蔗喂。

    public class C {
      @usableFromInline internal class D {
        @usableFromInline internal func f() {}
        
        @inlinable internal func g() {}
      }
    }
    


16忘渔、withUnsafePointer(to::) 和 withUnsafeBytes(of::)

withUnsafePointerwithUnsafeBytes通過指針提供對變量和屬性的內(nèi)存表示的臨時范圍訪問。它們當前只接受inout參數(shù)缰儿,這使得處理不可變值的內(nèi)存表示比它應(yīng)該做的更尷尬和更低效畦粮,需要復(fù)制:

let x = 1 + 6
var x2 = x
let value = withUnsafeBytes(of: &x2) {
    ptr in
    return (ptr[0] + ptr[1])
} 
value // 7

其內(nèi)部實現(xiàn)如下:

public func withUnsafePointer<T, Result>(
  to value: /*borrowed*/ T,
  _ body: (UnsafePointer<T>) throws -> Result
) rethrows -> Result

public func withUnsafeBytes<T, Result>(
  of value: /*borrowed*/ T,
  _ body: (UnsafeRawBufferPointer) throws -> Result
) re
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市乖阵,隨后出現(xiàn)的幾起案子宣赔,更是在濱河造成了極大的恐慌,老刑警劉巖瞪浸,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件儒将,死亡現(xiàn)場離奇詭異,居然都是意外死亡对蒲,警方通過查閱死者的電腦和手機钩蚊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹈矮,“玉大人砰逻,你說我怎么就攤上這事》耗瘢” “怎么了蝠咆?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長谈况。 經(jīng)常有香客問我勺美,道長递胧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任赡茸,我火速辦了婚禮缎脾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘占卧。我一直安慰自己遗菠,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布华蜒。 她就那樣靜靜地躺著辙纬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叭喜。 梳的紋絲不亂的頭發(fā)上贺拣,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音捂蕴,去河邊找鬼譬涡。 笑死,一個胖子當著我的面吹牛啥辨,可吹牛的內(nèi)容都是我干的涡匀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼溉知,長吁一口氣:“原來是場噩夢啊……” “哼陨瘩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起级乍,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤舌劳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后卡者,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒿囤,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年崇决,在試婚紗的時候發(fā)現(xiàn)自己被綠了材诽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡恒傻,死狀恐怖脸侥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盈厘,我是刑警寧澤睁枕,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響外遇,放射性物質(zhì)發(fā)生泄漏注簿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一跳仿、第九天 我趴在偏房一處隱蔽的房頂上張望诡渴。 院中可真熱鬧,春花似錦菲语、人聲如沸妄辩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽眼耀。三九已至,卻和暖如春佩憾,著一層夾襖步出監(jiān)牢的瞬間哮伟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工鸯屿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留澈吨,地道東北人把敢。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓寄摆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親修赞。 傳聞我的和親對象是個殘疾皇子婶恼,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

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