问题
public class Account {
// MARK: Initializer
// Custom initializer
// MARK: Stored Properties
let concurrentQueue: DispatchQueue = DispatchQueue(
label: "concurrentQueue",
qos: DispatchQoS.userInitiated,
attributes: [DispatchQueue.Attributes.concurrent]
)
private var _name: String
public name: String {
get {
return self.concurrentQueue.sync { return self._name }
}
set {
self.concurrentQueue.async(flags: .barrier) {
self._name = newValue
}
}
}
}
Let's say you have a class like above where you want thread safety.
What is the difference between the getter in the Account
class and defining the getter like this?
get {
var result: String!
self.concurrentQueue.sync { result = self._name }
return result
}
I'm currently wrapping my head around thread safety and I always see reads created like the latter. It seems to me they're virtually the same... am I wrong?
Source: GCD Tutorial
回答1:
There is no difference. There are two DispatchQueue.sync
methods:
public func sync(execute block: () -> Swift.Void)
public func sync<T>(execute work: () throws -> T) rethrows -> T
and in your first example the second one is used: The closure can return a value, which then becomes the return
value of the sync
call. Therefore in
get {
return self.concurrentQueue.sync { return self._name }
}
the return value of sync { ... }
is self._name
and that is returned
from the getter method. This is equivalent to (but simpler than) storing the
value in a temporary variable (and here the closure returns Void
):
get {
var result: String!
self.concurrentQueue.sync { result = self._name }
return result
}
Of course that works only with synchronously dispatched closures,
not with asynchronous calls. These are stored for later execution and must
return Void
:
public func async(..., execute work: @escaping @convention(block) () -> Swift.Void)
来源:https://stackoverflow.com/questions/45569118/when-creating-thread-safe-reads-in-swift-why-is-a-variable-create-outside-the-c