为什么我得到一个EXC_BAD_ACCESS

时间:2009-12-17 21:43:52

标签: iphone objective-c twitter

嘿。我一直在研究Twitter应用程序,并且已经在EXC_ BAD_ ACCESS错误上停留了很长时间。我知道EXC_ BAD_ ACCESS是一个内存问题,但我无法确定问题所在。这是我的代码示例:

- (void)viewDidLoad {
   [super viewDidLoad];

   NSString *path = @"/Volumes/Schools/BHS/Student/740827/Documents/Forrest McIntyre CS193P/Presence2";
   NSArray *propList = [NSArray arrayWithContentsOfFile:[NSBundle pathForResource:@"TwitterUsers" ofType:@"plist" inDirectory:path]];

   people = [[NSMutableArray alloc]init];

   for (NSString *name in propList) {
     Person *p = [[Person alloc] initWithUserName: name];
     [people addObject: p];
     [p release];
   }
   // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
   // self.navigationItem.rightBarButtonItem = self.editButtonItem;
}

在评论后的最后一个大括号上抛出异常。我相信它确实被扔进了某个地方的for循环中,但只是出现了。

以下是Person的实现文件:

@implementation Person
@synthesize image;
@synthesize username;
@synthesize displayName;
@synthesize statusArray;

-(id)initWithUserName:(NSString *)userName {
 if(self = [super init])
 {
  self.username = userName;
  NSDictionary *info = [TwitterHelper fetchInfoForUsername:userName];
  self.displayName = [info objectForKey:@"name"];
  NSLog([NSString stringWithFormat:@"%@",[info objectForKey:@"profile_image_url"]]);
  NSString *imageURL2 = [NSString stringWithFormat:@"%@",[info objectForKey:@"profile_image_url"]];
  self.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString: imageURL2]]];
  [info release];
  self.statusArray = [TwitterHelper fetchTimelineForUsername:userName]; 
 }
 return self;
}
@end

感谢您的帮助

编辑:这是PersonListViewController的头文件(包含ViewDidLoad的类)。 这只是为了向您展示人们的来源。

@interface PersonListViewController : UITableViewController {
    NSMutableArray *people;
}

@end

8 个答案:

答案 0 :(得分:9)

因为您永远不会保留propListpath,所以您不应该发布它们。

但是,您应该发布people

有关内存管理的概述,请参阅Memory Management Programming Guide

要快速修复,请尝试使用静态分析器。

答案 1 :(得分:3)

我认为问题在于:

[propList release];

由于您使用arrayWithContentsOfFile创建了propList,因此无需释放它 - 它将自动释放。自动释放实际上是导致错误的原因,因为它试图释放您已经手动释放的内容。

ETA:正如cobbal所提到的,你也不需要发布path

答案 2 :(得分:1)

调试EXC_BAD_ACCESS很难调试。将消息发送到已释放的对象时会发生这种情况。您需要通过启用NSZombiEnabled环境变量来找出导致此一般错误的原因,以便Objective-C环境能够“跟踪”解除分配的对象。使用此功能,当您收到错误时,您可以通过查看调用堆栈来确定错误发生的位置。你不会知道它的发布地点,但至少它会让你接近。

我没有在这里设置它,但你也可能传递一个指向错误的指针,这将导致该对象不会像僵尸/虚拟一样持久存在。

最重要的是,您需要确保要释放的变量,并在必要时保留它们。

Apple的技术问答A给出了Finding bugs with EXC_BAD_ACCESS的提示。

答案 3 :(得分:1)

首先,在您的示例中,这些都不是必需的:

 [path release];
 [propList release];

,因为:

path是一个字符串文字(将永远存在)

propList已自动释放

答案 4 :(得分:1)

对于任何EXC_BAD_ACCESS错误,您通常会尝试向已发布的对象发送消息。追踪这些内容的最佳方式是使用NSZombieEnabled

这可以通过永远不会实际释放一个对象,但将其包装为“僵尸”并在其中设置一个标志,表示它通常会被释放。这样,如果您再次尝试访问它,它仍然知道在发生错误之前它是什么,并且通过这些信息,您通常可以回溯以查看问题所在。

当调试器有时会抓取任何有用的信息时,它特别有助于后台线程。

非常重要但是,您需要100%确保这只是在您的调试代码而不是您的分发代码中。因为什么都没有发布,你的应用程序将泄漏,泄漏和泄漏。为了提醒我这样做,我把这个日志放在我的appdelegate:

if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
  NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");

如果您需要帮助查找确切的行,请执行构建和调试( CMD-Y )而不是构建并运行( CMD-R )。当应用程序崩溃时,调试器会向您显示确切的行,并与NSZombieEnabled结合使用,您应该能够确切地找到原因。

答案 5 :(得分:0)

http://www.cocoadev.com/index.pl?NSZombieEnabled可用于跟踪EXC_BAD_ACCESS错误。它们不是在release时解除分配对象,而是将它们置于僵尸状态,当随后访问它们时会引发异常。请确保不要使用此标志设置释放代码,因为它会像筛子那样泄漏内存。

答案 6 :(得分:0)

什么是self.editButtonItem?我没有在你的.h文件中看到它

答案 7 :(得分:0)

有几件事。

  • initWithUserName:中,您从不包含alloc / copy / create的方法获取信息。此外,您没有明确保留它。然而你释放了它。根据Cocoa Memory管理规则,假设fetchInfoForUsername:按预期自动释放其结果,这是有问题的。

  • 在初始值设定项中使用属性访问器被认为是错误的形式,因为它可能会导致KVO通知被发送给半生不熟的实例。