2011-01-19 159 views
1

我最近在iOS上成为线程好奇。请指出你将采取的方向,以在现代iOS设备上实现(如果可能的话)以下内容......谢谢!线程,优先级和放弃

用户正在输入文字,每几秒钟说一个字。

我不时想启动DifficultProcess来做一些语义处理。总之,我想我需要能够做四件事情:从主

  • 如果DifficultProcess完成

    • 推出DifficultProcess,得到一个消息从它回到同一主
    • 抛弃,摆脱,DifficultProcess如果我想从主
    • 最后的优先问题:DifficultProcess必须比主要或用户输入的优先级低得多,我希望DifficultProcess真的真的优先;这甚至有可能吗?

    从本质上看,现代(2011年)(1月下旬)iOS中A,B,C所使用的调用是什么?我不在乎爸爸的方法!甚至可能以任何方式“D”?

    我想那是四个想法!

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

    (对于任何1997年之前出生的,你会认识到,作为一个典型的“投机性处理”的模式。)

    感谢的人谁的指针可以在这个被人打扰!

  • 回答

    7

    我会推荐使用NSOperation和NSOperationQueue来管理你需要能够任意取消的后台活动。

    NSOperation的取消和NSOperationQueue的取消所有操作是要看的方法。

    为了让消息从后台回到主线程,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]; 
    
    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 
    

    ,但我从来不知道它是必要的,调度足够聪明,以保持用户界面的响应。

    +0

    GCD非常适合这类工作。每当用户键入内容时,我都会有一个计时器。所以当它触发时(用户在2秒钟内没有按下按键),它会调用dispatch_async来触发处理,并在完成后向主线程发送NSNotification。 – 2011-01-19 23:38:10

    +1

    你确定观察者在主线程中得到通知吗?我没有在iOS上测试过,但是在Mac OS X上测试了IIRC,观察发生在任何引起变化的线程上。 – 2011-01-20 15:49:02

    +0

    我一直没有清楚 - 你可以在你用performSelectorOnMainThread调用的方法中做你的UI的东西,或者你可以通过主线程上的该方法通过KVO来触发它。我认为你是正确的关于变化的线程上发生的通知。 – 2011-01-20 18:21:57

    3

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

    虽然取消是棘手的。除了“分块”和检查每个块的标志之外,没有好的通用机制来取消后台工作。要使消息返回,只需将dispatch_async返回到主队列。如果你恰好眯起来,你可以将dispatch_async视为演员模型中的“发送消息”。

    (编辑)如果您需要在后台对内容进行序列化,请创建一个专用队列并将其目标设置为全局低优先级iirc。