1.) NSOperation Queues是一个合理的选择吗?如果不是,还有什么其他选择?
NSOperationQueue听起来是个不错的选择。
当然,你还有其他选择:pthreads、libdispatch(也称为GCD)、基于pthreads的C++线程库等等。如果你不需要生成太多操作,那就只取决于你喜欢哪种模型了。
2.) 如何最小化睡眠时间?(显然我希望工作能得到尽可能多的周期/合理的周期,而且我不确定我的睡眠是否对所有UI更新都起作用。)
不要睡觉=) 你可以为你的UI元素使用定时器或显式回调或通知来通知依赖项。如果依赖项执行UI更新,则你很可能将消息添加到主线程的消息队列中。
3.) 有没有更好的技术来保持UI更新?例如,我可以使用NSTimer或其他方法向UI发送消息,告诉它更新和/或检查按钮的状态吗?
这真的取决于你在做什么。如果你只想更新进度条,则可以从辅助线程中写入值,并从主线程中读取该值。然后,在主运行循环上使用定时器定期向你的对象发送消息,以更新其显示(基于当前值)。对于像未分段进度指示器这样的东西,这可能很好。
另一种选择更适用于事件或阶段:它将涉及从辅助线程发布更新(例如通知或委托的回调),随着进度的推移而进行更新(有关#2的更多信息)。
更新
我不确定这在iOS模型中是否合适,但听起来是可以的。
是的,没问题 - 有许多方法可供选择。哪个“最好”取决于上下文。
我的当前理解是在一个线程中启动UI(不是主线程!)
你实际上并没有显式地启动UI;主线程(通常)由将事件和消息推送到主线程驱动。主线程使用运行循环,并在每次运行循环迭代时处理队列中的消息/事件。你还可以在未来安排这些消息(稍后会详细介绍)。话虽如此,所有针对UIKit和AppKit(如果你针对OSX)对象的消息都应该在主线程上执行(作为一般化的规则,你最终会发现有例外情况)。如果你有一个完全与消息传递UIKit对象的方法分离的具体实现,并且该程序是线程安全的,那么你实际上可以从任何线程执行这些消息,因为它不会影响UIKit实现的状态。最简单的例子:
@interface MONView : UIView
@end
@implementation MONView
- (NSString *)iconImageName { return @"tortoise.png"; }
@end
启动我的工作线程,使用定时器生成信号通知UI查看进度值并适当更新进度条。针对这个特定应用程序,你的倒数第二段已经足够了,我现在不需要进行最后一段的操作。谢谢。
要实现这个功能,您可以使用类似以下的方法:
@interface MONView : UIView
{
NSTimer * timer;
MONAsyncWorker * worker;
}
@end
@implementation MONView
- (void)workerWillExit
{
assert([NSThread isMainThread]);
[self.timer invalidate];
self.timer = nil;
self.worker = nil;
}
- (void)timerUpdateCallback
{
assert([NSThread isMainThread]);
assert(self.worker);
double progress = self.worker.progress;
[self updateProgressBar:progress];
}
- (void)beginDownload:(NSURL *)url
{
assert([NSThread isMainThread]);
assert(nil == worker);
worker = [[MONAsyncWorker alloc] initWithURL:url];
[self.operationQueue addOperation:worker];
const NSTimeInterval displayUpdateFrequencyInSeconds = 0.200;
timer = [[NSTimer scheduledTimerWithTimeInterval:displayUpdateFrequencyInSeconds target:self selector:@selector(timerUpdateCallback) userInfo:nil repeats:YES] retain];
}
@end
请注意,这只是一个非常基础的演示。通常将计时器、更新处理和操作放在视图控制器中而不是视图中更为常见。