《Swift 开发者必备 Tips》 阅读笔记(一)

2018-07-24  本文已影响98人  伯wen

本编是Swifter - Swift 开发者必备 Tips 阅读笔记

一、柯里化(Currying), 百度百科

func addOne(num: Int) -> Int {
    return num + 1
}
func addTwo(num: Int) -> Int {
    return num + 2
}

func addThree(num: Int) -> Int {
    return num + 3
}
func addTo(adder: Int, num: Int) -> Int {
    return num + adder
}
func addTo(adder: Int) -> (Int) -> Int {
    func addNum(num: Int) -> Int {
        return num + adder
    }
    return addNum
}
func addTo(adder: Int) -> (Int) -> Int {
    return {
        num in
        return num + adder
    }
}
let addTwo = addTo(2)
print(addTwo(1))          // 打印: 3
print(addTwo(2))          // 打印: 4
print(addTwo(3))          // 打印: 5

let addThree = addTo(3)
print(addThree(1))        // 打印: 4
print(addThree(2))        // 打印: 5
print(addThree(3))        // 打印: 6
柯里化应用实例
struct Control {
    let target: AnyObject
    let action: Selector
    
    func performAction() {
        target.perform(action)
    }
}
class SomeClass: UIView {
    
    var control: Control?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.control = aControl(target: self, action: NSSelectorFromString("say"))
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.control?.performAction()
    }
    
    @objc func say() {
        print("啦啦啦")
    }
    
}
protocol TargetAction {
    func performAction()
}

struct TargetActionWrapper<T: AnyObject>: TargetAction {
    weak var target: T?
    let action: (T) -> () -> ()
    
    func performAction() -> () {
        if let t = target {
            action(t)()
        }
    }
}
enum ControlEvent {
    case touchesBegan
    case touchesEnded
    // ...
}
class Control: UIView {
    var actions = [ControlEvent: TargetAction]()
    
    func setTarget<T: AnyObject>(target: T, action: @escaping (T) -> () -> (), controlEvent: ControlEvent) {
        
        actions[controlEvent] = TargetActionWrapper(target: target, action: action)
    }
    
    func removeTargetForControlEvent(controlEvent: ControlEvent) {
        actions[controlEvent] = nil
    }
    
    func performActionForControlEvent(controlEvent: ControlEvent) {
        actions[controlEvent]?.performAction()
    }
}
class SomeClass: UIView {
    
    var control: Control = Control()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.control.setTarget(target: self, action: SomeClass.touchesBegan, controlEvent: .touchesBegan)
        self.control.setTarget(target: self, action: SomeClass.touchesEnded, controlEvent: .touchesEnded)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.control.performActionForControlEvent(controlEvent: .touchesBegan)
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.control.performActionForControlEvent(controlEvent: .touchesEnded)
    }
    
    func touchesBegan() {
        print("开始点击")
    }
    
    func touchesEnded() {
        print("结束点击")
    }
}

二、将protocol的方法声明为mutating

protocol Vehicle
{
    var numberOfWheels: Int {get}
    var color: UIColor {get set}

    mutating func changeColor()
}

struct MyCar: Vehicle {
    let numberOfWheels = 4
    var color = UIColor.blue

    mutating func changeColor() {
        // 因为 `color` 的类型是 `UIColor`,这里直接写 .red 就足以推断类型了
        color = .red
    }
}

三、Sequence

1、迭代器, 百度百科
public protocol IteratorProtocol {

    associatedtype Element

    // 返回下一个元素, 如果没有返回 nil
    // 通过反复调用, 可以获取所有的元素, 一旦元素的序列已经耗尽, 所有后续的调用返回 nil
    public mutating func next() -> Self.Element?
}
let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
var animalIterator = animals.makeIterator()

while let animal = animalIterator.next() {
    print(animal)
}
// 打印结果:
Antelope
Butterfly
Camel
Dolphin
print(animalIterator.next())
// 打印结果: nil
struct CustomIterator<T>: IteratorProtocol {
    
    typealias Element = T
    
    var array: [Element]
    
    var currentIndex = 0
    
    init(_ array: [Element]) {
        self.array = array
    }
    
    mutating func next() -> Element? {
        if currentIndex < array.count {
            let int = array[currentIndex]
            currentIndex += 1
            return int
        }else {
            return nil;
        }
    }
}
let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
var custom = CustomIterator(animals)
while let animal = custom.next() {
    print(animal)
}

