2

I have a window that displays some data in an NSTableView. This data is loaded in the background. The data-loading-thread is started in the windowDidLoad: method. If the window is closed before loading has finished, the background thread should be cancelled. I do this by signalling the thread in the windowWillClose: delegate method and waiting for the background thread to finish.

Now this all works perfectly. But I have one problem: How can I update the data in the table view? I have tried calling reloadData via performSelectorOnMainThread: but this leads to a race condition: The reloadData call is sometimes queued on the main thread after the window close command, and will execute after the window has closed, and everything goes up in flames.

What's the best way to control and communicate with a background thread?

Jakob Egger
  • 11,981
  • 4
  • 38
  • 48

1 Answers1

3

Well, you know, this is exactly what makes the use of threading complex: you always face synchronization issues.

What I suggest is, instead of calling [tableView reloadData] from your thread, simply signal your controller (by calling a method controllerShouldReloadTable) and let your controller do the check if windowWillClose has been called or not. There might be a chance that your controller has been also released by the time controllerShouldReloadTable, and to fix this you will definitely need to retain the controller from the secondary thread.

On a side note, I would cancel the thread in viewDidUnload (for symmetry).

Most important: I would use asynchronous calls and a delegate class so that the whole multithreading issue is solved at its root.

EDIT: Sending asynchronously a request will not block the sending thread waiting for the response. Instead, asynchronous send (for NSURLConnection is called start) immediately returns (so, no blocking) and when the response is received, a delegate method will be called (i.e., connectionDidFinishLoading:) so that you can updated the model and the UI. Take a look at NSURLConnection docs, but as usual, I strongly suggest using [ASIHTTPRequest][2], which has many advantages.

Community
  • 1
  • 1
sergio
  • 68,819
  • 11
  • 102
  • 123
  • This is a good idea, I'll try this. But I can't use `viewDidUnload` because that's only available on iOS, and in Cocoa a window is not a view. I don't think I need to retain the controller because the `performSelector` methods retain the target anyway. Could you elaborate on what you mean with "asynchronous calls and delegate classes"? I'm not sure I understand this. – Jakob Egger May 26 '11 at 20:06
  • I tried it, and it seems to work now. If threaded programming only wasn't so hard... – Jakob Egger May 26 '11 at 20:51
  • Jakob, see my edit.. you will love async I/O, it is so natural to event-loop based systems... – sergio May 26 '11 at 21:42
  • Oh, thanks! Now I understand. I'm not sure if this will help me in my case, as I'm not loading data from HTTP, but rather from a database using my own classes, which don't have this async-type interface. – Jakob Egger May 26 '11 at 22:47