EXC_BAD_ACCESS в UITableView на IOS - PullRequest
       3

EXC_BAD_ACCESS в UITableView на IOS

2 голосов
/ 21 декабря 2010

При прокрутке таблицы мой сбой приложения и консоль сказали, что это EXC_BAD_ACCESS.Я смотрю везде, и люди предлагают мне использовать NSZombieEnabled в переменных среды моего исполняемого файла.Я установил NSZombieEnabled, NSDebugEnabled, MallocStackLogging и MallocStackLoggingNoCompact на YES на моих исполняемых файлах.

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

[Session started at 2010-12-21 21:11:21 +0700.]
GNU gdb 6.3.50-20050815 (Apple version gdb-1510) (Wed Sep 22 02:45:02 UTC 2010)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin".sharedlibrary apply-load-rules all
Attaching to process 9335.
TwitterSearch(9335) malloc: recording malloc stacks to disk using standard recorder
TwitterSearch(9335) malloc: process 9300 no longer exists, stack logs deleted from   /tmp/stack-logs.9300.TwitterSearch.suirlR.index
TwitterSearch(9335) malloc: stack logs being written into /tmp/stack- logs.9335.TwitterSearch.tQJAXk.index
2010-12-21 21:11:25.446 TwitterSearch[9335:207] View Did Load
Program received signal:  “EXC_BAD_ACCESS”.

И вот когда я попытался набрать backtrace на GDB:

Program received signal:  “EXC_BAD_ACCESS”.
(gdb) backtrace
#0  0x00f20a67 in objc_msgSend ()   
#1  0x0565cd80 in ?? ()
#2  0x0033b7fa in -[UITableView(UITableViewInternal)  _createPreparedCellForGlobalRow:withIndexPath:] ()
#3  0x0033177f in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:] ()
#4  0x00346450 in -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow:] ()
#5  0x0033e538 in -[UITableView layoutSubviews] ()
#6  0x01ffc451 in -[CALayer layoutSublayers] ()
#7  0x01ffc17c in CALayerLayoutIfNeeded ()
#8  0x01ff537c in CA::Context::commit_transaction ()
#9  0x01ff50d0 in CA::Transaction::commit ()
#10 0x020257d5 in CA::Transaction::observer_callback ()
#11 0x00d9ffbb in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#12 0x00d350e7 in __CFRunLoopDoObservers ()
#13 0x00cfdbd7 in __CFRunLoopRun ()
#14 0x00cfd240 in CFRunLoopRunSpecific ()
#15 0x00cfd161 in CFRunLoopRunInMode ()
#16 0x01a73268 in GSEventRunModal ()
#17 0x01a7332d in GSEventRun ()
#18 0x002d642e in UIApplicationMain ()
#19 0x00001d4e in main (argc=1, argv=0xbfffee34) at /Users/suprie/Documents/Projects/Self/cocoa/TwitterSearch/main.m:14

Я очень благодарен за любую подсказку, которая поможет мне отладить мое приложение,

РЕДАКТИРОВАТЬ это заголовочный файл таблицы

#import <UIKit/UIKit.h>


@interface TwitterTableViewController : UITableViewController {

    NSMutableArray *twitters;

 }

@property(nonatomic,retain) NSMutableArray *twitters;

@end

и файл реализации

#import "TwitterTableViewController.h"

@implementation TwitterTableViewController

@synthesize twitters;

