使用ARC将消息发送到解除分配的实例

时间:2012-10-27 02:35:42

标签: objective-c debugging memory-management exc-bad-access

我通常不会问这样的问题,但我真的不能理解它。我有一个类'GetTableInfoFromDatabase',它连接到我的数据库并下载一些JSON。这在我的标签栏应用程序的第一个屏幕上运行得很好。我可以调用getNewData方法,因为我想要有效地刷新数据。

当我尝试创建'GetTableInfoFromDatabase'类的实例并从另一个选项卡调用相同的方法时,我的问题出现了。我收到以下错误:

*** -[GetTableInfoFromDatabase respondsToSelector:]: message sent to deallocated instance 0x1d89e830

有趣的是,我正在使用ARC。罪魁祸首(在我看来)是ASIHTTPRequest。我必须启用-fno-objc-arc才能使项目进行编译。该库用于GetTableInfoFromDatabase类。

这是班级:

- (void) getEventDataWithSender:(id)sender{


ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"-------.com/getdata.php"]];
[request setDelegate:self];
NSLog(@"Running!");
[request startAsynchronous];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = appDelegate.managedObjectContext;
}

这就是我所说的:

GetTableInfoFromDatabase *getInfo = [[GetTableInfoFromDatabase alloc]init];
[getInfo getEventDataWithSender:self];

我甚至改变了标签的顺序,因此第一个要显示的标签只是调用此方法,没有别的。甚至在'GetTableInfoFromDatabase'之前已经由最后一次初始化它的类初始化之前。仍然崩溃。

有没有人有任何想法?这太令人沮丧了!

2 个答案:

答案 0 :(得分:10)

如果您打算将该变量公开给其他视图控制器,则需要将该变量分配给属性。在此代码执行后,ARC将,并且应该立即解除分配 getInfo

GetTableInfoFromDatabase *getInfo = [[GetTableInfoFromDatabase alloc]init];
[getInfo getEventDataWithSender:self];

因此,如果该行包含在 viewDidLoad:中,并且该方法中没有其他任何内容引用 getInfo ,则会立即释放该行。为什么,因为你没有告诉编译器它应该保留它。

所以在暴露这个类的视图控制器中,在任何标签上它可能是...的孩子......你会做这样的事情:

ViewController.h

@class GetTableInfoFromDatabase;  // forward declaration

@interface ViewController : UIViewController

@property (strong, nonatomic) GetTableInfoFromDatabase *getInfo;

<强> ViewController.m

@implementation ViewController

@synthesize getInfo = _getInfo;

- (void) viewDidLoad {
    [super viewDidLoad];

    self.getInfo = [[GetTableInfoFromDatabase alloc]init]; // assign your value to a property

    [self.getInfo getEventDataWithSender:self];
}

因此,当您在标题中将属性声明为时,它将保留对它的强引用。 @Synthesize getInfo = _getInfo意味着它将为名为 _getInfo 的实例变量周围的 self.getInfo 创建一个getter和setter。如果您不想将其作为属性公开,只需要一个实例变量......您可以这样做:

ViewController.h

@class GetTableInfoFromDatabase;  // forward declaration

@interface ViewController : UIViewController {
    GetTableInfoFromDatabase _getInfo;
}

<强> ViewController.m

@implementation ViewController

- (void) viewDidLoad {
    [super viewDidLoad];

    _getInfo = [[GetTableInfoFromDatabase alloc]init]; // assign your value to a property

    [_getInfo getEventDataWithSender:self];
}

默认情况下,除非另有说明,否则编译器将保持对该实例变量的强引用。您也可以使用弱引用,并且所有这些选项都有很好的文档记录。因此,对于ARC或普通的旧内存管理,如果您希望它暂停一段时间,您需要创建一个实例变量或属性。

老实说......所有ARC为你做的就是让你不必打电话给保留和释放。在ARC之前,设置该属性将如下所示:

    GetTableInfoFromDatabase getInfo = [[GetTableInfoFromDatabase alloc]init];

    self.getInfo = getInfo;

    [getInfo release];

现在使用ARC,编译器只是为您编写代码;)希望这有帮助!

    [self.getInfo getEventDataWithSender:self];

答案 1 :(得分:0)

您的GetTableInfoFromDatabase对象正在被取消分配,几乎可以肯定,因为没有任何东西可以强烈引用它。在上面的代码中,getInfo是一个局部变量,所以我希望它会在此代码之后很快发布,除非你将它存储在某个地方。

几乎可以肯定,dealloc中的GetTableInfoFromDatabase不会清除请求的委托。您应该在GetTableInfoFromDatabase的ivar中保存请​​求,以便在取消分配时将其作为委托删除。

作为旁注,请避免使用get添加ObjC方法。这在KVC中具有特殊含义(这意味着第一个参数应该通过引用更新)。通常,您在此处使用的方法将以“fetch”开头。