随笔 - 298  文章 - 377  trackbacks - 0
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(34)

随笔分类

随笔档案

文章档案

相册

收藏夹

搜索

  •  

最新评论

阅读排行榜

评论排行榜

在开发的时候 因为没有好好去了解三者的差异性 一时贪图便捷 一味使用NSThread开启异步线程 线程爆满没有及时关闭销毁 挖了坑吃了亏。 
今天就在这里简单写写三个的用法和差异性:

NSThread 封装性最差,主要基于thread使用,方便使用,缺点是需要手动关闭; 
GCD基于C的API,代码看起来比较乱(高大上),主要基于task使用; 
NSOperation是基于GCD,被封装成NSObject对象使用,主要基于队列使用。

NSThread的使用

NSThread 方法

1.创建:

//需要手动开启 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [thread start]; 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
//或 自动开启线程     [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
  • 1
  • 2
  • 1
  • 2
//或 隐式创建并开启线程     [self performSelectorInBackground:@selector(run) withObject:nil];
  • 1
  • 2
  • 1
  • 2

②获取主线程和判断是否为主线程

 + (NSThread *)mainThread; // 获得主线程     - (BOOL)isMainThread; // 是否为主线程     + (BOOL)isMainThread; // 是否为主线程
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

③或许当前线程和线程名称

NSThread *current = [NSThread currentThread];     - (void)setName:(NSString *)name;
  • 1
  • 2
  • 1
  • 2

④线程中的通信 线程A跳去线程B

//选择主线程     - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;     //选择特定线程     - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

⑤回到主线程更新UI

[self performSelectorOnMainThread:@selector(appendTextView:) withObject:message waitUntilDone:YES];
  • 1
  • 1

⑥线程睡眠

+ (void)sleepUntilDate:(NSDate *)date;     + (void)sleepForTimeInterval:(NSTimeInterval)ti;
  • 1
  • 2
  • 1
  • 2

⑦NSThread 线程取消和线程销毁 
线程取消- (void)cancel; 
实际上只是把isCancel状态置为YES,没有实际上销毁线程。要实现取消的功能,我们需要自己在线程的main函数中定期检查isCancelled状态来判断线程是否需要退出,当isCancelled为YES的时候,我们手动退出。如果我们没有在main函数中检查isCancelled状态,那么调用-cancel将没有任何意义。 
线程销毁 - (void)exit; 
个会立即终止线程,即使任务没有完成。有可能导致内存泄漏等。 
注意:对于有runloop的线程,可以使用CFRunLoopStop()结束runloop配合-cancel结束线程 
runloop启动的方法中run和runUntilDate:都无法使用CFRunLoopStop()退出,只有runMode:beforeDate:可以响应CFRunLoopStop(),所以要想使用CFRunLoopStop()退出runloop,必须使用runMode:beforeDate:启动

NSThread 完整例子

 - (void)viewDidLoad{      // ①创建线程  b并指定方法threadTest     self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadTest) object:nil];      //②在线程启动之前设置线程优先级       self.thread.qualityOfService = NSQualityOfServiceDefault;      //③启动线程     [self.thread start];   } /*由于线程的创建和销毁非常消耗性能,大多情况下,我们需要复用一个长期运行的线程来执行任务。在线程启动之后会首先执行-threadStar,正常情况下threadStar方法执行结束之后,线程就会退出。为了线程可以长期复用接收消息,我们需要在threadStar中给thread添加runloop*/ - (void)threadStar{          // ①给线程设置名字         [[NSThread currentThread] setName:@"myThread"];          // ②给线程添加runloop         NSRunLoop *runLoop = [NSRunLoop currentRunLoop];              //③给runloop添加数据源         [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];            //④:检查isCancelled         while (![[NSThread currentThread] isCancelled]) {                    //⑤启动runloop               [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];           } }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

①:设置线程的名字,这一步不是必须的,主要是为了debug的时候更方便,可以直接看出这是哪个线程

②:自定义的线程默认是没有runloop的,调用-currentRunLoop,方法内部会为线程创建runloop

③:如果没有数据源,runloop会在启动之后会立刻退出。所以需要给runloop添加一个数据源,这里添加的是NSPort数据源

④:定期检查isCancelled,当外部调用-cancel方法将isCancelled置为YES的时候,线程可以退出

⑤:启动runloop

在耗时操作中再次使用self.thread,这里把耗时操作loadImage扔给它去做:

[self performSelector:@selector(loadImage) onThread:self.thread withObject:nil waitUntilDone:NO] 
  • 1
  • 2
  • 1
  • 2

最后,当你想要结束这个线程的时候,使用CFRunLoopStop()配合-cancel来结束线程:

//在self.thread内部直接调用cancelThread方法 //在其他线程则用[self performSelector:@selector(cancelThread) onThread:self.thread withObject:nil waitUntilDone:NO]   - (void)cancelThread {     [[NSThread currentThread] cancel];     CFRunLoopStop(CFRunLoopGetCurrent()); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

GCD的使用

1️⃣获取一个全局队列

dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  /*     全局队列的四种类型:     DISPATCH_QUEUE_PRIORITY_HIGH     DISPATCH_QUEUE_PRIORITY_DEFAULT     DISPATCH_QUEUE_PRIORITY_LOW     DISPATCH_QUEUE_PRIORITY_BACKGROUND //等待所有比它级别高的队列中的任务执行完或CPU空闲的时候才会执行自己的任务 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

① 创建串行队列/并发队列

//串行队列    dispatch_queue_t serialQueue;    serialQueue = dispatch_queue_create("com.example.SerialQueue", NULL);    //并发队列   dispatch_queue_t concurrentQueue;    concurrentQueue = dispatch_queue_create("com.example.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

②获取主队列

dispatch_queue_t mainQueue; mainQueue = dispatch_get_main_queue();
  • 1
  • 2
  • 1
  • 2

③添加到任务队列执行操作

//异步执行 dispatch_queue_t myCustomQueue; myCustomQueue = dispatch_queue_create("com.example.MyCustomQueue", NULL); dispatch_async(myCustomQueue, ^{     NSLog("Do some work here."); }); //同步执行 dispatch_sync(myCustomQueue, ^{     NSLog("Do some more work here."); });
posted on 2016-11-04 23:32 聂文龙 阅读(248) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理