#pragma mark -
#pragma mark Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // Return the number of sections.
    return 1;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
   // Return the number of rows in the section.
   return [twitters count];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 90.0f;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    const NSInteger TAG_IMAGE_VIEW = 1001;
    const NSInteger TAG_TWEET_VIEW = 1002;
    const NSInteger TAG_FROM_VIEW = 1003;

    static NSString *CellIdentifier = @"Cell";

    UIImageView *imageView;
    UILabel *tweet;
    UILabel *from;


    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

        // Image
        imageView = [[[[UIImageView alloc] initWithFrame:CGRectMake(5.0f, 5.0f, 60.0f, 60.0f)] autorelease] retain];
        [cell.contentView addSubview:imageView];        
        imageView.tag = TAG_IMAGE_VIEW;

        // Tweet
        tweet = [[[UILabel alloc] initWithFrame:CGRectMake(105.0f, 5.0f, 200.0f, 50.0f)] autorelease];
        [cell.contentView addSubview:tweet];
        tweet.tag = TAG_TWEET_VIEW;
        tweet.numberOfLines = 2;
        tweet.font = [UIFont fontWithName:@"Helvetica" size:12];
        tweet.textColor = [UIColor blackColor];
        tweet.backgroundColor = [UIColor clearColor];

        // From
        from = [[[UILabel alloc] initWithFrame:CGRectMake(105.0f, 55.0, 200.0f, 35.0f)] autorelease];
        [cell.contentView addSubview:from];
        from.tag = TAG_FROM_VIEW;
        from.numberOfLines = 1;
        from.font = [UIFont fontWithName:@"Helvetica" size:10];
        from.textColor = [UIColor blackColor];
        from.backgroundColor = [UIColor clearColor];    
    }

    // Configure the cell...
    NSMutableDictionary *twitter = [twitters objectAtIndex:(NSInteger) indexPath.row];
    // cell.text = [twitter objectForKey:@"text"];

    tweet.text = (NSString *) [twitter objectForKey:@"text"];
    tweet.hidden = NO;

    from.text = (NSString *) [twitter objectForKey:@"from_user"];
    from.hidden = NO;

    NSString *avatar_url = (NSString *)[twitter objectForKey:@"profile_image_url"];
    NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: avatar_url]];

    imageView.image = [UIImage imageWithData: imageData];
    imageView.hidden = NO;


    return cell;
}




#pragma mark -
#pragma mark Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableDictionary *twitter = [twitters objectAtIndex:(NSInteger)indexPath.row];
NSLog(@"Twit ini kepilih :%@", [twitter objectForKey:@"text"]);
}


#pragma mark -
#pragma mark Memory management

