我已经搜索了Swift的书籍,但找不到@synchronized的Swift版本。我如何做互斥在Swift?


当前回答

您可以创建propertyWrapper synchronized

这里是NSLock下罩的例子。你可以使用任何你想要的同步GCD, posix_locks等

@propertyWrapper public struct Synchronised<T> {
    private let lock = NSLock()

    private var _wrappedValue: T
    public var wrappedValue: T {
        get {
            lock.lock()
            defer {
                lock.unlock()
            }
            return _wrappedValue
        }
        set {
            lock.lock()
            defer {
                lock.unlock()
            }
            _wrappedValue = newValue
        }
    }

    public init(wrappedValue: T) {
        self._wrappedValue = wrappedValue
    }
}

@Synchronised var example: String = "testing"

基于@drewster的答案

其他回答

使用Bryan McLemore的答案,我扩展了它,以支持使用Swift 2.0延迟能力扔进安全庄园的对象。

func synchronized( lock:AnyObject, block:() throws -> Void ) rethrows
{
    objc_sync_enter(lock)
    defer {
        objc_sync_exit(lock)
    }

    try block()
}

斯威夫特4

在Swift 4中,你可以使用gcd调度队列来锁定资源。

class MyObject {
    private var internalState: Int = 0
    private let internalQueue: DispatchQueue = DispatchQueue(label:"LockingQueue") // Serial by default

    var state: Int {
        get {
            return internalQueue.sync { internalState }
        }

        set (newState) {
            internalQueue.sync { internalState = newState }
        }
    }
} 

在Swift4中使用NSLock:

let lock = NSLock()
lock.lock()
if isRunning == true {
        print("Service IS running ==> please wait")
        return
} else {
    print("Service not running")
}
isRunning = true
lock.unlock()

警告 NSLock类使用POSIX线程来实现它的锁定行为。当向NSLock对象发送解锁消息时,必须确保该消息是从发送初始锁定消息的同一个线程发送的。从不同的线程解锁锁可能会导致未定义的行为。

类似于Objective-C中的@synchronized指令,在Swift中可以有任意的返回类型和漂亮的重抛出行为。

// Swift 3
func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return try body()
}

使用defer语句可以直接返回一个值,而不需要引入临时变量。


在Swift 2中,为闭包添加@noescape属性可以进行更多的优化:

// Swift 2
func synchronized<T>(lock: AnyObject, @noescape _ body: () throws -> T) rethrows -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return try body()
}

基于GNewc[1](我喜欢任意返回类型)和Tod Cunningham[2](我喜欢延迟)的答案。

Dispatch_barrier_async是更好的方法,同时不会阻塞当前线程。

dispatch_barrier_async (accessQueue, { 字典对象。ID = object })