// 打印:
Antelope
Butterfly
Camel
Dolphin
print(custom.next())
// 返回: nil
struct CustomReverseIterator<T>: IteratorProtocol {
    
    typealias Element = T
    
    var array: [Element]
    
    var currentIndex: Int
    
    init(_ array: [Element]) {
        self.array = array
        currentIndex = array.count - 1
    }
    
    mutating func next() -> Element? {
        guard currentIndex >= 0 else {
            return nil
        }
        let int = array[currentIndex]
        currentIndex -= 1
        return int
    }
}
2、Sequence
public protocol Sequence {
    // 关联类型, 必须遵守了IteratorProtocol协议
    associatedtype Iterator : IteratorProtocol
    // 获取一个迭代器
    public func makeIterator() -> Self.Iterator
}
struct CustomReverseSequence<T>: Sequence {
    
    var array: [T]
    
    init(_ array: [T]) {
        self.array = array
    }
    
    typealias intrator = CustomReverseIterator<T>
    
    func makeIterator() -> intrator {
        return CustomReverseIterator(self.array)
    }
}
let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
let sequence = CustomReverseSequence(animals)
for animal in sequence {
    print(animal)
}
// 打印:
Dolphin
Camel
Butterfly
Antelope
var iterator = sequence.makeIterator()
while let animal = iterator.next() {
    print(animal)
}
let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
let sequence = CustomReverseSequence(animals)
let newSequence = sequence.map {
    return $0 + "123"
}
print(newSequence)
// 打印: ["Dolphin123", "Camel123", "Butterfly123", "Antelope123"]

四、多元组(Tuple)

/*
CGRectDivide(CGRect rect, CGRect *slice, CGRect *remainder, 
                             CGFloat amount, CGRectEdge edge)
*/
CGRect rect = CGRectMake(0, 0, 100, 100);
CGRect small;
CGRect large;
CGRectDivide(rect, &small, &large, 20, CGRectMinXEdge);
extension CGRect {
    //...
    func divided(atDistance: CGFloat, from fromEdge: CGRectEdge) 
                    -> (slice: CGRect, remainder: CGRect)
    //...
}
let rect = CGRect(x: 0, y: 0, width: 100, height: 100)
let (small, large) = rect.divided(atDistance: 20, from: .minXEdge)
func swapMe1<T>( a: inout T, b: inout T) {
    let temp = a
    a = b
    b = temp
}
func swapMe2<T>(a: inout T, b: inout T) {
    (a, b) = (b, a)
}

五、@autoclosure 和 ??

1、自动闭包 @autoclosure
func logIfTrue(_ predicate: () -> Bool) {
    if predicate() {
        print("true")
    }
}
logIfTrue { () -> Bool in
    return 2 > 1
}
logIfTrue {2 > 1}
func logIfTrue(_ predicate: @autoclosure () -> Bool) {
    if predicate() {
        print("true")
    }
}
logIfTrue (2 > 1)
2、??
var a: Int?
var b = 10
var c = a ?? b
func ??<T>(optional: T?, defaultValue: @autoclosure () -> T?) -> T?

func ??<T>(optional: T?, defaultValue: @autoclosure () -> T) -> T
func ??<T>(optional: T?, defaultValue: @autoclosure () -> T) -> T {
    switch optional {
    case .some(let value):
        return value
    case .none:
        return defaultValue()
    }
}

@autoclosure并不支持带有输入参数的写法, 也就是说只有形如() -> T的参数才能使用这个特性简化

六、@escaping

func doWork(block: () -> ()) {
    block()
}
doWork {
    print("work")
}
func doWorkAsync(block: @escaping: () -> ()) {
    DispatchQueue.main.async {
        block()
    }
}
class S {
    var foo = "foo"

    func method1() {
        doWork {
            print(foo)
        }
        foo = "bar"
    }

    func method2() {
        doWorkAsync {
            print(self.foo)
        }
        foo = "bar"
    }
}

S().method1() // foo
S().method2() // bar
func method3() {
    doWorkAsync {
        [weak self] in
        print(self?.foo ?? "nil")
    }
    foo = "bar"
}

S().method3() // nil

如果你在协议或者父类中定义了一个接受@escaping为参数的方法, 那么在实际协议和类型或者是这个父类的子类时, 对应的方法也必须被声明为@escaping, 否则两个方法会被认为拥有不同的函数签名

protocol P {
    func work(b: @escaping ()->())
}

// 可以编译
class C: P {
    func work(b: @escaping () -> ()) {
        DispatchQueue.main.async {
           print("in C")
           b()
        }
    }
}

