首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Swift中创建线程安全数组

在Swift中创建线程安全数组
EN

Stack Overflow用户
提问于 2015-01-28 19:26:46
回答 16查看 60.9K关注 0票数 87

我在Swift中遇到线程问题。我有一个数组,里面有一些对象。通过委托,这个类几乎每秒都会获得新的对象。在这之后,我必须检查对象是否已经在数组中,所以我必须更新对象,否则我必须删除/添加新对象。

如果我添加一个新对象,我必须首先通过网络获取一些数据。这是通过积木的handelt。

现在我的问题是,如何同步这些任务?

我已经尝试了一个dispatch_semaphore,但是这个阻塞了UI,直到这个阻塞结束。

我还尝试了一个简单的bool变量,它检查代码块当前是否正在执行,同时跳过compare方法。

但这两种方法都不理想。

管理阵列的最佳方法是什么,我不希望阵列中有重复的数据。

EN

回答 16

Stack Overflow用户

发布于 2015-03-11 08:42:31

Swift的更新

推荐的线程安全访问模式是使用分派barrier

代码语言:javascript
运行
复制
let queue = DispatchQueue(label: "thread-safe-obj", attributes: .concurrent)

// write
queue.async(flags: .barrier) {
    // perform writes on data
}

// read
var value: ValueType!
queue.sync {
    // perform read and assign value
}
return value
票数 105
EN

Stack Overflow用户

发布于 2016-10-14 22:17:52

Kirsteins的答案是正确的,但为了方便起见,我用Amol Chaudhari和Rob的建议更新了这个答案,他们建议使用带有异步屏障的并发队列,以允许并发读取但阻止写入。

我还包装了一些对我有用的其他数组函数。

代码语言:javascript
运行
复制
public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = dispatch_queue_create("SynchronizedArrayAccess", DISPATCH_QUEUE_CONCURRENT)

public func append(newElement: T) {
    dispatch_barrier_async(self.accessQueue) {
        self.array.append(newElement)
    }
}

public func removeAtIndex(index: Int) {
    dispatch_barrier_async(self.accessQueue) {
        self.array.removeAtIndex(index)
    }
}

public var count: Int {
    var count = 0

    dispatch_sync(self.accessQueue) {
        count = self.array.count
    }

    return count
}

public func first() -> T? {
    var element: T?

    dispatch_sync(self.accessQueue) {
        if !self.array.isEmpty {
            element = self.array[0]
        }
    }

    return element
}

public subscript(index: Int) -> T {
    set {
        dispatch_barrier_async(self.accessQueue) {
            self.array[index] = newValue
        }
    }
    get {
        var element: T!

        dispatch_sync(self.accessQueue) {
            element = self.array[index]
        }

        return element
    }
}
}

更新这是相同的代码,针对Swift3进行了更新。

代码语言:javascript
运行
复制
public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = DispatchQueue(label: "SynchronizedArrayAccess", attributes: .concurrent)

public func append(newElement: T) {

    self.accessQueue.async(flags:.barrier) {
        self.array.append(newElement)
    }
}

public func removeAtIndex(index: Int) {

    self.accessQueue.async(flags:.barrier) {
        self.array.remove(at: index)
    }
}

public var count: Int {
    var count = 0

    self.accessQueue.sync {
        count = self.array.count
    }

    return count
}

public func first() -> T? {
    var element: T?

    self.accessQueue.sync {
        if !self.array.isEmpty {
            element = self.array[0]
        }
    }

    return element
}

public subscript(index: Int) -> T {
    set {
        self.accessQueue.async(flags:.barrier) {
            self.array[index] = newValue
        }
    }
    get {
        var element: T!
        self.accessQueue.sync {
            element = self.array[index]
        }

        return element
    }
}
}
票数 38
EN

Stack Overflow用户

发布于 2020-06-28 16:42:14

我不明白为什么人们对如此简单的事情采取如此复杂的方法

  • 不要滥用DispatchQueues进行锁定。使用queue.sync只不过是获取一个锁,并在锁(DispatchGroup)等待时将工作分派给另一个线程。它不仅是不必要的,而且可能会有副作用,这取决于您要锁定的内容。您可以自己在GCD Source

中查找它

  • 不要使用objc_sync_enter/exit,这些是由ObjCs @synchronized使用的,它将隐式地将Swift集合连接到ObjC副本,这也是不必要的。而且它是一个遗留的API。

只需定义一个锁,并保护您的集合访问。

代码语言:javascript
运行
复制
var lock = DispatchSemaphore(value: 1)
var a = [1, 2, 3]

lock.wait()
a.append(4)
lock.signal()

如果你想让你的生活更轻松一点,定义一个小的扩展。

代码语言:javascript
运行
复制
extension DispatchSemaphore {

    @discardableResult
    func with<T>(_ block: () throws -> T) rethrows -> T {
        wait()
        defer { signal() }
        return try block()
    }
}

let lock = DispatchSemaphore(value: 1)
var a = [1, 2, 3]

lock.with { a.append(4) }

您还可以定义一个@propertyWrapper,使您的成员var成为原子。

代码语言:javascript
运行
复制
@propertyWrapper
struct Atomic<Value> {

    private let lock = DispatchSemaphore(value: 1)
    private var value: Value

    init(default: Value) {
        self.value = `default`
    }

    var wrappedValue: Value {
        get {
            lock.wait()
            defer { lock.signal() }
            return value
        }
        set {
            lock.wait()
            value = newValue
            lock.signal()
        }
    }
}

最后但并非最不重要的是,对于原始原子类型,还有

票数 37
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28191079

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档