Log 输出

    func printLog<T>(_ message: T,
                  file: String = #file,
                  method: String = #function,
                  line: Int = #line) {
        #if DEBUG
            print("\((file as NSString).lastPathComponent)[\(line)],\(method): \(message)")
        #endif
    }

属性访问控制

属性访问控制 privatefilePrivateinternalpublicopen

  1. internal 是 swift 默认的控制级

  2. private 让代码只能在当前作用域内被使用,filePrivate 表示只能在当前文件中被访问。

  3. 同一 module/target 中访问,保持默认的 internal 就行

  4. target外只能调用 publicopen 的代码。区别在于只有标记为 open的内容才能被别的框架继承或者重写。

  5. set 方法设置访问权限 private, get 方法默认interval

class MyClass {

private(set) var name: String?

}
  1. 如果我们希望在别的 module 中也能访问这个属性,同时又保持只在当前作用域可以设置的话,我们需要将 get 的访问权限提高为 public
public class MyClass {

public private(set) var name: String?

}

Swift 中的测试

由于 测试的 targetapp的 target是不同的,因此在测试中导入 app 的 module 后我们是访问不到那些默认 `internal` 的待测试方法的。而在 Swift 2.0 中, Apple 为 app 的测试开了“后門”, 现在可以通过在测试代码中导入 app 的 target 时,在之前追加 @testable ,就可以访问到 app target 中 internal 的内容。

@testable import MyApp

将 Protocol 的方法声明为 mutating

代码

Swift 的 protocol 不仅可以被class类型实现,也适用于 structenum 。因为这个原因,我们在写给别人用的协议时需要多考虑是否使用 mutating 来修饰方法,比如定义为 mutating func myMethod() 。Swift 的 mutating 关键字修饰方法是为了能在该方法中修改 struct 或是 enum 的变量,所以如果你没在协议方法里写mutating 的话,别人如果用 struct 或是enum 来实现这个协议的话,就不能在方法里改变自己的变量了。

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

    mutating func changeColor()
}


struct MyCar: vehicle {

    let numberOfWheels: Int = 4
    var color: UIColor = UIColor.blue

    mutating func changeColor() {
         color = .red
    }
}

另外,在使用 class来实现带有 mutating 的方法的协议时,具体实现的前面是不需要加 mutating修饰的,因为 class 可以随意更改自己的成员变量。所以说在协议里用 mutating 修饰方法,对于 class 的实现是完全透明,可以当作不存在的。

Sequence

代码

swift 的 for...in 可以用在所有实现了 Sequence 协议的类型上,而为了实现 Sequence 你首先要实现一个 IteratorProtol。比如一个实现了反向的 iteratorSequence 可以这么写:

// 1. 定义一个实现了 IteratorProtocol 协议的类型
// IteratorProtocol 需要制定一个 typealias Element
// 以及提供一个返回 Element? 的方法 next()
class ReverseIterator<T>: IteratorProtocol {

    typealias Element = T

    var array: [Element]
    var currentIndex = 0


    init(array: [Element]) {
        self.array = array
        currentIndex = array.count - 1
    }

    func next() -> Element? {

        if currentIndex < 0 {
            return nil
        }
        else {
            let element = array[currentIndex]
            currentIndex -= 1
            return element
        }
    }
}

// 2. 定义 Sequence
// 和 IteratorProtocol 很类似,不过换成指定一个 typealias Iterator
// 以及提供一个返回 Iterator? 的方法 makeIterator()

struct ReverseSequence<T>: Sequence {
    var array: [T]

    init(array: [T]) {
        self.array = array
    }

    typealias Iterator = ReverseIterator<T>

    func makeIterator() -> ReverseIterator<T> {
        return ReverseIterator(array: array)
    }
}

    let arr = [0, 1, 2, 3]
    //对 sequence 可以使用 for...in 来循环访问
    for i in ReverseSequence(array: arr)
    {
        print("index \(i) is \(arr[i])")
    }

输出结果为

index 3 is 3

index 2 is 2

index 1 is 1

index 0 is 0

如果我们想要深究 for...in 这样的方法到底做了什么的话,如果我们将其展开,大概会是下面这个样子:

    var iterator = arr.makeIterator()
    while let obj = iterator.next() {
        print(obj)
    }

顺便你可以免费得到的收益是你可以使用像 map, reducefilter 这些方法,因为 Sequence 协议扩展 (protocol extension) 已经实现了它们。

results matching ""

    No results matching ""