0

My UIViewController has a UITableView. Each custom cell is given a model object with weak association.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    List *list = self.lists[indexPath.row];
    ListCoverTableViewCell *cell = (ListCoverTableViewCell *)[tableView dequeueReusableCellWithIdentifier:NormalCell forIndexPath:indexPath];
    cell.list = list;
    return cell;
}

Each cell then observes a property on the model object.

- (void)addProgressObserverToCell:(ListCoverTableViewCell *)cell
{
    @try {
        [cell.list.tasksManager addObserver:cell
                                 forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                                    options:0 context:nil];
    } @catch (NSException *__unused exception) {}
}

addProgressObserverToCell: is called from viewWillAppear (in case the user taps on a cell and comes back), and in tableView's willDisplayCell: (for when the user scrolls).

A similar method removeProgressObserverFromCell gets called in viewWillDisappear (for when the user taps a cell and navigates away) and in tableView's didEndDisplayingCell (for when the user scrolls).

- (void)removeProgressObserverFromCell:(ListCoverTableViewCell *)cell
{
    @try {
        [cell.list.tasksManager removeObserver:cell
                                    forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                                       context:nil];
    } @catch (NSException *__unused exception) {}
}

So far, everything is balanced. I add observers in viewWillAppear/willDisplayCell, and remove them in viewWillDisappear/didEndDisplayingCell.

To be safe (and defensive), I updated my ViewController's dealloc method to also remove all observers. I simply loop through the tableView's visible cells and call removeProgressObserverFromCell:.

By running this code in the dealloc, I'm finding the model objects stored within my UITableView's visibleCells are never released. How is my defensive removal of observers causing my model object to be retained?

djibouti33
  • 12,102
  • 9
  • 83
  • 116
  • Have you used logging to confirm that add observer and remove observer calls are actually balanced? – Paulw11 Sep 21 '15 at 20:41
  • with the `removeObserver` calls in dealloc, the calls aren't balanced any longer. The @catch block is run, and if I log the exception, it just says "cannot remove observer because nothing is registered". And that's because they were already removed in `viewDidDisappear`. – djibouti33 Sep 21 '15 at 20:43
  • Right, so it isn't necessarily that objects are being retained, it may be that they haven't been released yet at the time you are looking. – Paulw11 Sep 21 '15 at 20:46
  • I thought that too, but I can click around the app for a while afterwards and I never see those logs from my model object being dealloc'd. The system seems to be holding on to them for much longer than necessary. If I delete the `removeObserver` call from dealloc, all model objects are dealloc'd immediately, as expected. – djibouti33 Sep 21 '15 at 21:03
  • Ok, so I misunderstood your question. I thought you meant that having the code dealloc made you realise that the objects weren't being released (ie the fact that the dealloc code could remove the observer meant they were still there) but it is the opposite. If you have the dealloc code they aren't being released – Paulw11 Sep 21 '15 at 21:08
  • exactly. for some reason, running the code in my @try block causes something to hold on to my model object. The 5 visible cells get dealloc'd, but those darn model objects still stick around indefinitely. – djibouti33 Sep 21 '15 at 21:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/90266/discussion-between-paulw11-and-djibouti33). – Paulw11 Sep 21 '15 at 21:10

0 Answers0