Swift: Thread-safe dictionary access via cocoa-bindings

947 Views Asked by At

I have a class and I need to bind a few NSTextFields to some values of a dictionary that will be changed by a thread.

class Test: NSObject {
  @objc dynamic var dict : [String:Int] = [:]

  let queue = DispatchQueue(label: "myQueue", attributes: .concurrent)

  func changeValue() {
    queue.async(flags: .barrier) {
        self.dict["Key1"] = Int.random(in: 1..<100)
    }
  }

    func readValue() -> Int? {
        queue.sync {
            return self.dict["Key1"]
        }
    }

}

As far as I understood this is the way to do (so not accessing the variable directly but through a func that handles the queue.

But what when I try to bind a NSTextField to "Key1" of the dict using cocoa bindings? Binding to the variable "dict" directly works in my tests but I'm not sure (I'm quite sure it isn't) if this is thread safe. What would be the correct way to do this?

Edit: This code example looks legit but fails for some reason

class Test: NSObject {

    var _dict : [String:Int] = ["Key1":1]
    let queue = DispatchQueue(label: "myQueue", attributes: .concurrent)

    @objc dynamic var dict:[String:Int] {
        get {
            queue.sync { return self._dict }
        }
        set {
            queue.async(flags: .barrier) { self._dict = newValue }
        }
    }

    func changeValue() {
        queue.async(flags: .barrier) {
            // This change will not be visible in the bound object
            self._dict["Key1"] = Int.random(in: 1..<100)
            // This causes a crash
            self.dict = ["Key1":2]
        }
    }

}
0

There are 0 best solutions below