reloadData 后 NSMutableArray 变为 nil

Posted

技术标签:

【中文标题】reloadData 后 NSMutableArray 变为 nil【英文标题】:NSMutableArray becoming nil after reloadData 【发布时间】:2010-07-12 23:33:39 【问题描述】:

在我正在开发的 iPhone 应用程序中,我从 Web 服务获取一组数据,将其存储在可变数组中以显示在表格中,并将其存储在核心数据中作为没有网络时的备份。

我的数组在application:didFinishLaunchingWithOptions中初始化:如下tableArray = [[NSMutableArray alloc] initWithCapacity:100]; 然后在调用 viewDidLoad 后填充数组,这意味着 UITableView 存在(通过检查调试器进行验证),并且在调用 reloadData 之前,我让 NSLog 打印出数组的内容,果然一切都在那里。

我的问题是 reloadData 被调用后,tableArray 变为 null,如 tableView:numberOfRowsInSection: 中的 NSLog 所示。

我完全不知道为什么会发生这种情况,尽管我只在 Cocoa 中编程了几个月,很容易遗漏一些明显的东西。

编辑:用基本代码更新。

@interface MyAppDelegate : NSObject ... NSMutableArray *tableArray; @property (nonatomic, retain) NSMutableArray *tableArray; ... @end

@implementation MyAppDelegate @synthesize tableArray

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions   
    tableArray = [[NSMutableArray alloc] initWithCapacity:100];

    masterViewController = [[MasterViewController alloc] initWithNibName:@"MasterViewController" bundle:[NSBundle mainBundle]];
    [masterViewController.tableView setDelegate:self];
    [masterViewController.tableView setDataSource:self];
    ...

然后在 masterViewController 的 viewDidLoad 中调用一个名为 runWithNetwork 的方法:

- (void)runWithNetwork 
    ...
    NSArray *backpackArray = [[mainDict objectForKey:@"items"] objectForKey:@"item"];
    NSLog(@"%i", [backpackArray count]);
    for (int a=0; a<[backpackArray count]; a++) 
    NSDictionary *itemDict = [backpackArray objectAtIndex:a];
        NSString *ID = [[itemDict valueForKey:@"defindex"] stringValue];
        NSString *level = [[itemDict valueForKey:@"level"] stringValue];
        NSString *quality = [[itemDict valueForKey:@"quality"] stringValue];
        NSString *inventory = [[itemDict valueForKey:@"inventory"] stringValue];
        NSNumber *uid = [NSNumber numberWithInt:a];

        //Insert new
        myItem = [NSEntityDescription insertNewObjectForEntityForName:@"Backpack" inManagedObjectContext:managedObjectContext_];
        [myItem setValue:level forKey:@"level"];
        [myItem setValue:inventory forKey:@"inventory"];
        [myItem setValue:quality forKey:@"quality"];
        [myItem setValue:uid forKey:@"uid"];

        //Link to item db
        NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id == %@", ID];
        [fetch setEntity:[NSEntityDescription entityForName:@"GlobalItems" inManagedObjectContext:managedObjectContext_]];
        [fetch setPredicate:predicate];

        item = [[managedObjectContext_ executeFetchRequest:fetch error:nil] objectAtIndex:0];
        [myItem setValue:item forKey:@"item"];

        [tableArray addObject:[item valueForKey:@"name"]]; //a series of nsstrings

    
    NSLog(@"%@, %i", tableArray, [tableArray retainCount]); // all strings are printed correctly here, retaincount is 1

    [masterViewController.tableView reloadData];

然后我去我的表方法:

- (NSInteger)tableView:(UITableView *)tView numberOfRowsInSection:(NSInteger)section   
    NSLog(@"%@, %i", tableArray, [tableArray retainCount]);  //(null) printed, 0 for retaincount
    return [tableArray count];  //returns 0

tableView 位于 MasterViewController 的 xib 中,并在那里正确链接。它只在 MasterViewController 中描述过,并设置为 IBOutlet。 tableArray 仅在 MyAppDelegate.h 中描述,不会在其他任何地方重新创建。

【问题讨论】:

很奇怪,你的变量自发变成了nil。您是否尝试使用 Guard Malloc 运行您的程序(运行菜单 -> 启用 Guard Malloc)以查看您是否在某处有缓冲区 voerflow? 刚刚尝试过,我假设 GuardMalloc 找到的任何内容都会打印在控制台中?在这种情况下,那里的一切似乎都很好,我收到了 GM 的“欢迎”消息,然后一切都像以前一样被 NSLog 打印出来。 我想到了几种可能性,但是通过模糊描述您认为代码的工作方式很难弄清楚任何事情。查看代码(或仍然存在问题的简化版本)将更容易推断。 【参考方案1】:

正如我在评论中所说,很难弄清楚到底哪里出了问题。但是根据我在邮件列表等上帮助人们的经验,像这样的错误最常见的原因是当你认为你有两个不同的对象时。例如,一个实例是在 nib 中创建的,而另一个实例是在其他地方的代码中手动创建的。可能值得检查。

【讨论】:

已更新代码。 Re: 重复bug,tableView只定义在一个文件中,并且在IB中正确链接,tableArray只定义在一个文件中,不会在任何文件中意外重新创建。不过,感谢您的输入,我还没有检查多个对象。 @MattMcN:它的方法返回不一致结果的类通常具有分身。在这种情况下,runWithNetwork 将在该类的一个实例上调用,并且该表会将其数据源方法发送到另一个。 (我并不是要坚持这是问题所在——只是你不小心忽略了最有可能的嫌疑人。) 啊,我明白了。我调用 runWithNetwork 的方式是[[[UIApplication sharedApplication] delegate] runWithNetwork],它似乎返回了我的委托的一个新实例,一个带有空数组的实例。我现在重新构建了应用程序,从委托到 viewController 再到委托到委托到 viewController,一切都很好。【参考方案2】:

您的tableArray 没有被保留,因为您没有使用访问器来设置它。变化:

tableArray = [[NSMutableArray alloc] initWithCapacity:100];

到:

[self setTableArray:[[NSMutableArray alloc] initWithCapacity:100]];

【讨论】:

以上是关于reloadData 后 NSMutableArray 变为 nil的主要内容,如果未能解决你的问题,请参考以下文章

为啥 UITableView contentOffset 在 tableview reloadData 期间变化很大,而不是保持不变? reloadData 后如何使其保持不变?

在 UICollectionView 上调用 reloadData 后 contentSize 未更新

iOS UITableView reloadData 刷新结束后执行后续操作

UIImagePickerController 关闭后 UICollectionView 不会 reloadData()

reloadData后无法单击tableView单元格中的按钮

UICollectionViewFlowLayout 子类:reloadData 后粘性单元格消失