Search code examples
swiftmacosconcurrencynsviewnsoperationqueue

Drawing in NSView from background operation has no effect


I'm trying to draw to a NSView from a background operation, but don't see any effect.

let queue = OperationQueue()
queue.addOperation() {
  doTheBackgroundStuff()
}

starts the background operation, which is doing lots of calculations. In the AppDelegate I have

@IBOutlet weak var image: NSImageView!  // some image to show
@IBOutlet weak var number: NSTextField! // a corresponding number
@IBOutlet weak var mainView: NSView!    // the main view holding the above

The assignment

number.intValue = Int32(someNumber)

is issued from the background operation regularly (often). But the text does never change. I have set the "can draw concurrently" in IB for the view as well as for the TextField. I also tried

if mainView.lockFocusIfCanDraw() {
  mainView.setNeedsDisplay(mainView.rectPreservedDuringLiveResize)
  mainView.unlockFocus()
}

after the text field assignment. Also to no avail.


Solution

  • Typically these problems go away if you send your view updating code back to the main queue from within your background task:

    DispatchQueue.main.async {
        // your view update code
    }
    

    If there's not too many place inside your doTheBackgroundStuff you could just sprinkle those in for view updates, i.e. whenever you access your mainView.

    Otherwise it helps to re-group things into parts that do non-UI heavy lifting and then push the view updates to Dispatch.main.async at the end.