文档章节

iOS多线程编程之NSThread的使用

浪子艾菲儿
 浪子艾菲儿
发布于 2013/05/02 10:53
字数 1690
阅读 860
收藏 13

1、简介:

1.1 iOS有三种多线程编程的技术,分别是:

1.、NSThread 

2、Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的使用

3、GCD  全称:Grand Central Dispatch( iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。

这篇我们主要介绍和使用NSThread,后面会继续2、3 的讲解和使用。

1.2 三种方式的有缺点介绍:

NSThread:

优点:NSThread 比其他两个轻量级

缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销

NSThread实现的技术有下面三种:


Technology

Description

Cocoa threads

Cocoa implements threads using the NSThread class. Cocoa also provides methods on NSObject for spawning new threads and executing code on already-running threads. For more information, see “Using NSThread” and “Using NSObject to Spawn a Thread.”

POSIX threads

POSIX threads provide a C-based interface for creating threads. If you are not writing a Cocoa application, this is the best choice for creating threads. The POSIX interface is relatively simple to use and offers ample flexibility for configuring your threads. For more information, see “Using POSIX Threads”

Multiprocessing Services

Multiprocessing Services is a legacy C-based interface used by applications transitioning from older versions of Mac OS. This technology is available in OS X only and should be avoided for any new development. Instead, you should use the NSThread class or POSIX threads. If you need more information on this technology, see Multiprocessing Services Programming Guide.

一般使用cocoa thread 技术。


Cocoa operation 

优点:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。

Cocoa operation 相关的类是 NSOperation ,NSOperationQueue。NSOperation是个抽象类,使用它必须用它的子类,可以实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。创建NSOperation子类的对象,把对象添加到NSOperationQueue队列里执行。

GCD

Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。在iOS4.0开始之后才能使用。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。现在的iOS系统都升级到6了,所以不用担心该技术不能使用。


介绍完这三种多线程编程方式,我们这篇先介绍NSThread的使用。

2、NSThread的使用

2.1 NSThread 有两种直接创建方式:

- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument

+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument

第一个是实例方法,第二个是类方法

[cpp]  view plain copy

1 [NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil]; 
2 NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:)  object:nil]; 
3 [myThread start];

2.2参数的意义:

selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。

target  :selector消息发送的对象

argument:传输给target的唯一参数,也可以是nil

第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息

2.3 PS:不显式创建线程的方法:

用NSObject的类方法  performSelectorInBackground:withObject: 创建一个线程:
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];

2.4 下载图片的例子:

2.4.1  新建singeView app

新建项目,并在xib文件上放置一个imageView控件。按住control键拖到viewControll

er.h文件中创建imageView IBOutlet 

ViewController.m中实现:

[cpp]        view plain       copy  

  1. //  

  2. //  ViewController.m  

  3. //  NSThreadDemo  

  4. //  

  5. //  Created by rongfzh on 12-9-23.  

  6. //  Copyright (c) 2012年 rongfzh. All rights reserved.  

  7. //  

  8.   

  9. #import "ViewController.h"  

  10. #define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"  

  11. @interface ViewController ()  

  12.   

  13. @end  

  14.   

  15. @implementation ViewController  

  16.   

  17. -(void)downloadImage:(NSString *) url{  

  18.     NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];  

  19.     UIImage *image = [[UIImage alloc]initWithData:data];  

  20.     if(image == nil){  

  21.           

  22.     }else{  

  23.         [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];  

  24.     }  

  25. }  

  26.   

  27. -(void)updateUI:(UIImage*) image{  

  28.     self.imageView.image = image;  

  29. }  

  30.   

  31.   

  32. - (void)viewDidLoad  

  33. {  

  34.     [super viewDidLoad];  

  35.       

  36. //    [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];  

  37.     NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];  

  38.     [thread start];  

  39. }  

  40.   

  41. - (void)didReceiveMemoryWarning  

  42. {  

  43.     [super didReceiveMemoryWarning];  

  44.     // Dispose of any resources that can be recreated.  

  45. }  

  46.   

  47. @end  

2.4.2线程间通讯

线程下载完图片后怎么通知主线程更新界面呢?

[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];

performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:

