问题
The following process leads to a crash of my app:
- the user opens a view and a request is send to the server
- the request is executed in background
- the user navigates back to the root view
- the request has been finished
and the following code is executed
// MyDatasource.m
// e.g. in connectionDidFinishLoading
[callback loadedDataSource:self];
In the meantime the other models/views has been deallocated and the message is sent to a deallocated instance.
callback
is of type id
and conforms to the KalDataSourceCallbacks
protocoll.
How can I avoid that a message is sent to a deallocated object?
PS: My question is similar to this question
Edit:
I'll try to set callback
to nil in the dealloc
method (in my datasource class). This doesn't solve the problem, because MyDataSource
is always present and the dealloc
method should only be called if RootViewController
is released (what should happen when the app is closed).
What I've done so far:
Now MyDataSource
is retained by a property in my RootViewController
:
// RootViewController.h
@property (retain) MyDataSource *dataSource;
// RootViewController.m
@synthesize dataSource;
// ...
self.dataSource = [[[MyDataSource alloc] init] autorelease];
kal.dataSource = dataSource;
- (void)dealloc {
[dataSource release];
// ...
}
KalViewController does not retain its datasource. You probably will want to store a reference to the dataSource in an instance variable so that you can release it after the calendar has been destroyed.
I also created a callback
property:
// MyDataSource.h
@property (retain) id<KalDataSourceCallbacks> callback;
// MyDataSource.m
@synthesize callback;
// ...
- (void)presentingDatesFrom:(NSDate *)fromDate to:(NSDate *)toDate delegate:(id<KalDataSourceCallbacks>)delegate {
// ...
self.callback = delegate;
}
- (void)dealloc {
[callback release];
callback = nil;
// ...
}
Currently the app is not crashing. I have to test on the devices. Adding callback = nil
doesn't do anything here, because the dealloc is never called.
How should I release MyDataSource
after the calendar has been destroyed? That doesn't work because I don't know if the calendar has been destroyed. So the dataSource can only live over the whole app runtime.
Edit 2:
Can I check callback
for nil
to find out if it has been released?
if (callback != nil)
[callback loadedDataSource:self];
This doesn't help.
Edit 3:
The app was not crashing because I retained the delegate:
@property (retain) id<KalDataSourceCallbacks> callback;
should be
@property (assign) id<KalDataSourceCallbacks> callback;
So how could I avoid that the method loadedDataSource
is sent to a deallocated object for my special case?
回答1:
when you move out of the current view set the delegate to nil.
回答2:
You will need to make sure that you finish the connection and release it and set it to nil. A message sent to a nil object is ignored.
回答3:
In KalDataSource.h
I added the following method to the KalDataSource
protocoll:
@protocol KalDataSource <NSObject, UITableViewDataSource>
// ...
- (void)destroyCallback;
@end
In KalDataSource.m
I added the method to get rid of the warnings:
@implementation SimpleKalDataSource
// ...
- (void)destroyCallback
{
// do nothing
}
@end
In KalViewController.m
I'm calling my before created method when the object is deallocated:
- (void)dealloc
{
// ...
[dataSource destroyCallback];
}
In MyDataSource.m
I'm implementing the function
- (void)destroyCallback {
self.callback = nil;
}
and set the delegate to nil.
来源:https://stackoverflow.com/questions/4051738/how-to-avoid-that-callback-is-sent-to-deallocated-instance