在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的实例。我会建议作如下修改:
-
让
sortedArtistArray
的NSMutableArray*
,如:NSMutableArray* sortedArtistArray;
-
不要在
parseiPodLibrary
覆盖数组引用。相反,只是排序的数据集复制到可变数组,如:-(void)parseiPodLibrary{ //..... NSArray* temp = [artistArray sortedArrayUsingDescriptors:sortingArray]; [sortedArtistArray removeAllObjects]; [sortedArtistArray addObjectsFromArray:temp]; }
不要在
viewDidAppear
调用[iPodLibrary retain];
。你已经调用了alloc/init,所以不需要再保留它。确保您在
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
初始化摆脱viewDidAppear
到viewDidLoad:
。这就是你应该初始化视图的地方。而且你应该清理在viewDidUnload
中初始化的任何内容,这将在低内存情况下调用。
原来问题出在我的ArtistClass - 艺术家字符串在我不知情的情况下被自动发布。将代码分解为多行代码是一个巨大的帮助。谢谢大家!!! – chrisgilpin 2011-04-16 23:03:57