I'm working on a timeline based app that displays posts from App.net. When I tap a cell I load a TableViewController that loads a data controller object. This controller object then loads a data object. The controller object goes onto a background thread, fetching the posts in the thread. When it gets them it sends them to the data object which also goes onto a background thread to apply formatting to the posts and pre-calculate the heights needed to display the post text.
Then, from the background thread I call dispatch_async(dispatch_get_main_queue(), ^{...
and post a notification:
[[NSNotificationCenter defaultCenter] postNotificationName:PostStreamDataDidUpdateNotification object:self];
self
in this case is the data object that the TableViewController uses to populate it's cells. The program throws a tantrum when this notification is posted because technically self (the data object), the data controller object, and the TableViewController could be released by the navigation controller. This happens when I load a thread, therefore entering the background thread, and then popping the view from the navigation controller. The TableViewController released, as is everything it owned: the data controller, the data object etc.
I'm at a loss of what to do. From searches on the internet I can deduce that I'm running into Zombie problem. That sounded manageable, until I couldn't find anyone talking about how to avoid or fix them. Instruments makes them easy to find but how to avoid them...
I'm thinking that something is fishy with how I'm declaring properties and that setting something as a strong reference might be a bad idea.
Currently the TableViewController declares the data controller (PRSPostStreamDataController) as such:
@property (nonatomic, strong) PRSPostStreamDataController *postStreamDataController;
And that data controller object declared the data object as such:
@property (nonatomic, strong, readonly) PRSPostStreamData *data;
Some Questions bouncing around in my head:
Should I call
newSelf = [self copy];
before I enter the background thread and then return newSelf as the notification object? (I've attempted this but at this point I'm just throwing paint at a canvas)Should I cancel the background thread in my dealloc method? If so, how is that done? This question has a very similar premise to mine, except that the request completes and my problem lies in the background thread. a simple
delegate = nil;
doesn't exist for me.Testing for
self = nil
seems futile because the Xcode debugger is telling me self is not nil.Should I give up on my hopes of background threads entirely?
I'm new to stack overflow (and iOS Development too) but I do know that questions are supposed to be singular and concise. So the question:
It's great that I can use Instruments to track down Zombies in my app and it's great that I can see the methods responsible but how do I avoid creating zombie objects on a background thread?
This question is broad but I hope the information I provided can narrow it down. Let me know if I can improve the question
One possible solution would be to separate your data access layer, ie. the model, to an independent service (usually implemented as a singleton). This way the data is owned and managed by this service and not by the view controller that displays the data. This pattern is sometimes called Model-View-Controller-Store. It sometimes goes by other names, too — look it up.
This SO question also deals with similar issue: Pattern for preloading data for subsequent view to be displayed