用:performSelector:onThread:withObject:waitUntilDone: 

运行下载图片:

图片下载下来了。

2.3 线程同步

我们演示一个经典的卖票的例子来讲NSThread的线程同步:

.h

[cpp]        view plain       copy  

  1. #import <UIKit/UIKit.h>  

  2.   

  3. @class ViewController;  

  4.   

  5. @interface AppDelegate : UIResponder <UIApplicationDelegate>  

  6. {  

  7.     int tickets;  

  8.     int count;  

  9.     NSThread* ticketsThreadone;  

  10.     NSThread* ticketsThreadtwo;  

  11.     NSCondition* ticketsCondition;  

  12.     NSLock *theLock;  

  13. }  

  14. @property (strong, nonatomic) UIWindow *window;  

  15.   

  16. @property (strong, nonatomic) ViewController *viewController;  

  17.   

  18. @end  

[cpp]        view plain       copy  

  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  

  2. {  

  3.       

  4.     tickets = 100;  

  5.     count = 0;  

  6.     theLock = [[NSLock alloc] init];  

  7.     // 锁对象  

  8.     ticketsCondition = [[NSCondition alloc] init];  

  9.     ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  

  10.     [ticketsThreadone setName:@"Thread-1"];  

  11.     [ticketsThreadone start];  

  12.       

  13.       

  14.     ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  

  15.     [ticketsThreadtwo setName:@"Thread-2"];  

  16.     [ticketsThreadtwo start];  

  17.       

  18.     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  

  19.     // Override point for customization after application launch.  

  20.     self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];  

  21.     self.window.rootViewController = self.viewController;  

  22.     [self.window makeKeyAndVisible];  

  23.     return YES;  

  24. }  

  25.   

  26. - (void)run{  

  27.     while (TRUE) {  

  28.         // 上锁  

  29. //        [ticketsCondition lock];  

  30.         [theLock lock];  

  31.         if(tickets >= 0){  

  32.             [NSThread sleepForTimeInterval:0.09];  

  33.             count = 100 - tickets;  

  34.             NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);  

  35.             tickets--;  

  36.         }else{  

  37.             break;  

  38.         }  

  39.         [theLock unlock];  

  40. //        [ticketsCondition unlock];  

  41.     }  

  42. }  

如果没有线程同步的lock,卖票数可能是-1.加上lock之后线程同步保证了数据的正确性。 
上面例子我使用了两种锁,一种NSCondition ,一种是:NSLock。 NSCondition我已经注释了。

线程的顺序执行

他们都可以通过

        [ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。

比如:

[cpp]        view plain       copy  

  1. #import "AppDelegate.h"  

  2.   

  3. #import "ViewController.h"  

  4.   

  5. @implementation AppDelegate  

  6.   

  7. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  

  8. {  

  9.       

  10.     tickets = 100;  

  11.     count = 0;  

  12.     theLock = [[NSLock alloc] init];  

  13.     // 锁对象  

  14.     ticketsCondition = [[NSCondition alloc] init];  

  15.     ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  

  16.     [ticketsThreadone setName:@"Thread-1"];  

  17.     [ticketsThreadone start];  

  18.       

  19.     ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  

  20.     [ticketsThreadtwo setName:@"Thread-2"];  

  21.     [ticketsThreadtwo start];  

  22.       

  23.     NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];  

  24.     [ticketsThreadthree setName:@"Thread-3"];  

  25.     [ticketsThreadthree start];      

  26.     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  

  27.     // Override point for customization after application launch.  

  28.     self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];  

  29.     self.window.rootViewController = self.viewController;  

  30.     [self.window makeKeyAndVisible];  

  31.     return YES;  

  32. }  

  33.   

  34. -(void)run3{  

  35.     while (YES) {  

  36.         [ticketsCondition lock];  

  37.         [NSThread sleepForTimeInterval:3];  

  38.         [ticketsCondition signal];  

  39.         [ticketsCondition unlock];  

  40.     }  

  41. }  

  42.   

  43. - (void)run{  

  44.     while (TRUE) {  

  45.         // 上锁  

  46.         [ticketsCondition lock];  

  47.         [ticketsCondition wait];  

  48.         [theLock lock];  

  49.         if(tickets >= 0){  

  50.             [NSThread sleepForTimeInterval:0.09];  

  51.             count = 100 - tickets;  

  52.             NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);  

  53.             tickets--;  

  54.         }else{  

  55.             break;  

  56.         }  

  57.         [theLock unlock];  

  58.         [ticketsCondition unlock];  

  59.     }  

  60. }  