- (void)didReceiveMemoryWarning {
   // Releases the view if it doesn't have a superview.
   [super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
}


- (void)dealloc {
    [super dealloc];
}


@end

это viewDidLoad из myViewController:

- (void)viewDidLoad {

    NSLog(@"View Did Load");
    [super viewDidLoad];

    twitterTableController = [[TwitterTableViewController alloc] init];

    responseData = [[NSMutableData data] retain];

    UIView *mView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    mView.backgroundColor = [UIColor whiteColor];

    theTableView = [[[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)] autorelease];
    theTableView.delegate = twitterTableController;
    theTableView.dataSource = twitterTableController;

    UIBarButtonItem *rightButton = [[[UIBarButtonItem alloc] initWithTitle:@"Refresh" style:UIBarButtonItemStyleDone  target:self action:@selector(refreshResult)] autorelease];

    self.navigationItem.rightBarButtonItem = rightButton;
    //  [mView addSubview:label];

    self.view = mView;
    [self.view addSubview:theTableView];

    NSString *url = @"http://search.twitter.com/search.json?q=suprie";

    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
                                          cachePolicy:NSURLRequestUseProtocolCachePolicy
                                      timeoutInterval:60.0];

    [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
}

[ОБНОВЛЕНИЕ] Я попробовал прибор, чтобы найти проблему.Мой друг сказал, что если бы это был Зомби, Инструмент сказал бы мне.Проблема в том, что при сбое программы прибор ничего не говорил.

Я также удалил все авто-релизы.все равно сбой программы.Мне удалось использовать malloc_history, и результат был

(gdb) shell malloc_history 10433 0x0552bfc0
malloc_history Report Version:  2.0
Process:         TwitterSearch [10433]
Path:            /Users/suprie/Library/Application Support/iPhone  Simulator/4.2/Applications/AF5C1948-C3DC-4680-9023- 4C3DFE8A5E13/TwitterSearch.app/TwitterSearch
Load Address:    0x1000
Identifier:      TwitterSearch
Version:         ??? (???)
Code Type:       X86 (Native)
Parent Process:  gdb-i386-apple-darwin [10435]

Date/Time:       2010-12-21 23:28:41.144 +0700
OS Version:      Mac OS X 10.6.5 (10H574)
Report Version:  6

ALLOC 0x552bfc0-0x552bfd7 [size=24]: thread_18d9540 |start | main | UIApplicationMain |  GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSources0 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ | MultiplexerSource::perform() | URLConnectionClient::processEvents() | URLConnectionClient::ClientConnectionEventQueue::processAllEventsAndConsumePayload(XConnectionEventInfo<XClientEvent, XClientEventParams>*, long) | URLConnectionClient::ClientConnectionEventQueue::processAllEventsAndConsumePayload(XConnectionEventInfo<XClientEvent, XClientEventParams>*, long) | URLConnectionClient::_clientDidFinishLoading(URLConnectionClient::ClientConnectionEventQueue*) | _NSURLConnectionDidFinishLoading | -[NSURLConnection(NSURLConnectionReallyInternal) sendDidFinishLoading] | -[TwitterViewController connectionDidFinishLoading:] | -[NSString(NSString_SBJSON) JSONValue] | -[SBJsonParser objectWithString:] | -[SBJsonParser scanValue:] | -[SBJsonParser scanRestOfDictionary:] | -[SBJsonParser scanValue:] | -[SBJsonParser scanRestOfArray:] | +[NSMutableArray arrayWithCapacity:] | -[__NSPlaceholderArray initWithCapacity:] | +[__NSArrayM __new::] | __CFAllocateObject2 | class_createInstance | _internal_class_createInstanceFromZone | calloc | malloc_zone_calloc 

Но я не мог прочитать это.Я не понимаю, какая строка вызвала сбой моих приложений

[ИСПРАВЛЕНО] Я исправил ошибку ... вот новый CellforRowatIndexPath

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    const NSInteger TAG_IMAGE_VIEW = 1001;
    const NSInteger TAG_TWEET_VIEW = 1002;
    const NSInteger TAG_FROM_VIEW = 1003;
    static NSString *CellIdentifier = @"Cell";

    UIImageView *imageView;

    UILabel *lblTweet;
    UILabel *from;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];


        imageView = [[UIImageView alloc] initWithFrame:CGRectMake(5.0f, 5.0f, 60.0f, 60.0f)];
        [cell.contentView addSubview:imageView];        
        imageView.tag = TAG_IMAGE_VIEW; 

        // Tweet
        lblTweet = [[UILabel alloc] initWithFrame:CGRectMake(105.0f, 5.0f, 200.0f, 50.0f)] ;
        [cell.contentView addSubview:lblTweet];
        lblTweet.tag = TAG_TWEET_VIEW;
        lblTweet.numberOfLines = 2;
        lblTweet.font = [UIFont fontWithName:@"Helvetica" size:12];
        lblTweet.textColor = [UIColor blackColor];
        lblTweet.backgroundColor = [UIColor clearColor];

        // From
        from = [[UILabel alloc] initWithFrame:CGRectMake(105.0f, 55.0, 200.0f, 35.0f)] ;
        [cell.contentView addSubview:from];
        from.tag = TAG_FROM_VIEW;
        from.numberOfLines = 1;
        from.font = [UIFont fontWithName:@"Helvetica" size:10];
        from.textColor = [UIColor blackColor];
        from.backgroundColor = [UIColor clearColor];
    }else{
        // I add this to fix the error
        imageView = (UIImageView *) [[cell viewWithTag:TAG_IMAGE_VIEW] retain];
        lblTweet = (UILabel *)[cell viewWithTag:TAG_TWEET_VIEW];
        from = (UILabel *)[cell viewWithTag:TAG_FROM_VIEW];
    }

    NSMutableDictionary *twitter = [twitters objectAtIndex:(NSInteger) indexPath.row];
    NSString *textTweet = (NSString *) [twitter objectForKey:@"text"];

    lblTweet.text = textTweet;
    lblTweet.hidden = NO;

    from.text = (NSString *) [twitter objectForKey:@"from_user"];
    from.hidden = NO;

    NSString *avatar_url = (NSString *)[twitter objectForKey:@"profile_image_url"];

    NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: avatar_url]];

    imageView.image = [UIImage imageWithData: imageData];
    imageView.hidden = NO;
    return cell;
}

