Cocoa和Objective-C 中加鎖的方式有很多,但是在日常開發(fā)中最常用的應(yīng)該是@synchronized,這個(gè)關(guān)鍵字可以用來修飾一個(gè)變量,并為其自動加上和解除互斥鎖。這樣,可以保證變量在作用范圍內(nèi)不會被其他線程改變
@synchronized(self) {
//給 self 加鎖
}
雖然這個(gè)方法很簡單好用,但是很不幸的是在Swift 中它已經(jīng)不存在了
那么在swift 中想要用這樣的方式加鎖,改怎么辦呢?
其實(shí)@synchronized 在幕后做的事情是調(diào)用了objc_sync 中的objc_sync_enter 和objc_sync_exit 方法,并且加入了一些異常判斷。因此,在Swift 中,如果我們忽略掉那些異常的話,我們想要lock 一個(gè)變量的話,可以這樣寫:
public func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
return try body()
}
調(diào)用的時(shí)候這樣調(diào)用就可以了:
synchronized(self) {
//... 代碼
}
給對象加鎖
public class Synchronized<T> {
/// Private value. Use `public` `value` computed property (or `reader` and `writer` methods)
/// for safe, thread-safe access to this underlying value.
private var _value: T
/// Private reader-write synchronization queue
private var queue: DispatchQueue
/// Create `Synchronized` object
///
/// - Parameter value: The initial value to be synchronized.
/// queueName: The initial queueName
public init(_ value: T, queueName: String = "synchronized") {
_value = value
queue = DispatchQueue(label: Bundle.main.bundleIdentifier ?? "com.Synchronized" + "." + queueName, qos: .default, attributes: .concurrent)
}
/// A threadsafe variable to set and get the underlying object
public var value: T {
get { return queue.sync { _value } }
set { queue.async(flags: .barrier) { self._value = newValue } }
}
/// A "reader" method to allow thread-safe, read-only concurrent access to the underlying object.
///
/// - Warning: If the underlying object is a reference type, you are responsible for making sure you
/// do not mutating anything. If you stick with value types (`struct` or primitive types),
/// this will be enforced for you.
public func reader<U>(_ block: (T) throws -> U) rethrows -> U {
return try queue.sync { try block(_value) }
}
/// A "writer" method to allow thread-safe write with barrier to the underlying object
public func writer(_ block: @escaping (inout T) -> Void) {
queue.async(flags: .barrier) {
block(&self._value)
}
}
}