多线程.docx
- 文档编号:10758338
- 上传时间:2023-02-22
- 格式:DOCX
- 页数:18
- 大小:22.43KB
多线程.docx
《多线程.docx》由会员分享,可在线阅读,更多相关《多线程.docx(18页珍藏版)》请在冰豆网上搜索。
多线程
简介 iOS有三种多线程编程的技术,分别是:
(一)NSThread
(二)CocoaNSOperation (三)GCD(全称:
GrandCentralDispatch)
这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。
三种方式的优缺点介绍:
1)NSThread:
优点:
NSThread比其他两个轻量级 缺点:
需要自己管理线程的生命周期,线程同步。
线程同步对数据的加锁会有一定的系统开销
NSThread实现的技术有下面三种:
Cocoathreads——POSIXthreads——MultiprocessingServices 一般使用cocoathread技术。
CocoaNSOperation 优点:
不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。
Cocoaoperation相关的类是NSOperation,NSOperationQueue。
NSOperation是个抽象类,使用它必须用它的子类,可以实现它或者使用它定义好的两个子类:
NSInvocationOperation和NSBlockOperation。
创建NSOperation子类的对象,把对象添加到NSOperationQueue队列里执行。
GCD GrandCentralDispatch(GCD)是Apple开发的一个多核编程的解决方法。
在iOS4.0开始之后才能使用。
GCD是一个替代诸如NSThread,NSOperationQueue,NSInvocationOperation等技术的很高效和强大的技术。
现在的iOS系统都升级到7了,所以不用担心该技术不能使用。
介绍完这三种多线程编程方式,本文将依次介绍这三种技术的使用。
(一)NSThread的使用 NSThread有两种直接创建方式:
-(id)initWithTarget:
(id)targetselector:
(SEL)selectorobject:
(id)argument
+(void)detachNewThreadSelector:
(SEL)aSelectortoTarget:
(id)aTargetwithObject:
(id)anArgument
第一个是实例方法,第二个是类方法
1、[NSThreaddetachNewThreadSelector:
@selector(doSomething:
)toTarget:
selfwithObject:
nil];
2、NSThread*myThread=[[NSThreadalloc]initWithTarget:
self
selector:
@selector(doSomething:
)
object:
nil];
[myThreadstart];
参数的意义:
selector:
线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
target :
selector消息发送的对象 argument:
传输给target的唯一参数,也可以是nil
第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息
不显式创建线程的方法:
用NSObject的类方法 performSelectorInBackground:
withObject:
创建一个线程:
1
[ObjperformSelectorInBackground:
@selector(doSomething)withObject:
nil];
下载图片的例子:
新建singeViewapp 新建项目,并在xib文件上放置一个imageView控件。
按住control键拖到viewController.h文件中创建imageViewIBOutlet ViewController.m中实现:
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//
// ViewController.m
// NSThreadDemo
//
// Createdbyrongfzhon12-9-23.
// Copyright(c)2012年rongfzh.Allrightsreserved.
//
#import"ViewController.h"
#definekURL@"
@interfaceViewController()
@end
@implementationViewController
-(void)downloadImage:
(NSString*)url{
NSData*data=[[NSDataalloc]initWithContentsOfURL:
[NSURLURLWithString:
url]];
UIImage*image=[[UIImagealloc]initWithData:
data];
if(image==nil){
}else{
[selfperformSelectorOnMainThread:
@selector(updateUI:
)withObject:
imagewaitUntilDone:
YES];
}
}
-(void)updateUI:
(UIImage*)image{
self.imageView.image=image;
}
-(void)viewDidLoad
{
[superviewDidLoad];
// [NSThreaddetachNewThreadSelector:
@selector(downloadImage:
)toTarget:
selfwithObject:
kURL];
NSThread*thread=[[NSThreadalloc]initWithTarget:
selfselector:
@selector(downloadImage:
)object:
kURL];
[threadstart];
}
-(void)didReceiveMemoryWarning
{
[superdidReceiveMemoryWarning];
//Disposeofanyresourcesthatcanberecreated.
}
@end
线程间通讯 线程下载完图片后怎么通知主线程更新界面呢?
1
[selfperformSelectorOnMainThread:
@selector(updateUI:
)withObject:
imagewaitUntilDone:
YES];
performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:
1
performSelector:
onThread:
withObject:
waitUntilDone:
运行下载图片:
线程同步 我们演示一个经典的卖票的例子来讲NSThread的线程同步:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#import
@classViewController;
@interfaceAppDelegate:
UIResponder
{
inttickets;
intcount;
NSThread*ticketsThreadone;
NSThread*ticketsThreadtwo;
NSCondition*ticketsCondition;
NSLock*theLock;
}
@property(strong,nonatomic)UIWindow*window;
@property(strong,nonatomic)ViewController*viewController;
@end
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
-(BOOL)application:
(UIApplication*)applicationdidFinishLaunchingWithOptions:
(NSDictionary*)launchOptions
{
tickets=100;
count=0;
theLock=[[NSLockalloc]init];
//锁对象
ticketsCondition=[[NSConditionalloc]init];
ticketsThreadone=[[NSThreadalloc]initWithTarget:
selfselector:
@selector(run)object:
nil];
[ticketsThreadonesetName:
@"Thread-1"];
[ticketsThreadonestart];
ticketsThreadtwo=[[NSThreadalloc]initWithTarget:
selfselector:
@selector(run)object:
nil];
[ticketsThreadtwosetName:
@"Thread-2"];
[ticketsThreadtwostart];
self.window=[[UIWindowalloc]initWithFrame:
[[UIScreenmainScreen]bounds]];
//Overridepointforcustomizationafterapplicationlaunch.
self.viewController=[[ViewControlleralloc]initWithNibName:
@"ViewController"bundle:
nil];
self.window.rootViewController=self.viewController;
[self.windowmakeKeyAndVisible];
returnYES;
}
-(void)run{
while(TRUE){
//上锁
// [ticketsConditionlock];
[theLocklock];
if(tickets>=0){
[NSThreadsleepForTimeInterval:
0.09];
count=100-tickets;
NSLog(@"当前票数是:
%d,售出:
%d,线程名:
%@",tickets,count,[[NSThreadcurrentThread]name]);
tickets--;
}else{
break;
}
[theLockunlock];
// [ticketsConditionunlock];
}
}
如果没有线程同步的lock,卖票数可能是-1.加上lock之后线程同步保证了数据的正确性。
上面例子我使用了两种锁,一种NSCondition,一种是:
NSLock。
NSCondition我已经注释了。
线程的顺序执行 他们都可以通过[ticketsConditionsignal];发送信号的方式,在一个线程唤醒另外一个线程的等待。
比如:
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#import"AppDelegate.h"
#import"ViewController.h"
@implementationAppDelegate
-(BOOL)application:
(UIApplication*)applicationdidFinishLaunchingWithOptions:
(NSDictionary*)launchOptions
{
tickets=100;
count=0;
theLock=[[NSLockalloc]init];
//锁对象
ticketsCondition=[[NSConditionalloc]init];
ticketsThreadone=[[NSThreadalloc]initWithTarget:
selfselector:
@selector(run)object:
nil];
[ticketsThreadonesetName:
@"Thread-1"];
[ticketsThreadonestart];
ticketsThreadtwo=[[NSThreadalloc]initWithTarget:
selfselector:
@selector(run)object:
nil];
[ticketsThreadtwosetName:
@"Thread-2"];
[ticketsThreadtwostart];
NSThread*ticketsThreadthree=[[NSThreadalloc]initWithTarget:
selfselector:
@selector(run3)object:
nil];
[ticketsThreadthreesetName:
@"Thread-3"];
[ticketsThreadthreestart];
self.window=[[UIWindowalloc]initWithFrame:
[[UIScreenmainScreen]bounds]];
//Overridepointforcustomizationafterapplicationlaunch.
self.viewController=[[ViewControlleralloc]initWithNibName:
@"ViewController"bundle:
nil];
self.window.rootViewController=self.viewController;
[self.windowmakeKeyAndVisible];
returnYES;
}
-(void)run3{
while(YES){
[ticketsConditionlock];
[NSThreadsleepForTimeInterval:
3];
[ticketsConditionsignal];
[ticketsConditionunlock];
}
}
-(void)run{
while(TRUE){
//上锁
[ticketsConditionlock];
[ticketsConditionwait];
[theLocklock];
if(tickets>=0){
[NSThreadsleepForTimeInterval:
0.09];
count=100-tickets;
NSLog(@"当前票数是:
%d,售出:
%d,线程名:
%@",tickets,count,[[NSThreadcurrentThread]name]);
tickets--;
}else{
break;
}
[theLockunlock];
[ticketsConditionunlock];
}
}
wait是等待,我加了一个线程3去唤醒其他两个线程锁中的wait。
其他同步 我们可以使用指令@synchronized来简化NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。
1
2
3
4
5
6
7
-(void)doSomeThing:
(id)anObj
{
@synchronized(anObj)
{
//Everythingbetweenthebracesisprotectedbythe@synchronizeddirective.
}
}
还有其他的一些锁对象,比如:
循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习
NSThread下载图片的例子代码:
(二)CocoaNSOperation的使用 使用NSOperation的方式有两种, 一种是用定义好的两个子类:
NSInvocationOperation和NSBlockOperation。
另一种是继承NSOperation
如果你也熟悉Java,NSOperation就和java.lang.Runnable接口很相似。
和Java的Runnable一样,NSOperation也是设计用来扩展的,只需继承重写NSOperation的一个方法main。
相当与java中Runnalbe的Run方法。
然后把NSOperation子类的对象放入NSOperationQueue队列中,该队列就会启动并开始处理它。
NSInvocationOperation例子:
这里同样,我们实现一个下载图片的例子。
新建一个SingleViewapp,拖放一个ImageView控件到xib界面。
实现代码如下:
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
28
29
30
31
#import"ViewController.h"
#definekURL@"
@interfaceViewController()
@end
@implementationViewController
-(void)viewDidLoad
{
[superviewDidLoad];
NSInvocationOperation*operation=[[NSInvocationOperationalloc]initWithTarget:
self
selector:
@selector(downloadImage:
)
object:
kURL];
NSOperationQueue*queue=[[NSOperationQueuealloc]init];
[queueaddOperation:
operation];
//Doanyadditionalsetupafterloadingtheview,typi
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多线程