how to avoid that callback is sent to deallocated instance

本秂侑毒 提交于 2019-12-08 13:02:23

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!