在UITableView中滚动时发生崩溃 - 对象被意外释放

问题描述:

**注意:我更新了基于aroth建议的代码 - 但它仍然崩溃。下面的帖子中的代码是更新后的代码。在UITableView中滚动时发生崩溃 - 对象被意外释放

我想创建一个基于表视图XCode模板(XCode 4)的iPhone应用程序。表视图会以正确的顺序填充正确的数据 - 但是当我滚动浏览表时,应用程序崩溃(有时候我可以滚动5或10多个单元格,有时会立即冻结)。表视图是从另一个“iPodLibraryParser”对象的IVAR中的“艺术家”对象提供的。我相信问题在于'iPodLibraryParser'对象被过早释放 - 但我不明白为什么。

我已经创建了下面的头文件的iPodLibraryParser对象:

#import <Foundation/Foundation.h> 
#import <MediaPlayer/MediaPlayer.h> 
#import <CoreLocation/CoreLocation.h> 
#import "ArtistClass.h" 

@interface iPodLibraryParser : NSObject { 

    //Location stuff 
    CLLocationManager *locationManager; 
    IBOutlet UITextField *latitudeTextField; 
    IBOutlet UITextField *longitudeTextField; 
    IBOutlet UILabel *latitudeLabel; 
    IBOutlet UILabel *longitudeLabel; 

    //Music Library Stuff 
    NSString *currentArtist; 
    NSString *currentAlbum; 
    NSMutableArray *artistArray; 
    NSMutableArray *sortedArtistArray;  
} 

@property (nonatomic, retain) NSMutableArray *sortedArtistArray; 

-(void)parseiPodLibrary; 
-(id) initializeiPodLibraryParser; 

@end 

在这个类的.m文件相关的代码:

@implementation iPodLibraryParser 

@synthesize sortedArtistArray; 

-(id) initializeiPodLibraryParser{ 

    [super init]; 

    sortedArtistArray = [[NSMutableArray alloc] initWithObjects:nil]; 

    return self; 

} 

    -(void)parseiPodLibrary{ 

    ..... 

NSArray *sortingArray = [[NSArray alloc] initWithObjects:artistTrackCountSorter,nil]; 
NSArray *tempSortedArray = [artistArray sortedArrayUsingDescriptors:sortingArray]; 
[sortedArtistArray removeAllObjects]; 
[sortedArtistArray addObjectsFromArray:tempSortedArray]; 

    } 

艺术家对象头:

#import <UIKit/UIKit.h> 
#import "iPodLibraryParser.h" 

@interface ArtistClass : NSObject { 

    NSString *artistName; 
    int numberOfTracks; 

    id artistClassViewController; 
} 

-(id) initializeArtistObjectWithDocument:(id)myDocument withArtist:(NSString*) artist; 

@property (nonatomic, retain) NSString *artistName; 
@property (nonatomic, assign) int numberOfTracks; 

@end 

表视图控制器(从正在使用的模板中称为RootViewController)

部首:

#import <UIKit/UIKit.h> 
#import "iPodLibraryParser.h" 
#import "ArtistClass.h" 

@interface RootViewController : UITableViewController { 

    iPodLibraryParser *iPodLibrary; 
} 

@property (nonatomic, retain) iPodLibraryParser *iPodLibrary; 

@end 

相关代码

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 

    NSLog(@"In viewDidAppear"); 

    iPodLibrary = [[iPodLibraryParser alloc] initializeiPodLibraryParser]; 
    [iPodLibrary parseiPodLibrary]; 

} 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return 1; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 

    NSLog(@"there are %i artists in the array", [[iPodLibrary sortedArtistArray] count]); 
    return [[iPodLibrary sortedArtistArray] count]; 

} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSLog(@"in tableView blah"); 

    static NSString *CellIdentifier = @"Cell"; 

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

    // Configure the cell. 

    NSLog(@"getting row: %i",indexPath.row); 

    cell.textLabel.text = [[[iPodLibrary sortedArtistArray] objectAtIndex:indexPath.row] artistName]; 

    return cell; 
} 

