Jon*_*ier 1 iphone crash core-data objective-c
我在我的iPhone应用程序的UIViewController中有一个方法(在UINavigationController中),只要在ViewController视图的表中选择了一行,就会调用该方法.在这个方法中,我访问存储在实例字段dreamsArray中的"Dream"数组,其中包含来自我的数据库的NSManagedObjects.我可以在其他方法中访问此数组中的对象,但似乎每当我尝试在此特定方法中从此数组中检索或修改检索到的对象时,程序就会崩溃.
以下是dreamsArray的创建方式:
dreamsArray = [[NSMutableArray alloc] init];
[self managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Dream" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release]; [sortDescriptor release];
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if ( mutableFetchResults == nil )
NSLog(@"oh noes! no fetch results DreamsTabController:45");
dreamsArray = [mutableFetchResults mutableCopy];
[mutableFetchResults release];
[request release];
Run Code Online (Sandbox Code Playgroud)
查询dreamsArray及其对象的实例:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if ( cell == nil )
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID] autorelease];
Dream *dream = (Dream *)[dreamsArray objectAtIndex:indexPath.row];
cell.textLabel.text = [dream title];
cell.detailTextLabel.text = @"foo!";
[dream release];
return cell;
}
Run Code Online (Sandbox Code Playgroud)
并且有所有问题的方法:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Dream *dream = (Dream *)[dreamsArray objectAtIndex:indexPath.row];
// BOOM - crashes right here
EditDreamController *edit = [[EditDreamController alloc] initWithNibName:@"EditDream" bundle:nil];
edit.dream = [[NSArray alloc] initWithObjects:dream.dreamContent, nil];
[navigationController pushViewController:edit animated:YES];
[dream release];
[edit release];
}
Run Code Online (Sandbox Code Playgroud)
在查询dreamsArray后,应用程序立即崩溃.
即使NSLog(@"%@", dream.title)在此方法中调用简单也会导致崩溃.这可能会出错?
Wil*_*ley 27
以下代码更短,更高效,更易于阅读,并且没有第一个块的六个左右内存泄漏:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Dream" inManagedObjectContext:[self managedObjectContext]]];
static NSArray *sortDescriptors = nil;
if (!sortDescriptors)
sortDescriptors = [[NSArray alloc] initWithObject:[[[NSSortDescriptor alloc] initWithKey:@"title" ascending:NO] autorelease]];
[request setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
if (!fetchResults)
NSLog(@"oh noes! no fetch results DreamsTabController:45, error %@", error);
[request release];
dreamsArray = [NSMutableArray arrayWithArray:fetchResults];
Run Code Online (Sandbox Code Playgroud)
这个方法被重写为更小而不是过度释放的梦想,这导致了崩溃:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
static NSString *cellID = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID] ? : [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID] autorelease];
Dream *dream = [dreamsArray objectAtIndex:indexPath.row];
cell.textLabel.text = dream.title;
cell.detailTextLabel.text = @"foo!";
return cell;
}
Run Code Online (Sandbox Code Playgroud)
这种方法过度释放了'梦想'并且在NSArray上泄漏,因此也是一个"梦想"实例.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
{
EditDreamController *editDreamController = [[EditDreamController alloc] initWithNibName:@"EditDream" bundle:nil];
Dream *dream = [dreamsArray objectAtIndex:indexPath.row];
editDreamController.dream = [NSArray arrayWithObjects:dream.dreamContent];
[navigationController pushViewController:editDreamController animated:YES];
[editDreamController release];
}
Run Code Online (Sandbox Code Playgroud)
目前还不清楚,当EditDreamController上的实例变量采用数组时它是奇异的 - 如果你真的可以设置多个数组,它应该是'梦想'.
-会
Dream *dream = (Dream *)[dreamsArray objectAtIndex:indexPath.row];
cell.textLabel.text = [dream title];
cell.detailTextLabel.text = @"foo!";
[dream release];
Run Code Online (Sandbox Code Playgroud)
你不应该释放-dream.阵列掌握它.该-tableView:didSelectRowAtIndexPath:方法也是如此.最有可能的是,该对象已被释放足够多次以释放,在数组中留下悬空引用.
最终结果?
崩溃.
此外,您的第一个代码有:
dreamsArray = [[NSMutableArray alloc] init];
[self managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Dream" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release]; [sortDescriptor release];
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if ( mutableFetchResults == nil )
NSLog(@"oh noes! no fetch results DreamsTabController:45");
dreamsArray = [mutableFetchResults mutableCopy];
Run Code Online (Sandbox Code Playgroud)
这里有几个混乱的代码.
(1)为什么将dreamsArray设置为空的可变数组,然后重置它以引用获取请求结果的可变副本?你正在泄漏空的可变数组.
(2)你打电话[self managedObjectContext],但不要对返回值做任何事情.然后managedObjectContext直接使用.只是[self managedObjectContext]到处使用.开销可以忽略不计.
(3)您创建一个保留的提取请求并将其分配给request,但从不释放它.另一个内存泄漏.
(4)你为什么要复制mutableFetchResults两次?这没有任何意义(并导致另一次泄漏).
总而言之,我建议重新访问Objective-C内存管理的文档.