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
}
属性访问控制
属性访问控制 private,filePrivate, internal,public 和 open。
internal是 swift 默认的控制级private让代码只能在当前作用域内被使用,filePrivate表示只能在当前文件中被访问。同一
module/target中访问,保持默认的internal就行target外只能调用public和open的代码。区别在于只有标记为open的内容才能被别的框架继承或者重写。为
set方法设置访问权限private, get 方法默认interval
class MyClass {
private(set) var name: String?
}
- 如果我们希望在别的
module中也能访问这个属性,同时又保持只在当前作用域可以设置的话,我们需要将get的访问权限提高为public。
public class MyClass {
public private(set) var name: String?
}
Swift 中的测试
由于 测试的 target 和 app的 target是不同的,因此在测试中导入 app 的 module 后我们是访问不到那些默认 `internal` 的待测试方法的。而在 Swift 2.0 中, Apple 为 app 的测试开了“后門”, 现在可以通过在测试代码中导入 app 的 target 时,在之前追加 @testable ,就可以访问到 app target 中 internal 的内容。
@testable import MyApp
将 Protocol 的方法声明为 mutating
Swift 的 protocol 不仅可以被class类型实现,也适用于 struct和 enum 。因为这个原因,我们在写给别人用的协议时需要多考虑是否使用 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。比如一个实现了反向的 iterator 和 Sequence 可以这么写:
// 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, reduce 和 filter 这些方法,因为 Sequence 协议扩展 (protocol extension) 已经实现了它们。