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


当前回答

在2018年WWDC的“理解崩溃和崩溃日志”会议414中,他们展示了以下使用DispatchQueues与sync的方法。

在swift 4中应该像下面这样:

class ImageCache {
    private let queue = DispatchQueue(label: "sync queue")
    private var storage: [String: UIImage] = [:]
    public subscript(key: String) -> UIImage? {
        get {
          return queue.sync {
            return storage[key]
          }
        }
        set {
          queue.sync {
            storage[key] = newValue
          }
        }
    }
}

无论如何,您也可以使用带屏障的并发队列使读取更快。同步和异步读取同时执行,写入新值等待前一个操作完成。

class ImageCache {
    private let queue = DispatchQueue(label: "with barriers", attributes: .concurrent)
    private var storage: [String: UIImage] = [:]

    func get(_ key: String) -> UIImage? {
        return queue.sync { [weak self] in
            guard let self = self else { return nil }
            return self.storage[key]
        }
    }

    func set(_ image: UIImage, for key: String) {
        queue.async(flags: .barrier) { [weak self] in
            guard let self = self else { return }
            self.storage[key] = image
        }
    }
}

其他回答

图我将发布我的Swift 5实现,建立在前面的答案。谢谢你们了!我发现有一个返回值的方法也很有用,所以我有两个方法。

这是一个简单的类首先创建:

import Foundation
class Sync {
public class func synced(_ lock: Any, closure: () -> ()) {
        objc_sync_enter(lock)
        defer { objc_sync_exit(lock) }
        closure()
    }
    public class func syncedReturn(_ lock: Any, closure: () -> (Any?)) -> Any? {
        objc_sync_enter(lock)
        defer { objc_sync_exit(lock) }
        return closure()
    }
}

如果需要返回值,就像这样使用它:

return Sync.syncedReturn(self, closure: {
    // some code here
    return "hello world"
})

Or:

Sync.synced(self, closure: {
    // do some work synchronously
})

斯威夫特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 }
        }
    }
} 

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

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

类似于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](我喜欢延迟)的答案。

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

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

    try block()
}