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

时间:2011-04-16 05:13:26

标签: objective-c uitableview

**注意:我已经根据aroth的建议更新了代码 - 但是它仍在崩溃。以下帖子中的代码是更新后的代码。

我正在尝试基于表视图XCode模板(XCode 4)创建一个iPhone应用程序。表格视图以正确的顺序填充正确的数据 - 但是当我滚动表格时应用程序崩溃(有时我可以滚动5或10个以上的单元格,有时它会立即冻结)。表格视图由NSArray中的“Artist”对象提供,NSArray是另一个“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中创建的Artist对象创建一个数组 - 并且完美地工作(可以滚动整个表而不会崩溃)

再次感谢!

- 编辑:

值得注意的是,我在不同时间会遇到不同的错误:

大多数时候,这一行只是EXC_BAD_ACCESS:

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

有时它是:

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

另一个与无法识别的RGB选择器有关(非常奇怪)。

2 个答案:

答案 0 :(得分:0)

问题在于你这样做:

sortedArtistArray = [artistArray sortedArrayUsingDescriptors:sortingArray];

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

此外,因为您的init会:

sortedArtistArray = [[NSArray alloc] init];

...并且因为在分配给它之前你没有释放它,你的代码正在泄漏NSArray实例。我建议进行以下修订:

  1. sortedArtistArray设为NSMutableArray*,例如:

    NSMutableArray* sortedArtistArray;

  2. 请勿覆盖parseiPodLibrary中的数组引用。而只是将已排序的数据集复制到可变数组中,如:

    -(void)parseiPodLibrary{
    
        //.....
    
        NSArray* temp = [artistArray sortedArrayUsingDescriptors:sortingArray];
        [sortedArtistArray removeAllObjects];
        [sortedArtistArray addObjectsFromArray:temp];
    
    }
    
  3. 请勿在{{1​​}}中致电[iPodLibrary retain];。你已经调用了alloc / init,因此不需要再次保留它。

  4. 确保您致电viewDidAppear中的[iPodLibrary release];viewWillDisappear中的[sortedArtistArray release];,以便您不会泄漏内存。

答案 1 :(得分:0)

我认为你的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 ivar,因此不会调用其mutator,并且该属性被标记为retain并不重要。如果您认为它被隐式保留,那么您可能会在其他地方过度释放它。如果您使用此样式分配属性,我发现您将了解自己的内存管理:

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初始化从viewDidAppear移至viewDidLoad:。这就是你应该初始化你的观点的地方。你应该清理viewDidUnload中初始化的任何内容,这些内容将在低内存情况下调用。