Home Swift Tips (2) - Standards
Post
Cancel

Swift Tips (2) - Standards

方法参数命名规范

由于Objective-C API的命名转换,到Swift API的更新,现在(Swift 4.0)我们更应该使用靠近Swift系统的命名方式:

1
func convert(_ point: CGPoint, from view: UIView?) -> CGPoint

不符合规范的:func convertPoint(_ point: CGPoint, fromView view: UIView?) -> CGPoint

类的初始化

类的初始化方法分为三种,DESIGNATED,CONVENIENCE 和 REQUIRED。对于初始化方法,必须遵循:

  1. 初始化路径必须保证对象完全初始化,这可以通过调用本类型的 designated 初始化方法来得到保证;
  2. 子类的 designated 初始化方法必须调用父类的 designated 方法,以保证父类也完成初始化。

convenience 方法是 Swift 初始化方法中的 “二等公民”,只作为补充和提供使用上的方便。所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置,另外 convenience 的初始化方法是不能被子类重写或者是从子类中以 super 的方式被调用的。

对于某些我们希望子类中一定实现的 designated 初始化方法,我们可以通过添加 required 关键字进行限制,强制子类对这个方法重写实现。这样做的最大的好处是可以保证依赖于某个 designated 初始化方法的 convenience 一直可以被使用。

属性访问控制

现在的 Swift 版本(4.1),private关键字的访问权限已经改为:当前模组下的私有属性。

Swift 5.x, private 已经修改为当前 class or struct/enum… 且在当前文件下才能访问到的私有属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Module: libSome
class User {
	private var id: String
}

extension User {
	func foo() {
		print(id) // accessible
	}
}

// Other app or lib:
@import libSome

extension User {
	func bar() {
		print(id) // value of type 'User' has no member 'id'
	}
}

其他关键字还有publicinternalfileprivate,含义为公开内部文件私有,默认使用的是internal,严格的使用访问控制,可以优化代码和模组的使用,也会减少许多不必要的麻烦。

另外对于 Swift 中的只读属性也是通过访问控制完成的:

1
2
3
4
class User {
	private(set) var id: String  	     
	fileprivate(set) var local: String
}

嵌套 enum

在 enum 里编译器是不允许直接嵌套使用的,我们可以添加 indirect 使编译器通过编译。

1
2
3
4
5
6
indirect enum Node<Value> {
	case empty
	case value(value: Value, left: Node<Value>, right: Node<Value>)
}

let leaf = Node.value(value: 1, left: .empty, right: .empty)

Lock

Objective-C 中的@synchronized其实是使用了互斥锁objc_sync中的objc_sync_enterobcj_sync_exit方法。在 Swift 中我们可以仿写一下:

1
2
3
4
5
6
7
8
9
10
11
12
func synchronized(_ obj: AnyObject, closure: () -> Void) {
	objc_sync_enter(obj)
    closure()
    objc_sync_exit(obj)
}

func foo() {
	...
	synchronized(anObj) {
		...
	}
}

这样就可以简单的给一个对象加锁了。

自旋锁 OSSpinLock 作为一个高性能的自旋锁,以前被基础框架广泛使用,但是后来苹果工程师证实一些线程优先级调度算法,会造成优先级翻转问题,造成自旋锁被破坏。作为高性能锁的替换,一些大公司的框架会使用 dispatch_semaphore 、 pthread_mutex 、 NSLock。

  • dispatch_semaphore

    GCD 中的信号量,用法简单,在调用wait()时如果信号量为负则会阻断当前线程,实现不同线程的互斥。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let semaphore = DispatchSemaphore(value: 0)
func foo() {
	dispatch_global_async(.default) {
		sleep(10)
		semaphore.signal()
	}
	semaphore.wait()
	...
}

// or
func bar() {
	semaphore.wait(); defer { semaphore.signal() }
	... // 方法内是单线程加锁访问的
}

  • pthread_mutex 互斥锁

    pthread_mutex 是 Linux 和 Mac 系统常用的互斥锁,使用方法与普通互斥锁一样,而已实现线程同步。具体的使用教程可参考 Google。

  • NSLock

    NSLock 其实是对 pthread_mutex 的一层封装。

This post is licensed under CC BY 4.0 by the author.