Swift進階學習筆記

xixinRunBoy發表於2018-04-16

設計原則

不允許忽略錯誤的設計原則

不斷的將模板程式碼和功能程式碼分離,實現高可重用性

contains使用

檢查一個序列中的所有元素是否全部都滿足某個條件, 封裝一個更具有描述性名字的新函式

extension Sequence {
  public func all(matching predicate: (Element) -> Bool) -> Bool {
  // 對於 個條件,如果沒有元素 滿 它的話,那意味著所有元素都滿 它:
  return !contains { !predicate($0) } }
}
let evenNums = nums.filter { $0 % 2 == 0 } // [2, 4, 6, 8, 10] 
evenNums.all { $0 % 2 == 0 } // true
複製程式碼

flatMap使用

實現原理

extension Array {
  func flatMap<T>(_ transform: (Element) -> [T]) -> [T] {
    var result: [T] = []
    for x in self {
      // map的實現區別是append(_:)
      result.append(contentsOf: transform(x)) 
    }
    return result 
  }
}
複製程式碼

forEach使用

在一個 view controller 裡你想把一個陣列中的檢視都加到當前 view 上的話,只需要寫 theViews.forEach(view.addSubview) 就足夠了 因為return會造成行為不太明確,建議大多數其他情況不要用forEach

切片ArraySlice

切片型別只是陣列的一種表示方式,它背後的資料仍 然是原來的陣列,只不過是用切片的方式來進行表示。這意味著原來的陣列並不需要被複制。 ArraySlice 具有的方法和 Array 上定義的方法是一致的,因此你可以把它當做陣列來進行處理。 如果你需要將切片轉換為陣列的話,你可以通過把它傳遞給 Array 的構建方法來完成 注: 切片只是陣列的另一種表示形式,實際資料還是指向原來的儲存位置,這樣的目的是保持操作的高效,不要每次都複製一次陣列,和寫時複製是同樣的原理

有用的字典方法

字典合併merge(_:uniquingKeysWith:),它接受兩個引數,第一個是要進行合併的鍵值對,第二個是定義如何合併相同鍵的兩個值的函式。我們可以使用這個方法將一個字典合併 至另一個字典中去,如下例所示:

var settings = defaultSettings
let overriddenSettings: [String:Setting] = ["Name": .text("Jane's iPhone")] 
settings.merge(overriddenSettings, uniquingKeysWith: { $1 })
settings
// ["Name": Setting.text("Jane\'s iPhone"), "Airplane Mode": Setting.bool(false)]
複製程式碼

{ $1 } 表示相同key的時候取第二個,也可以自定義邏輯返回

mapValues方法能夠保持字典結構,只對其中的值進行對映

let settingsAsStrings = settings.mapValues { setting -> String in 
  switch setting {
    case .text(let text): return text
    case .int(let number): return String(number)
    case .bool(let value): return String(value)
  } 
}
settingsAsStrings // ["Name": "Jane\'s iPhone", "Airplane Mode": "false"]
複製程式碼

可選值

a = 10 和 a? = 10 的細微不同。前一種寫法無條件地將一個新值賦給變數,而後一種寫 法只在 a 的值在賦值發生前不是 nil 的時候才生效。

var a:Int?=5 
a?=10
a // Optional(10)
var b: Int? = nil
b?=10
b // nil
複製程式碼

多個可選值 let m = i ?? j ?? k ?? 0

可選值map的使用

// before
var firstCharAsString: String? = nil 
if let char = characters.first {
  firstCharAsString = String(char) 
}
// after
let firstChar = characters.first.map { String($0) } // Optional("a")
複製程式碼

可選值flatMap的使用 fatMap 可以把結果展平為單個可選值Int??, 而不是原來的結果Int?? 不僅可以展平陣列,還可以展平可選值

// before
if let a = stringNumbers.first, let b = Int(a) { 
  print(b)
} //1
// after
let y = stringNumbers.first.flatMap { Int($0) } // Optional(1)
複製程式碼

結構體

寫時複製(高效方式) 為了提供高效的寫時複製特性,我們需要知道一個物件是否是 唯一的。如果它是唯一引用,那麼我們就可以直接原地修改物件。否則,我們需要在修改前創 建物件的複製。在 Swift 中,我們可以使用 isKnownUniquelyReferenced 函式來檢查某個引 用只有一個持有者。如果你將一個 Swift 類的例項傳遞給這個函式,並且沒有其他變數強引用 這個物件的話,函式將返回 true。

編碼和解碼

編碼器: 將類轉化成json

解碼器: 將json轉換類

函式

閉包: 一個函式和它所捕獲的變數環境組合起來被稱為閉包。

閉包表示式: 函式可以使用 { } 來宣告為閉包表示式

鍵路徑

屬性相互繫結

extension NSObjectProtocol where Self: NSObject {
    func observe<A, Other>(_ keyPath: KeyPath<Self, A>,
                           writeTo other: Other,
                           _ otherKeyPath: ReferenceWritableKeyPath<Other, A>)
        -> NSKeyValueObservation where A: Equatable, Other: NSObjectProtocol
    {
        return observe(keyPath, options: .new) { _, change in
            guard let newValue = change.newValue, other[keyPath: otherKeyPath] != newValue else {
                return // prevent endless feedback loop
            }
            other[keyPath: otherKeyPath] = newValue }
        }
}

extension NSObjectProtocol where Self: NSObject {
    func bind<A, Other>(_ keyPath: ReferenceWritableKeyPath<Self,A>,
                        to other: Other,
                        _ otherKeyPath: ReferenceWritableKeyPath<Other,A>)
        -> (NSKeyValueObservation, NSKeyValueObservation) where A: Equatable, Other: NSObject
    {
        let one = observe(keyPath, writeTo: other, otherKeyPath)
        let two = other.observe(otherKeyPath, writeTo: self, keyPath)
        return (one,two)
    }
}

final class Sample: NSObject {
  @objc dynamic var name: String = ""
}
class MyObj: NSObject {
  @objc dynamic var test: String = ""
}
let sample = Sample()
let other = MyObj()
let observation = sample.bind(\Sample.name, to: other, \.test) sample.name = "NEW"
other.test // NEW
other.test = "HI"
sample.name // HI
複製程式碼

自動閉包

@escaping: 稍後呼叫的閉包叫做逃逸閉包

@autoclosure: 告訴編譯器它應該將某個引數用閉包表示式包裝起來,不需要將引數封裝到閉包中

if and(!evens.isEmpty, { evens[0] > 10 }) { 
  //執⾏行行操作
}
if and(!evens.isEmpty, evens[0] > 10) { // @autoclosure修飾
  //執⾏行行操作
}
複製程式碼

錯誤處理

rethrows: 告訴編譯器,這個函式只會在它的引數函式丟擲錯誤的時候拋 出錯誤。對那些向函式中傳遞的是不會丟擲錯誤的函式的呼叫,編譯器可以免除我們一定要使用 try 來進行呼叫的要求

extension Sequence {
  func all(matching predicate: (Element) throws -> Bool) rethrows -> Bool {
    for element in self {
      guard try predicate(element) else { return false } 
    }
      return true
  } 
}
複製程式碼

原生並行特性還沒有被新增到Swift

可以使用PromiseKit來暫時代替使用

協議

帶有關聯型別的協議

public protocol IteratorProtocol {
  associatedtype Element
  public mutating func next() -> Element?
}
複製程式碼

相關文章