設計原則
不允許忽略錯誤的設計原則
不斷的將模板程式碼和功能程式碼分離,實現高可重用性
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?
}
複製程式碼