当前位置:  开发笔记 > 前端 > 正文

如何解决iphone开发中遇到的EXC_BAD_ACCESS错误

如何解决《如何解决iphone开发中遇到的EXC_BAD_ACCESS错误》经验,为你挑选了3个好方法。

我想做一件简单的事; 从互联网上读取图像,将其保存到iphone上的应用程序文档目录中,然后从该文件中读回来,以便我以后可以用它做其他事情.编写文件工作正常,但当我尝试读回来时,我在GDB中得到一个EXC_BAD_ACCESS错误,我不知道如何解决.这是我的代码基本上是这样的:

-(UIImage *) downloadImageToFile {
NSURL * url = [[NSURL alloc] initWithString: self.urlField.text];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentsDirectory = [paths objectAtIndex:0];

[paths release]
NSString * path = [documentsDirectory stringByAppendingString:@"/testimg.png"];

NSData * data = [[NSData alloc] initWithContentsOfURL:url];

[data writeToFile:path atomically:YES];

return [[UIImage alloc] initWithContentsOfFile:path];
}

当我尝试从文件初始化UIImage时,代码在return语句中失败.有任何想法吗?

编辑:忽略添加最初是代码中的问题的版本.



1> Matthew Fred..:

注意:这特别适用于非ARC内存管理.

由于这有很多观点,并且经过检查的答案恰当地说明"代码显示内存管理在Objective-C中的工作原理严重缺乏",但没有人指出具体错误,我想我会添加一个触及他们的答案.

我们必须记住调用方法的基线级规则:

如果方法调用包含单词alloc,new,copyretain,则我们拥有所创建对象的所有权.¹如果我们拥有对象的所有权,则我们有责任释放它.

如果方法调用包含这些单词,我们就没有创建对象的所有权.¹如果我们没有对象的所有权,那么释放它不是我们的责任,因此我们永远不应该这样做.

让我们看看OP代码的每一行:

-(UIImage *) downloadImageToFile {

我们开始了一种新方法.在这样做的过程中,我们开始了一个新的上下文,其中每个创建的对象都存在.请记住这一点.下一行:

    NSURL * url = [[NSURL alloc] initWithString: self.urlField.text];

我们拥有url:alloc这个词告诉我们,我们拥有对象的所有权,我们需要自己释放它.如果我们不这样,那么代码就会泄漏内存.

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

我们不拥有paths:没有使用这四个魔术词,所以我们没有所有权,也绝不能自己发布.

    NSString *documentsDirectory = [paths objectAtIndex:0];

我们不拥有documentsDirectory:没有魔术词=没有所有权.

    [paths release]

回过头来看,我们发现我们没有自己的路径,因此当我们尝试访问不再存在的东西时,此版本会导致EXC_BAD_ACCESS崩溃.

    NSString * path = [documentsDirectory stringByAppendingString:@"/testimg.png"];

我们不拥有path:没有魔术词=没有所有权.

    NSData * data = [[NSData alloc] initWithContentsOfURL:url];

我们拥有data:那里的alloc这个词告诉我们我们拥有对象的所有权,我们需要自己释放它.如果我们不这样,那么代码就会泄漏内存.

以下两行不会创建或释放任何内容.然后是最后一行:

}

方法结束了,因此变量的上下文已经结束.纵观我们可以看到,我们拥有两个密码urldata,但并没有释放他们的任何.因此,每次调用此方法时,我们的代码都会泄漏内存.

NSURL物体url是不是很大,所以这是可能的,我们可能永远不会发现泄漏,但它仍然应该被清理,没有任何理由泄漏它.

NSData物体data是一个PNG图像,并可能是非常大的; 每次调用此方法时,我们都会泄漏对象的整个大小.想象一下,每次绘制一个表格单元格时都会调用它:整个应用程序崩溃不会花费很长时间.

那么我们需要做些什么来解决这些问题呢?它非常简单,我们只需要在不再需要它们时立即释放它们,通常是在它们最后一次使用之后:

-(UIImage *) downloadImageToFile {

    // We own this object due to the alloc
    NSURL * url = [[NSURL alloc] initWithString: self.urlField.text];

    // We don't own this object
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    // We don't own this object
    NSString *documentsDirectory = [paths objectAtIndex:0];

    //[paths release] -- commented out, we don't own paths so can't release it

    // We don't own this object
    NSString * path = [documentsDirectory stringByAppendingString:@"/testimg.png"];

    // We own this object due to the alloc
    NSData * data = [[NSData alloc] initWithContentsOfURL:url];

    [url release]; //We're done with the url object so we can release it

    [data writeToFile:path atomically:YES];

    [data release]; //We're done with the data object so we can release it

    return [[UIImage alloc] initWithContentsOfFile:path];

    //We've released everything we owned so it's safe to leave the context
}

有些人喜欢在方法结束时关闭上下文之前立即释放所有内容.在这种情况下,两个[url release];[data release];将出现在闭幕前右}括号.我发现如果我尽快释放它们代码就更清楚了,那么当我稍后完成对象时,我会清楚地说明它.

总结:我们拥有与创建的对象alloc,new,copy,或retain在方法调用这样的背景下结束之前必须释放他们.我们没有其他任何东西,绝不能释放它们.


¹这四个词中没有任何神奇的东西,它们只是苹果公司创造所述方法的人们一直使用的提醒.如果我们为自己的类创建自己的初始化或复制方法,那么在其适当的方法中包含单词alloc,new,copy或retain是我们的责任,如果我们不在我们的名称中使用它们,那么我们我们需要自己记住所有权是否已经过去.



2> Jon Thomason..:

对我有很大帮助的一件事是在objc_exception_throw上有一个断点.任何时候我都要抛出一个异常,我点击了这个断点,我可以调试堆栈链.我只是在我的iPhone项目中一直启用此断点.

为此,在xcode中转到左侧窗格"Groups&Files"的底部附近并找到"Breakpoints".打开它并单击Project Breakpoints,然后在详细信息窗格(顶部)中,您将看到一个标有"Double-Click for Symbol"的蓝色字段.双击它并输入"objc_exception_throw".

下次抛出异常时,您将停止并在调试器中,您可以将堆栈链向上移回导致异常的代码.



3> August..:

您的代码显示对Objective-C中内存管理的工作方式缺乏了解.除了您收到的EXC_BAD_ACCESS错误之外,不正确的内存管理还会导致内存泄漏,在iPhone等小型设备上可能会导致随机崩溃.

我建议你给这个读一遍:

Cocoa内存管理编程指南简介


我最近收到了很多关于EXC_BAD_ACCESS的问题,所以我写了这个http://loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html来解释它,并附上一系列调试技巧.在这种情况下(太多版本),Build and Analyze/scan-build可能会标记它.如果没有,肯定会启用Zombies.
推荐阅读
手机用户2402851155
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有