设计原则
不允许忽略错误的设计原则
不断的将模板代码和功能代码分离,实现高可重用性
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?
}
复制代码