Danedo
Danedo

Reputation: 2263

UITableView setDataSource - Deallocated object error

I have a UIViewController which contains this property:

@property (weak, nonatomic) IBOutlet UITableView *customerTableView;

In the UIViewController's viewDidLoad method, I have the following:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // ...
    CustomerTableViewDataSource *dataSource = [[CustomerTableViewDataSource alloc]
        init];
    [dataSource setData:customersSource];
    [customerTableView setDataSource:dataSource];
}

I receive this with NSZombies enabled:

*** -[CustomerTableViewDataSource numberOfSectionsInTableView:]: message sent to 
deallocated instance 0x3e07a0

The deallocated instance address is the same as the data source.

Is there any reason why the data source isn't 'sticking'?

Using the simulator and Zombies, I see that the reference is being released in viewDidLoad, which I suppose is no surprise since I declared it in that method and it should fall out of scope, however I would think that calling setDatasource would increase the refct. Well, it apparently doesn't.

Is there any way I can change this behavior?

Note: Everything works if I create an ivar and store the data source, but I feel like that clutters my class. Is this just life in the city?

Upvotes: 1

Views: 1111

Answers (2)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726559

From the documentation of UITableView:

@property(nonatomic, assign) id dataSource

Discussion

The data source must adopt the UITableViewDataSource protocol. The data source is not retained.

This means that customerTableView expects you to retain your data source object, which you did not do. Same goes for UITableView's delegate (in fact, for almost any delegate in cocoa, except CALayer's one). This design decision is made for a reason: the object that holds on to UITableView very often also serves as its delegate. Had the delegate been retained, the programmers would have to deal with retain cycles.

Unfortunately, the consequence of that decision is the problem that you are having: now you need to retain the data source (and the delegate, if any), e.g. by setting up an ivar.

Upvotes: 3

user529758
user529758

Reputation:

The table view's data source and delegate (as almost every delegate, by design) was always declared as (assign) and not (retain) even before Apple has introduced ARC. Nowadays in the ARC world I'm sure it's declared __weak (or else it would cause a retain cycle). So yes, go ahead and make an ivar in your class - that's exactly ivars are for.

P. s.: it's generally a bad design to create separate 'data source' and 'delegate' classes - as long as things don't get vers complicated, it's always better to use the view controller as your delegate/data source - in MVC, that's the layer which is designed for it - the (view) controller, that links the logic to the display.

Upvotes: 0

Related Questions