Каким-то образом, когда я прокручиваю вверх, приложенияперерисовать таблицу, и поскольку ячейка была нарисована раньше, таблица и все остальное не инициализировано должным образом и выдают «EXC_BAC_ACCESS».

Большое спасибо за вашу помощь: D

Ответы [ 6 ]

1 голос
/ 21 декабря 2010

Я думаю, что ваша ошибка происходит из этой строки:

imageView = [[[[UIImageView alloc] initWithFrame:CGRectMake(5.0f, 5.0f,60.0f, 60.0f)] autorelease] retain];

или из этой строки:

UIBarButtonItem *rightButton = [[[UIBarButtonItem alloc] initWithTitle:@"Refresh" style:UIBarButtonItemStyleDone  target:self action:@selector(refreshResult)] autorelease];

Возможно, проблема в методе viewDidLoad, и я думаю, что это в предыдущей строке.

В вашем коде 2 ошибки:

  1. Вы вызываете авто-релиз на объекты imageView и rightButton. Autorelease означает, что вы потеряли право собственности на ваш объект, и он помещен в бассейн в ожидании освобождения от система. В любое время он может быть "одеты" системой. Так что вы не должен выдвигать гипотезу о объект "autorelease". Так ты в следующий раз, вы можете imageView, может быть, в то время это уже было выпущено системой:

    [cell.contentView addSubview: imageView];
    imageView.tag = TAG_IMAGE_VIEW;

  2. Вы также вызываете retain для этого объекта, это означает, что вы вступаете во владение этим объектом. Это не имеет никакого смысла, потому что вы вызывали авто-релиз раньше. Вы вступаете во владение объектом, если создаете его с помощью метода, имя которого начинается или содержит «alloc», «new», «copy» или отправляет сообщение сохранения этому объекту.

Правильный способ сделать это:

imageView = [[UIImageView alloc] initWithFrame:CGRectMake(5.0f, 5.0f, 60.0f, 60.0f)];
[cell.contentView addSubview:imageView];        
imageView.tag = TAG_IMAGE_VIEW; 
....
[imageView release];

///////
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"Refresh" style:UIBarButtonItemStyleDone  target:self action:@selector(refreshResult)];
 ...
[rightButton release];

Более подробную информацию о правилах управления памятью в iOS вы можете найти здесь: Правила управления памятью

1 голос
/ 21 декабря 2010

EXC_BAD_ACCESS может быть вызвано попыткой пула автоматического выпуска выпустить что-то, что уже было выпущено явно.

