线程,优先级和放弃

时间:2011-01-19 22:31:32

标签: iphone cocoa ios

我最近对iOS很好奇。请指出我将采取的方向,在现代iOS设备上实现(如果可能)以下内容...谢谢!

用户输入文字,每隔几秒就说一个字。

有时我想启动DifficultProcess来进行一些语义处理。简而言之,我想我需要做四件事:

  • 从主
  • 启动DifficultProcess
  • 如果DifficultProcess完成,请将消息从它返回到相同的主
  • 放弃,摆脱,如果我愿意,可以从主要
  • 中删除
  • 最后是优先级问题:DifficultProcess的优先级要低于主要或用户输入,我希望DifficultProcess真正具有优先级;甚至可能吗?

基本上,现代(2011年)(1月下旬)iOS中用于A,B,C的调用是什么?我不关心爸爸的方法! “D”在任何方面都是可能的吗?

我猜这些是四个想法!

所以特别是我想发送一条消息,换句话说,在运行的后台进程中调用一个例程(这样,如果需要,可以杀掉正在运行的后台进程,或者可能改变它的模式经营等)。

(对于1997年以前出生的人,你会认为这是典型的“投机处理”范式。)

感谢能够为此烦恼的任何人的指示!

3 个答案:

答案 0 :(得分:7)

我建议使用NSOperation和NSOperationQueue来管理您需要能够任意取消的后台活动。

NSOperation的-cancel和NSOperationQueue的-cancelAllOperations是要查看的方法。

要将消息从后台返回到主线程,dispatch_async-to-main-thread-queue技术很好。您可以将此与您的NSOperation的委托协议相结合,以编码您要发回的邮件。

E.g。

@protocol MyOperationDelegate
- (void) operationStarted:(MyOperation *)operation;
- (void) makingProgressOnItem:(id)anItem otherInterestingItem:(NSDictionary *)otherItem remainingCount:(NSUInteger)count;
- (void) operationWillFinish:(MyOperation *)operation;
@end

@interface MyOperation
id <MyOperationDelegate> delegate;
@end

@implementation MyOperation
...

- (void) cancel
{ 
    [super cancel];

    // Tell the delegate we're about to finish (due to cancellation).
    dispatch_sync (dispatch_get_main_queue(), ^{
      [self.delegate operationWillFinish:self];
    });
}

- (void) main 
{
    // Check for cancellation

    if (self.isCancelled) return;

    // Starting

    dispatch_sync (dispatch_get_main_queue(), ^{
        [self.delegate operationStarted:self];
    });

    if (self.isCancelled) return; // Another cancel check


    // Send async progress messages periodically while doing some work

    while (workNotDone) 
    {
        // Do some work ...

        dispatch_async (dispatch_get_main_queue(), ^{
           [self.delegate makingProgressOnItem:foo otherInterestingItem:bar remainingCount:baz];
        });

       if (self.isCancelled) return;
    }


    // About to finish

    if (!self.isCancelled) {
        dispatch_sync (dispatch_get_main_queue(), ^{
           [self.delegate operationWillFinish:self];
        });
    }
}
@end

KVO对于非线性交流并不好;在发起键值变化的线程上收到观察结果。因此,如果您的后台线程更改了某个值,您的后台线程将收到有关它的KVO。可能不是你想要的。

爷爷的-performSelectorOnMainThread:withObject:waitUntilDone:继续是将消息传回主线程的好方法。限制是您的消息只能访问一个基于对象的参数。主线程的dispatch_async没有此限制。

如果要从后台线程到主线程触发异步(或同步)NSNotification,则需要使用-performSelectorOnMainThread。

NSNotification *note = [NSNotification notificationWithName:FinishedABunchOfWorkNotification object:self userInfo:nil];
[[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:note waitUntilDone:YES];

答案 1 :(得分:3)

我建议将dispatch_async用于全局低优先级队列(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0))。

取消比较棘手。除了“分块”并检查每个块的标志之外,我没有很好的取消后台工作的一般机制

要将消息返回,只需将dispatch_async返回主队列即可。如果您恰到好处地斜视,您可以将dispatch_async视为演员模型中的“发送消息”。

(编辑)如果你需要在后台序列化东西,建立一个私人队列并将其目标设置为全局低优先级,iirc。

答案 2 :(得分:2)

冒着引用爸爸方法的风险(自iPhone版本2以来一直存在)我使用

- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg

只要你记得你必须在作为选择器传递的方法中创建一个新的自动释放池,并且在方法结束时将其排空,这很简单且万无一失。除此之外做任何你喜欢的事 - 除了触​​摸UIKit。它不是线程安全的,因此任何UI更改都必须通过

完成
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait

或KVO触发器。密钥值观察将是后台线程与主线程进行通信的好方法,即工作完成。

- (void)myBackgroundThreadMethod {

    NSAutoreleasePool *threadPool = [[NSAutoreleasePool alloc] init];

    // my time-consuming processing here

    [threadPool drain];
}

要更精确地控制线程,您需要查看NSThread。 Threading Programming Guide详细说明了这一点 - 如果你通过NSThread创建一个线程,那么你可以控制线程的启动时间。该文档建议单独保留线程并让它终止 - 但显示如何终止它。一种方法是- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait

NSThread文档也说“仅保留优先权”。您可以使用

设置线程优先级
+ (BOOL)setThreadPriority:(double)priority

但是我从来不知道它是必要的,调度程序足够聪明以维持UI响应。