我正在初始化一个简单的界面,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秒。
答案 0 :(得分:6)
你有一个表列(我假设你的意思)绑定到一个数组控制器,所以这是表视图从中获取数据的地方。表视图可能很好地要求更新的数组,但它要求数组控制器,它不知道任何变化。
阵列控制器不会简单地转身并要求您提供新数据;这意味着它只是为了让你更难将表视图绑定到你的数组,而事实并非如此。这是一个控制器;它的工作是拥有(复制)数组并维护其顺序和用户选择其对象的某个子集。
因此,您需要阵列控制器来查找何时向阵列添加项目。实现此目标的最佳方法是将阵列控制器的contentArray
绑定到控制器的属性,并以符合KVO的方式更新该属性。
这意味着:
init
方法中创建可变数组。 (当然,请在dealloc
中发布。)addTracksObject:
和removeTracksObject:
(这是技术设置的访问方法,因此KVO会忽略它们的数组属性)。addTracksObject:
消息。您应该通过向自己发送insertObject:inTracksAtIndex:
消息(索引为[self countOfTracks]
来回复此消息,除非您要执行insort),并且您应该通过发送{insertObject:inTracksAtIndex:
来回复tracks
1}}数组insertObject:atIndex:
消息。正如我所提到的,当addFooObject:
是NSArray属性时,KVO会忽略removeFooObject:
和foo
,考虑到那些只有NSSet属性的访问者,所以你需要在insertObject:inFooAtIndex:
之上实现它们。 {1}}和removeObjectFromFooAtIndex:
因为那些是数组访问器,这意味着KVO会对它们作出反应。
正如我刚才描述的那样,第3步将会非常慢,因为它会导致数组控制器重新获取你的属性和表视图,以至少每次重新获取一次数组控制器的arrangedObjects
对于您添加的每一行。
因此,您应该使用此备用步骤3维护批量添加行为:
insertTracks:atIndexes:
,并向其传递一批(例如100或1000)轨道和[NSIndexSet indexSetWithRange:(NSRange){ [self countOfTracks], countOfBatch }]
形成的索引集的数组。您还需要实现removeTracksAtIndexes:
,因为如果您没有其对应方式,KVO将忽略每个插入方法。您可能应该设置阵列控制器以尝试保留选择,以免在您仍然引入行时过多地挫败用户。
此外,您可能希望在后台线程上创建对象,定期向自己发送另一批使用主线程执行添加的批处理。我通常会主动在主线程运行循环中做事情,但是当你的定期负载建立另一批时,这种事情很容易让你的界面变得迟钝。
答案 1 :(得分:1)
您需要在主线程的表视图上调用setNeedsDisplay:YES
。不要从后台线程调用它。所有Cocoa UI调用必须在主线程上完成或发生奇怪的事情。