wait是等待,我加了一个 线程3 去唤醒其他两个线程锁中的wait 

其他同步

我们可以使用指令 @synchronized  来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。
- (void)doSomeThing:(id)anObj
{
    @synchronized(anObj)
    {
        // Everything between the braces is protected by the @synchronized  directive.
    }
}
还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习

NSThread下载图片的例子代码:http://download.csdn.net/detail/totogo2010/4591149

著作权声明:本文由http://blog.csdn.net/totogo2010/原创,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

本文转载自:http://blog.csdn.net/totogo2010/

上一篇: 一个简单的单例
下一篇: NSOperation 应用
浪子艾菲儿
粉丝 45
博文 49
码字总数 13001
作品 0
海淀
程序员
私信 提问
iOS多线程编程之一——NSThread线程管理

iOS多线程编程之一——NSThread线程管理 NSTread是iOS中进行多线程开发的一个类,其结构逻辑清晰,使用十分方便,但其封装度和性能不高,线程周期,加锁等需要手动处理。 一、NSThread类方法...

珲少
2015/05/19
931
2
关于iOS多线程,这边勉强可以看看(OC&Swift)

iOS开发多线程总是绕不过的坎,看了很多前辈们优秀的文章,如:关于iOS多线程,我说,你听,没准你就懂了!、谈iOS多线程(NSThread、NSOperation、GCD)编程、iOS多线程:『GCD』详尽总结、i...

Andy_Ron
2018/08/26
0
0
iOS多线程编程之NSThread的使用

iOS多线程编程之NSThread的使用 1、简介: 1.1 iOS有三种多线程编程的技术,分别是: 1.、NSThread 2、Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的使用) 3、GCD 全...

malawo
2013/09/05
20
0
iOS开发 多线程(二) NSThread的使用(转)

每个iOS应用程序都有个专门用来更新显示UI界面、处理用户的触摸事件的主线程,因此不能将其他太耗时的操作放在主线程中执行,不然会造成主线程堵塞(出现卡机现象),带来极坏的用户体验。一般...

神补刀
2015/08/18
657
0
iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用 目录(?)[+] 介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理...

malawo
2013/09/05
42
0

没有更多内容

加载失败,请刷新页面

加载更多

Sqoop之导入Mysql数据到Hive出现ASCII

问题是这样的,从Mysql中导入数据到Hive中,Mysql中数据是"T2",到Hive中后,发现变为"54 32",咦,怎么乱码了,感觉这像ASCII编码。 现象有了,之前都没遇到过这样,觉得很奇怪,迅速找了下...

克虏伯
10分钟前
2
0
深度科技受邀参加鲲鹏计算产业峰会·海南

10月22日,华为及生态伙伴共同举办了以“鲲鹏展翅,力算未来 共赢多样性计算时代”为主题的“鲲鹏计算产业峰会•海南”,来自各领域的300多名行业客户、专家及生态伙伴齐聚一堂,共同分享计算...

后浪涛涛
12分钟前
3
0
【Android JetPack系列】LifeCycles

一、简介 Lifecycles 是一个持有组件生命周期状态(如活动或片段)信息的类,并允许其他对象观察此状态。 生命周期使用两个主要枚举来跟踪其关联组件的生命周期状态: Event:从 框架 和 Li...

Agnes2017
13分钟前
2
0
配置码云git自动更新的webhook

配置项目提交到git的时候自动同步服务器代码 一、在服务器项目跟目录新建文件hook.php 代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 <?php $json = file_get_contents("php://input"); $data ......

dragon_tech
19分钟前
2
0
一道题深度剖析this指向

< script > var num = 1 ; var myObject = { num : 2 , add : function (){ this . num = 3 ; ( function (){ // 这里的 this 是 window,因为自调用函数的调用者是windo,使用箭头函数则指向......

李超明
23分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部