我在Swift中遇到线程问题。我有一个数组,里面有一些对象。通过委托,这个类几乎每秒都会获得新的对象。在这之后,我必须检查对象是否已经在数组中,所以我必须更新对象,否则我必须删除/添加新对象。
如果我添加一个新对象,我必须首先通过网络获取一些数据。这是通过积木的handelt。
现在我的问题是,如何同步这些任务?
我已经尝试了一个dispatch_semaphore,但是这个阻塞了UI,直到这个阻塞结束。
我还尝试了一个简单的bool变量,它检查代码块当前是否正在执行,同时跳过compare方法。
但这两种方法都不理想。
管理阵列的最佳方法是什么,我不希望阵列中有重复的数据。
发布于 2015-03-11 08:42:31
Swift的更新
推荐的线程安全访问模式是使用分派barrier
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发布于 2016-10-14 22:17:52
Kirsteins的答案是正确的,但为了方便起见,我用Amol Chaudhari和Rob的建议更新了这个答案,他们建议使用带有异步屏障的并发队列,以允许并发读取但阻止写入。
我还包装了一些对我有用的其他数组函数。
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进行了更新。
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
}
}
}发布于 2020-06-28 16:42:14
我不明白为什么人们对如此简单的事情采取如此复杂的方法
DispatchQueues进行锁定。使用queue.sync只不过是获取一个锁,并在锁(DispatchGroup)等待时将工作分派给另一个线程。它不仅是不必要的,而且可能会有副作用,这取决于您要锁定的内容。您可以自己在GCD Source中查找它
objc_sync_enter/exit,这些是由ObjCs @synchronized使用的,它将隐式地将Swift集合连接到ObjC副本,这也是不必要的。而且它是一个遗留的API。只需定义一个锁,并保护您的集合访问。
var lock = DispatchSemaphore(value: 1)
var a = [1, 2, 3]
lock.wait()
a.append(4)
lock.signal()如果你想让你的生活更轻松一点,定义一个小的扩展。
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成为原子。
@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()
}
}
}最后但并非最不重要的是,对于原始原子类型,还有
https://stackoverflow.com/questions/28191079
复制相似问题