0

我正在初始化一个简单的接口,其中一个 NSTableView 绑定到一个数组控制器(它管理一个字典数组)。我想在后台加载数组的内容(这是一个非常耗时的过程),每 100 或 1000 个元素更新一次表格视图。这个想法是界面可用且响应迅速。我不知道之后如何触发更新/刷新。桌子仍然是空的。任何人都可以提供指点吗?

我目前的做法是:

// In init for my app controller. This seems to work well, but I've tried other methods here.
[self performSelectorInBackground:@selector(loadTable) withObject:nil];


- (void)loadTable {
  tracks = [[NSMutableArray alloc] initWithCapacity:[masters count]];

  // ... create each object one-by-one. Add it to tracks.
  for (... in ...) {
    [tracks addObject:newObject];
  }

  // Now I don't know what to do next. The table remains empty. 
  // Things I've tried (though possibly not in all combinations with the
  // method above):
  // 1. With a suitably-defined reloadData method, which just reloads
  //   the table view and sets needs display.
  [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];

  // 2. Reload directly.
  [tv reloadData];
  [tv setNeedsDisplay];
}

如果我只是直接加载数据,而不是在后台尝试这样做,一切正常,但需要将近 30 秒。

4

2 回答 2

6

您将表格列(我假设您的意思)绑定到数组控制器,因此表格视图从那里获取数据。表格视图很可能要求更新数组,但它要求数组控制器,它不知道有任何变化。

阵列控制器不会简单地转身向您询问新数据;这意味着它的存在只是为了让您更难将表视图绑定到您的数组,而事实并非如此。它是一个控制器;它的工作是拥有(副本)数组并维护其顺序和用户对其对象的某些子集的选择。

因此,您需要数组控制器来找出何时将项目添加到数组中。实现这一点的最佳方法是将数组控制器绑定到控制器的contentArray属性,并以符合 KVO 的方式更新该属性。

这意味着:

  1. init在您的方法中创建可变数组。(当然,在 . 中发布它dealloc。)
  2. 为方便起见,实现数组访问器方法,加上addTracksObject:removeTracksObject:(从技术上讲,它们是设置访问器方法,因此 KVO 将忽略它们作为数组属性)。
  3. 要添加曲目,请给自己发送addTracksObject:消息。insertObject:inTracksAtIndex:您应该通过向自己发送一条消息来响应这一点(使用[self countOfTracks]索引,除非您想进行排序),并且您应该insertObject:inTracksAtIndex:通过向您的tracks数组发送一条insertObject:atIndex:消息来响应。

正如我所提到的,KVO 将忽略addFooObject:when是一个 NSArray 属性,考虑removeFooObject:foo那些仅有的 NSSet 属性访问器,所以你需要在它们之上实现它们,insertObject:inFooAtIndex:因为removeObjectFromFooAtIndex:它们数组访问器,这意味着 KVO 会对它们做出反应。

正如我刚刚描述的那样,第 3 步会非常慢,因为它会导致数组控制器重新获取您的属性,并且表格视图会arrangedObjects为您添加的每一行至少重新获取一次数组控制器。

因此,您应该使用此备用步骤 3 来保持批量添加行为:

  • 实现insertTracks:atIndexes:,并将一组(例如,100 或 1000 个)轨道和由 组成的索引集传递给它[NSIndexSet indexSetWithRange:(NSRange){ [self countOfTracks], countOfBatch }]。您还需要实现removeTracksAtIndexes:,只是因为如果您没有对应的插入方法,KVO 将忽略每个插入方法。

您可能应该将数组控制器设置为尝试保留选择,以免在您仍在引入行时让用户感到沮丧。

此外,您可能希望在后台线程上创建对象,定期向自己发送另一批以使用主线程执行添加。我通常提倡尽可能在主线程运行循环上做事,但是这种事情很容易让你的界面变得迟钝,而你的周期性负载又会增加一批。

于 2010-11-22T06:45:51.377 回答
1

您需要setNeedsDisplay:YES在主线程上调用您的表视图。不要从后台线程调用它。所有 Cocoa UI 调用都必须在主线程上完成,否则会发生奇怪的事情。

于 2010-11-22T07:26:54.070 回答