2009-12-17 4 views
0

Эй. Я работаю над приложением Twitter и довольно долго задерживался на ошибке EXC_ BAD_ ACCESS. Я знаю, что EXC_ BAD_ ACCESS - проблема памяти, но я не могу определить, где проблема. Вот мой пример кода:Почему я получаю EXC_BAD_ACCES

- (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 где-то, но просто появляется после выхода.

Вот файл реализации для лица:

@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 

Спасибо за любую помощь

EDIT: Вот файл заголовка для PersonListViewController (класс, который содержит ViewDidLoad). Это просто, чтобы показать вам, откуда люди.

@interface PersonListViewController : UITableViewController { 
    NSMutableArray *people; 
} 

@end 
+0

Как вы указали свойство User Name Person, оно сохранено или скопировано? –

ответ

9

, так как вы никогда не сохраняют propList или path вы не должны выпускать их.

Вы должны, однако, релиз people

Для обзора управления памятью, см Memory Management Programming Guide

Для быстрого исправления, попробуйте статический анализатор.

+0

Выпуск 'people' должен быть, вероятно, до того, как он присвоит ему новое значение. Для меня это похоже на глобальную переменную. –

+0

хорошо пункт.Он должен быть выпущен (или автореализован) где-то, но – cobbal

+0

Люди не могут быть освобождены. Он используется в cellForRowAtIndexPath. Это также глобальная переменная. Он выпущен в методе Dealloc. – Forrest

1

Отладка EXC_BAD_ACCESS трудно отлаживать. Это происходит, когда сообщение отправляется на объект, который уже выпущен. Вам нужно выяснить, что вызывает эту общую ошибку, включив переменную среды NSZombiEnabled, чтобы среда Objective-C могла «отслеживать» освобожденный объект. Используя это, при получении ошибки вы можете определить, где произошла ошибка, если посмотреть на стек вызовов. Вы не будете знать, где он будет выпущен, но, по крайней мере, это приблизит вас.

У меня нет настройки здесь, но вы также можете передать указатель на ошибку, которая заставит объект не сохраняться как зомби/манекен.

В нижней строке вы должны убедиться, что переменные, которые вы имеете в виду, должны освобождаться, чтобы вы сохраняли их по мере необходимости.

Настоящий Технический Q & A от Apple дает советы по Finding bugs with EXC_BAD_ACCESS.

3

Я думаю, что проблема здесь:

[propList release]; 

Поскольку вы создали propList с помощью arrayWithContentsOfFile вам не нужно, чтобы освободить его - он будет автоматически освобожден. Автореферат - это на самом деле то, что вызывает ошибку, поскольку оно пытается освободить то, что вы уже выпустили вручную.

ETA: как упомянуто cobbal, вам также не нужно выпускать path.

+0

Самая большая кривая обучения для меня - это обучение (и все еще обучение), когда я должен отпустить или нет. Если вы выпустите объект из API, который вы должны получить EXC_BAD_CRAP, но иногда заголовок документа/не показывает это - вы должны верить, что все придерживаются соглашений об именах, которые, как я думаю, отстой. – Chris

+0

И добавить самый большой недостаток в прекрасной среде программирования. – Chris

+0

@ Крис: Я совершенно не согласен. Исключительно последовательные и простые правила управления памятью Cocoa - одна из самых сильных сторон. Я не думаю, что традиционная парадигма управления памятью какао - это, пожалуй, самое лучшее, что я видел. – Chuck

1

С одной стороны, ни один из них необходимы в вашем примере:

[path release]; 
[propList release]; 

, потому что:

path является строковым (всегда будет существовать)

propList является autoreleased

0

http://www.cocoadev.com/index.pl?NSZombieEnabled может быть полезен при отслеживании ошибок EXC_BAD_ACCESS. Вместо того, чтобы освобождать объекты, когда они release d, он помещает их в состояние зомби, которое вызывает исключение, когда к нему впоследствии обращаются. Просто убедитесь, что никогда не выпускаете код с установленным флагом, так как он будет утечка памяти, как сито.

0

что такое self.editButtonItem? Я не вижу его в вашем файле .h

+0

Это прокомментировано. Это код, который автоматически помещается туда, если вы хотите реализовать и отредактировать кнопку на панели навигации – Forrest

0

Пара вещей.

  • В initWithUserName: вы получаете информацию от метода, который не содержит Alloc/копировать/создавать. Кроме того, вы явно не сохраняете его. Но вы отпустите его. Это проблематично, предполагая, что fetchInfoForUsername: автореализует свой результат, как и ожидалось, в соответствии с правилами управления памятью какао.

  • Использование атрибутов доступа к ресурсам в инициализаторах считается плохой формой, поскольку это может привести к отправке уведомлений KVO для экземпляра с половиной выпечки.

1

Для любых ошибок EXC_BAD_ACCESS вы обычно пытаетесь отправить сообщение выпущенному объекту. BEST способ отслеживания этих действий используется NSZombieEnabled.

Это работает, никогда не выпуская объект, а завершая его как «зомби» и устанавливая внутри него флаг, который говорит, что он обычно был бы выпущен. Таким образом, если вы попытаетесь получить к нему доступ еще раз, он все еще знает, что это было до того, как вы сделали ошибку, и с этой небольшой информацией вы обычно можете отступить, чтобы узнать, в чем проблема.

Это особенно помогает в фоновом режиме, когда отладчик иногда дергает любую полезную информацию.

ОЧЕНЬ ВАЖНО ДЛЯ ЗАМЕЧАНИЯ, однако, необходимо, чтобы 100% убедитесь, что это только в вашем отладочном коде, а не в вашем коде распространения. Поскольку ничто никогда не выпускается, ваше приложение будет течь, течет и течет. Для того, чтобы напомнить мне, чтобы сделать это, я положил этот журнал в моем AppDelegate:

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

Если вам нужна помощь в поиске точной линии, сделайте сборку-и-Debug (CMD-Y) вместо Build- and-Run (CMD-R). Когда приложение выйдет из строя, отладчик покажет вам, в какой строке и в сочетании с NSZombieEnabled, вы должны точно выяснить, почему.

Смежные вопросы