Reputation: 2263
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
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
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