Не имея возможности увидеть ваш код, я бы посмотрел на то, что вы выпускаете в своем коде ([что-то релизное; Если вы найдете что-то подозрительное, просто закомментируйте это и снова запустите ваше приложение. Если вы получаете ту же ошибку, вы знаете, что это не так.

0 голосов
/ 22 декабря 2010

Я исправил ошибку и найдите место, где произошел сбой программы

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

   const NSInteger TAG_IMAGE_VIEW = 1001;
   const NSInteger TAG_TWEET_VIEW = 1002;
   const NSInteger TAG_FROM_VIEW = 1003;
   static NSString *CellIdentifier = @"Cell";

   UIImageView *imageView;

   UILabel *lblTweet;
   UILabel *from;

   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
   if (cell == nil) {
       cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
       imageView = [[UIImageView alloc] initWithFrame:CGRectMake(5.0f, 5.0f, 60.0f, 60.0f)];
       [cell.contentView addSubview:imageView];        
       imageView.tag = TAG_IMAGE_VIEW; 

       // Tweet
       lblTweet = [[UILabel alloc] initWithFrame:CGRectMake(105.0f, 5.0f, 200.0f, 50.0f)] ;
       [cell.contentView addSubview:lblTweet];
       lblTweet.tag = TAG_TWEET_VIEW;
       lblTweet.numberOfLines = 2;
       lblTweet.font = [UIFont fontWithName:@"Helvetica" size:12];
       lblTweet.textColor = [UIColor blackColor];
       lblTweet.backgroundColor = [UIColor clearColor];

       // From
       from = [[UILabel alloc] initWithFrame:CGRectMake(105.0f, 55.0, 200.0f, 35.0f)] ;
       [cell.contentView addSubview:from];
       from.tag = TAG_FROM_VIEW;
       from.numberOfLines = 1;
       from.font = [UIFont fontWithName:@"Helvetica" size:10];
       from.textColor = [UIColor blackColor];
       from.backgroundColor = [UIColor clearColor];
   }else{
       // I add this to fix the error
       imageView = (UIImageView *) [[cell viewWithTag:TAG_IMAGE_VIEW] retain];
       lblTweet = (UILabel *)[cell viewWithTag:TAG_TWEET_VIEW];
       from = (UILabel *)[cell viewWithTag:TAG_FROM_VIEW];
    }

    NSMutableDictionary *twitter = [twitters objectAtIndex:(NSInteger) indexPath.row];
    NSString *textTweet = (NSString *) [twitter objectForKey:@"text"];

    lblTweet.text = textTweet;
    lblTweet.hidden = NO;

    from.text = (NSString *) [twitter objectForKey:@"from_user"];
    from.hidden = NO;

    NSString *avatar_url = (NSString *)[twitter objectForKey:@"profile_image_url"];

    NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: avatar_url]];

    imageView.image = [UIImage imageWithData: imageData];
    imageView.hidden = NO;
    return cell;
}

Каким-то образом, когда я прокручиваю вверх, приложения перерисовывают таблицу, а поскольку ячейка была нарисована раньше, таблица и все остальное не инициализировано должным образом и выдают «EXC_BAC_ACCESS».

0 голосов
/ 21 декабря 2010

где вы мутируете массив twitters? Вы должны добавить в свой метод viewDidLoad следующую строку:

twitters = [[NSMutableArray alloc]init];

и затем установите или измените его. Вы можете отладить ваш код, выполнив NSLog'ом ваш cellForRowAtIndexPath и посмотреть, существует ли массив twitters

0 голосов
/ 21 декабря 2010

Таким образом, из трассировки стека видно, что происходит сбой при попытке обновить видимые ячейки. BAD_ACCESS обычно является признаком исчезнувшего объекта, то есть выпуска.
Я подозреваю, что вы выпустили переменную в вашем cellForRowAtIndex методе, которого у вас не должно быть. Попробуйте выяснить, дает ли вам подсказка сборка и анализ в XCode, в противном случае просто попробуйте удалить все релизы для отладки.
Если вы можете опубликовать метод, мы можем посмотреть на него и, возможно, помочь вам. Управление памятью в Objective-c не самая простая вещь ...

[править] глядя на ваш код, я не вижу никаких проблем. Я действительно озадачен тем, почему вы получите ошибку, которая у вас есть. Для начала я бы удалил все авто-релизы и случайное сохранение в представлении uiimage и проверил, помогает ли это. Может быть, кто-то еще может найти актуальную проблему.

0 голосов
/ 21 декабря 2010

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

Попробуйте и retain переменные, которые вы используете в своих методах tableView после их создания, и вы скоро узнаете, что было выпущено раньше / выходит за рамки.

Я всегда получаю это при попытке использовать метод автоматического освобождения с глобальной переменной.

Например: если у вас есть @property (nonatomic, retain) NSString *aString;, то использование aString = [NSString stringWithFormat:@"Some string"]; приведет к автоматическому освобождению при следующем цикле выполнения, и, следовательно, вы не сможете получить доступ к этому объекту позже, даже если вы думаете, что это глобальная переменная.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...