// 而这样是无法编译通过的:
class C1: P {
    func work(b: () -> ()) {
        // ...
    }
}

七、Optional Chaining

class Toy {
    let name: String
    init(name: String) {
        self.name = name
    }
}

class Pet {
    var toy: Toy?
}

class Child {
    var pet: Pet?
}
let xiaoming = Child()
let toyName = xiaoming.pet?.toy?.name
if let toyName = xiaoming.pet?.toy?.name {
    // 小明有宠物, 并且宠物拥有玩具
}
extension Toy {
    func play() {
        // 宠物玩玩具
    }
}
xiaoming.pet?.toy?.play()
if let result: () = xiaoming.pet?.toy?.play() {
    // 玩玩具
}else{
    // 没有玩具可以玩
}
if let result: () = xiaohong.pet?.toy?.play() {
    // 玩玩具
}else{
    // 没有玩具可以玩
}

if let result: () = xiaoli.pet?.toy?.play() {
    // 玩玩具
}else{
    // 没有玩具可以玩
}

这是错误的代码

let playClosure = { (child: Child) -> () in
    child.pet?.toy?.play()
}
let playClosure = { (child: Child) -> () in
    child.pet?.toy?.play()
   return ()
}
let playClosure = { (child: Child) -> ()? in
    child.pet?.toy?.play()
}
let playClosure = { (child: Child) -> ()? in
    return child.pet?.toy?.play()
}
if let toyName = playClosure(xiaoming) {
    print("玩玩具~")
}else {
    print("没有玩具玩~")
}

if let toyName = playClosure(xiaohong) {
    print("玩玩具~")
}else {
    print("没有玩具玩~")
}

if let toyName = playClosure(xiaoli) {
    print("玩玩具~")
}else {
    print("没有玩具玩~")
}

八、操作符

struct Vector2D {
    var x = 0.0
    var y = 0.0
}
let v1 = Vector2D(x: 1, y: 2)
let v2 = Vector2D(x: 3, y: 4)
let v3 = Vector2D(x: v1.x + v2.x, y: v1.y + v2.y)
// v3为 Vector2D(x: 4.0, y: 6.0)
func + (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
let v4 = v1 + v2
// v4为 Vector2D(x: 4.0, y: 6.0)
// - 减号
func - (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x - right.x, y: left.y - right.y)
}

// - 负号
prefix func - (vector: Vector2D) -> Vector2D {
    return Vector2D(x: -vector.x, y: -vector.y)
}
let v5 = v1 - v2
print(v5)
// v5 为 Vector2D(x: -2.0, y: -2.0)

let v6 = -v1
print(v6)
// v6 为 Vector2D(x: -1.0, y: -2.0)
func +* (letf: Vector2D, right: Vector2D) -> Double {
    return letf.x * right.x + letf.y * right.y
}

Operator implementation without matching operator declaration

precedencegroup DotProductPrecedence {
    associativity: none
    higherThan: MultiplicationPrecedence
}

infix operator +*: DotProductPrecedence

precedencegroup

定义一个操作符优先级别。操作符优先级的定义和类型声明有些类似, 一个操作符需要属于某个特定的优先级。Swift标准库中已经定义了一些常用的运算优先级组, 比如加法优先级组(AdditionPrecedence)和乘法优先级组(MultiplicationPrecedence)等。如果没有合适你的运算符的优先级组, 你就需要向我们在例子中做的这样, 自己指定结合律方式和优先级顺序了

associativity

定义了结合律, 即多个同类的操作符顺序出现时的计算顺序。比较常见的加法和减法都是left, 就是说多个加法同时出现时按照从左往右的顺序计算。
点乘的结果是一个Double, 不会再和其他点乘结合使用, 所以这里是none

higherThan

运算的优先级, 点积运算是优先于乘法运算的。除了higherThan, 也支持使用loverThan来指定优先级低于某个其他组。

infix

表示要定义的是一个中位操作符, 即前后都是输入; 其他的修饰子还包括prefixpostfix

precedencegroup DotProductPrecedence {
    associativity: none
    higherThan: MultiplicationPrecedence
}

infix operator +*: DotProductPrecedence

func +* (letf: Vector2D, right: Vector2D) -> Double {
    return letf.x * right.x + letf.y * right.y
}
let result = 3 * 5 + v1 +* v2
print(result)
// 打印: 26.0