该错误是在这一行:

cell.textLabel.text = [[[iPodLibrary sortedArtistArray] objectAtIndex:indexPath.row] artistName]; 

我试图创建与艺术家对象的数组,我的RootViewController的内创建 - 并且完美地工作(可以滚动整个桌子而不会崩溃)

再次感谢!

- 编辑:

这是有趣的是,我在不同的时间得到不同的错误:

大多数IT在该行只是EXC_BAD_ACCESS时代:

cell.textLabel.text = [[[iPodLibrary sortedArtistArray] objectAtIndex:indexPath.row] artistName]; 

有时候, :

-[UIAutoRotatingWindow isEqualToString:]: unrecognized selector sent to instance 0x1baa80 

而另一个与无法识别的RG有关B选择器(很奇怪)。

您的问题是,当你这样做:

sortedArtistArray = [artistArray sortedArrayUsingDescriptors:sortingArray];

sortedArrayUsingDescriptors方法返回一个自动释放的对象,所以当它得到你释放,而没有警告你不应该感到惊讶。

而且,因为你的init作用:

sortedArtistArray = [[NSArray alloc] init];

...因为你分配给它之前不释放,你的代码泄漏NSArray的实例。我会建议作如下修改:

  1. sortedArtistArrayNSMutableArray*,如:

    NSMutableArray* sortedArtistArray;

  2. 不要在parseiPodLibrary覆盖数组引用。相反,只是排序的数据集复制到可变数组,如:

    -(void)parseiPodLibrary{ 
    
        //..... 
    
        NSArray* temp = [artistArray sortedArrayUsingDescriptors:sortingArray]; 
        [sortedArtistArray removeAllObjects]; 
        [sortedArtistArray addObjectsFromArray:temp]; 
    
    } 
    
  3. 不要在viewDidAppear调用[iPodLibrary retain];。你已经调用了alloc/init,所以不需要再保留它。

  4. 确保您在dealloc调用viewWillDisappear[iPodLibrary release];,并[sortedArtistArray release];让你不泄漏内存。

我认为你的iPodLibrary变量比它的数组过度释放的可能性要大得多。

NSArray *artistArray = [iPodLibrary sortedArtistArray]; 
Artist *artist = [artistArray objectAtIndex:indexPath.row]; 
NSString *name = [artist artistName]; 
cell.textLabel.text = name; 

有没有可能是你的initializeiPodLibraryParser实现返回一个自动释放的对象:它失败,您应通过拆分您的代码到几行,看到解决?它不应该违反公约。但这会导致这个问题,这是有道理的。

当调用此:

iPodLibrary = [[iPodLibraryParser alloc] initializeiPodLibraryParser]; 

你直接分配iPodLibrary伊娃,所以它的突变不叫,它并不重要的属性标记为保留。如果你认为它被隐含地保留下来,那么很可能你会在其他地方过度释放它。我发现,如果你用这种风格来分配的属性,你就会明白你自己的内存管理:

iPodLibraryParser *parser = [[iPodLibraryParser alloc] initializeiPodLibraryParser]; // retain count should be 1 if not autoreleased 
[self setIpodLibrary:parser]; // retain count is now 2 
[parser release]; // retain count is now 1, will go to zero when you release it in dealloc or viewDidUnload 

最后,我想你iPodLibrary初始化摆脱viewDidAppearviewDidLoad:。这就是你应该初始化视图的地方。而且你应该清理在viewDidUnload中初始化的任何内容,这将在低内存情况下调用。

+0

原来问题出在我的ArtistClass - 艺术家字符串在我不知情的情况下被自动发布。将代码分解为多行代码是一个巨大的帮助。谢谢大家!!! – chrisgilpin 2011-04-16 23:03:57