Objective-C 后台线程 和 NSOperationQueue

旧街凉风 提交于 2020-01-07 04:28:59

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

  1. 后台线程

    简单操作,无需创建线程时,可以使用一下函数(以UILabel 为例):

    [myLabel performSelector:@selector(setText:) withObject:@"hello" afterDelay:0.1f];

    代替平时的操作:[myLabel setText:@"hello"];

    1)创建线程:执行线程函数,将函数要执行的任务从主界面线程中分离出来

    [NSThread detachNewThreadSelector:@selector(listenForRequests) toTarget:self withObject:nil ];

    -(void)listenForRequests

    {

          @autoreleasepool

          {

                //doSomething 

                ........            

          }

    }

    注意:线程函数内创建的任何对象在函数执行完成以后不会得到协防,为防止内存泄漏,在线程函数中需使用@autoreleasepool{}进行内存管理

           RunLoop
    说到 NSThread 就不能不说起与之关系相当紧密的 NSRunLoop。Run loop 相当于 win32 里面的消息循环机制,它可以让你根据事件/消息(鼠标消息,键盘消息,计时器消息等)来调度线程是忙碌还是闲置。
    系统会自动为应用程序的主线程生成一个与之对应的 run loop 来处理其消息循环。在触摸 UIView 时之所以能够激发 touchesBegan/touchesMoved 等等函数被调用,就是因为应用程序的主线程在 UIApplicationMain 里面有这样一个 run loop 在分发 input 或 timer 事件。

    2) 使用通知中心通知主线程更新界面:在线程函数中发送消息,在主线程中注册监听消息

        -(void)listenForRequests

    {

          @autoreleasepool

          {

                //doSomething 

               ........         

               [[NSNotificationCenter defaultCenter] postNotificationName:@"updateUI" object: obj];  

          }

    }

    主线程注册监听:

             [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(handlePost:) name:@"updateUI"  object:nil];

    -(void)handlePost:(NSNotification *)notify

    {

          id obj = [notify object];

          [self  performSelectorOnMainThread:@selector(update:) withObject:obj waitUntilDone:YES];

    }

    注: 这里接收到消息后,有必要的话,可以再开启线程来处理相关操作。

    附: 虽然传统的 NSThread 也可以进行多线程的管理,但是需要处理线程的声明周期,还要考虑线程同步、加锁等问题,会操作一定程度上的性能开销。

  2. 并发执行后台类 NSOperationQueue,分为4步来操作

    1)定义一个操作类

         a. 先定义一个回调接口,在任务完成后发送通知

             @protocal LongTaskOperationProtocal<NSObject>

             -(void) longTaskOperationFinished:(LongTaskOperation *)op;//接收 operation --LongTaskOperation 进行相关操作

             @end

         b. 定义一个操作类

            方法1. NSOperation子类 NAInvocationOperation

               NAInvocationOperation *operation = [[NSInvocationOperation alloc]initWitTarget:self selector:@selector(listenForRequets) object:obj];

             // 与当前线程同步执行代码   [operation star];

            // 异步执行需加入到 NSOperationQueue 中

             NSOperationQueue *operationQueue = [[NSOperationQueue alloc]init];

             [operationQueue addOperation:operation];

            方法2. NSOperation子类 NABlockOperation

            // 并发执行一个线程

          NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"执行线程。");

    }];

    [blockOperation start];

          // 并发执行多个线程

         NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"执行线程:%@",[NSThread currentThread]);

    }];

    [blockOperation addExecutionBlock:^{

        NSLog(@"执行一个并发线程线程:%@",[NSThread currentThread]);

    }];

    [blockOperation start];//并发的执行多个操作,分别在不同的线程中操作


  注: 线程完成后执行操作  :  operation.completionBlock =  ^(){};


        方法3. 自定义一个NSOperation的子类

         #import  "LongTaskOperationProtocal.h"

         @interface LongTaskOperation:NSOperation 

         {

               @private

                  NSString *imgFilePath;

         }

         @property (nonatomic,assign) id<LongTaskOperationProtocal> delegate;

               -(id)initWithPath:(NSString *)aPath;

                @end

        2)编写操作类的main()函数

                // LongTaskOperation.m   

                -(id)initWithPath:(NSString *)aPath

        {

            if (self == [super init]) {

        

            }

            return self;

        }

 

                //重写 NSOperation mian方法          

        -(void)main

        {

            if (!self.isCancelled) {

                @autoreleasepool {

                //do you back-end task

            

                if (!self.isCancelled &&self.delegate) {

                    [self.delegate longTaskOperationFinished:self];

                }

                        

              }

           }

        }

    注意:mian函数中一定要 使用独立的 autoreleasepool 来管理操作类中的变量,否则会造成内存泄漏。


    3)在需要进行耗时操作的类中创建操作类对象,并加入NSOperationQueue        

    NSOperationQueue *queue = [[NSOperationQueue alloc]init];

    [queue setMaxConcurrentOperationCount:[[NSProcessInfo processInfo]        activeProcessorCount] + 1];//设置线程队列中的最多线程数

    LongTaskOperation *operation = [[LongTaskOperation alloc]initWithPath:@"string"];

    operation.delegate = self;

    [queue addOperation:operation];

    operation = nil;


//注意:操作加入队列后,要立即释放操作对象。


    4)在进行耗时操作的类中定义操作完成函数

          -(void) longTaskOperationFinished:(LongTaskOperation *)op

           {........}

附:程序不需要队列时,释放队列

       [ queue cancelAllOperations];

      queue = nil;














易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!