最后需要多提一点的是,Swift 的操作符是不能定义在局部域中的,因为至少会希望在能在全局范围使用你的操作符,否则操作符也就失去意义了。另外,来自不同 module 的操作符是有可能冲突的,这对于库开发者来说是需要特别注意的地方。如果库中的操作符冲突的话,使用者是无法像解决类型名冲突那样通过指定库名字来进行调用的。因此在重载或者自定义操作符时,应当尽量将其作为其他某个方法的 "简便写法",而避免在其中实现大量逻辑或者提供独一无二的功能。这样即使出现了冲突,使用者也还可以通过方法名调用的方式使用你的库。运算符的命名也应当尽量明了,避免歧义和可能的误解。因为一个不被公认的操作符是存在冲突风险和理解难度的,所以我们不应该滥用这个特性。在使用重载或者自定义操作符时,请先再三权衡斟酌,你或者你的用户是否真的需要这个操作符。

九、func的参数修饰

func incrementor(variable: Int) -> Int {
    return variable + 1
}

这是错误的代码

func incrementor(variable: Int) -> Int {
   variable += 1
   print(variable)
   return variable
}
func incrementor2(variable: Int) -> Int {
    var num = variable
    num += 1
    return num
}
func incrementor(variable: inout Int) {
    variable += 1
}
var luckyNumber = 7
incrementor(variable: &luckyNumber)

print(luckyNumber)
// luckyNumber = 8
func makeIncrementor(addNumber: Int) -> ((inout Int) -> ()) {
    func incrementor(variable: inout Int) -> () {
        variable += addNumber;
    }
    return incrementor;
}

十、字面量表达

1、字面量
let aNumber = 3
let aString = "hello world"
let aBool = true
let anArray = [1, 2, 3]
let aDictionary = ["key1" : "value1", "key2" : "vakue2"]

2、使用字面量创建指定类型

ExpressibleByArrayLiteral
ExpressibleByBooleanLiteral
ExpressibleByDictionaryLiteral
ExpressibleByFloatLiteral
ExpressibleByNilLiteral
ExpressibleByIntegerLiteral
ExpressibleByStringLiteral
public protocol ExpressibleByBooleanLiteral {

    associatedtype BooleanLiteralType : _ExpressibleByBuiltinBooleanLiteral

    public init(booleanLiteral value: Self.BooleanLiteralType)
}
/// The default type for an otherwise-unconstrained boolean literal
typealias BooleanLiteralType = Bool
extension Int: ExpressibleByBooleanLiteral {
    public typealias BooleanLiteralType = Bool
    
    public init(booleanLiteral value: Int.BooleanLiteralType) {
        self = value ? 1 : 0
    }
}
let num1: Int = true
let num2: Int = false
print(num1, num2)        // 打印: 1 0
3、ExpressibleByStringLiteral
ExpressibleByExtendedGraphemeClusterLiteral
ExpressibleByUnicodeScalarLiteral
class Person {
    let name: String
    init(name value: String) {
        self.name = value
    }
}
class Person: ExpressibleByStringLiteral {
    let name: String
    init(name value: String) {
        self.name = value
    }

    required init(stringLiteral value: String) {
        self.name = value
    }

    required init(extendedGraphemeClusterLiteral value: String) {
        self.name = value
    }

    required init(unicodeScalarLiteral value: String) {
        self.name = value
    }
}

注意: 如果是结构体和枚举, 就不需要加required, 这是因为值类型无法被继承, 就不会有子类

class Person: ExpressibleByStringLiteral {
    let name: String
    init(name value: String) {
        self.name = value
    }

    required convenience init(stringLiteral value: String) {
        self.init(name: value)
    }

    required convenience init(extendedGraphemeClusterLiteral value: String) {
        self.init(name: value)
    }

    required convenience init(unicodeScalarLiteral value: String) {
        self.init(name: value)
    }
}

let p: Person = "xiaoMing"
print(p.name)

// 输出:
// xiaoMing
总结一下,字面量表达是一个很强大的特性,使用得当的话对缩短代码和清晰表意都很有帮助;但是这同时又是一个比较隐蔽的特性:因为你的代码并没有显式的赋值或者初始化,所以可能会给人造成迷惑:比如上面例子中为什么一个字符串能被赋值为 Person?你的同事在阅读代码的时候可能不得不去寻找这些负责字面量表达的代码进行查看 (而如果代码库很大的话,这不是一件容易的事情,因为你没有办法对字面量赋值进行 Cmd + 单击跳转)。

来自: 王巍 (onevcat). “Swifter - Swift 必备 Tips (第四版)。”

上一篇下一篇

猜你喜欢

热点阅读