如何避免回调被发送到释放实例 [英] how to avoid that callback is sent to deallocated instance

查看:104
本文介绍了如何避免回调被发送到释放实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下过程导致我的应用崩溃:




  • 用户打开一个视图,请求发送到服务器

  • 请求在后台执行

  • 用户导航回根视图

  • 完成



并执行以下代码

  // MyDatasource.m 
// eg in connectionDidFinishLoading
[callback loadedDataSource:self];

同时,其他模型/视图已被释放,并将消息发送到释放实例。



回调的类型为 id ,符合 KalDataSourceCallbacks protocol1。



如何避免将消息发送到已释放对象?



PS:我的问题类似于这个问题



编辑



callloc 方法(在我的datasource类中)的回调到nil。这不解决问题,因为 MyDataSource 总是存在,并且 dealloc 方法应该只调用 RootViewController 已发布(当应用关闭时会发生什么)。



到目前为止, p>

现在 MyDataSource 由我的中的属性保留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不保留其数据源。您可能希望在实例变量中存储对dataSource的引用,以便在日历被销毁后可以释放它。


我还创建了一个回调属性:

  // MyDataSource.h 
@property(retain)id< KalDataSourceCallbacks>回电话;

// MyDataSource.m
@synthesize callback;
// ...
- (void)presentingDatesFrom:(NSDate *)fromDate to:(NSDate *)toDate delegate:(id< KalDataSourceCallbacks>)delegate {
// ...
self.callback = delegate;
}
- (void)dealloc {
[callback release];
callback = nil;
// ...
}

目前该应用程序没有崩溃。我必须在设备上测试。添加 callback = nil 在此处不执行任何操作,因为dealloc不会被调用。



MyDataSource 之后日历已被销毁?这不工作,因为我不知道日历是否已被销毁。因此,dataSource只能在整个应用运行时生效。



编辑2:



我可以为 nil 检查回拨以确定是否已发布?

  if(callback!= nil)
[callback loadedDataSource:self];

这没有帮助。



编辑3:



应用程式并未崩溃,因为我保留了委派:

  @property(retain)id< KalDataSourceCallbacks>回电话; 

应为

  @property(assign)id< KalDataSourceCallbacks>回电话; 

那么如何避免方法 loadedDataSource KalDataSource.h

c $ c>我添加了以下方法到 KalDataSource protocol1:

  @protocol KalDataSource< NSObject,UITableViewDataSource> 
// ...
- (void)destroyCallback;
@end

KalDataSource.m 我添加了方法以摆脱警告:

  @implementation SimpleKalDataSource 
// ...
- (void)destroyCallback
{
// do nothing
}
@end

KalViewController.m 当对象被释放时,我在调用我的create方法之前:

   - (void)dealloc 
{
// ...
[dataSource destroyCallback];
}

MyDataSource.m 我正在实现函数

   - (void)destroyCallback {
self.callback = nil;
}

并将委托设置为nil。


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?

解决方案

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.

这篇关于如何避免回调被发送到释放实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