42

I have run into this problem a few times while porting Objective-C code to Swift. Say I have the following code:

dispatch_async(dispatch_get_main_queue()) {
    self.hostViewController?.view.addSubview(self.commandField)
}

This will result in an error, underlining the entire dispatch_async call, offering:

Could not find member 'addSubview'

I assume this is an error that has not yet been properly implemented because if I put the addSubview call outside the dispatch_async block, the project builds fine. Initially I assumed it may have something to do with capturing self in the block. However, inserting [unowned self] in results in the same error, as does [weak self] in (after the appropriate ! unwrap operators have been inserted).

How can I get dispatch_async blocks to work in Swift that need to capture self?

JAL
  • 41,701
  • 23
  • 172
  • 300
Ephemera
  • 8,672
  • 8
  • 44
  • 84

2 Answers2

65

You should condition spinning off this action on the non-nullity, not test for it after you've already initiated it:

if let hostView = self.hostViewController?.view {
    DispatchQueue.main.async {
         hostView.addSubview(self.commandField)
    }
} else {
    // handle nil hostView 
}

You should never unwrap an optional outside of an if let, or testing it first. Doing this should also resolve yer weak self issue.

Renish Dadhaniya
  • 10,642
  • 2
  • 31
  • 56
iluvcapra
  • 9,436
  • 2
  • 30
  • 32
  • Ah that works, thanks! So is the compiler complaining that it can't deterministically unwrap `hostController?` inside the block? Or is there something else going on here? – Ephemera Jun 08 '14 at 01:33
  • 5
    It's because the expression `self.hostViewController?.view` returns an object of type `NSView?`, *not* `NSView`. Optional chains always have to be checked and the result either has to be letted or forced. – iluvcapra Jun 08 '14 at 02:31
13

The dispatch_async syntax has changed with Swift 3:

DispatchQueue.main.async { 
    hostView.addSubview(self.commandField)
}
JAL
  • 41,701
  • 23
  • 172
  • 300