ios多线程技术

qixiang0 2013-05-07

[size=large]1、简介:

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

1.、NSThread

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

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

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

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

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

NSThread:

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

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

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

Technology

Description

Cocoathreads

CocoaimplementsthreadsusingtheNSThreadclass.CocoaalsoprovidesmethodsonNSObjectforspawningnewthreadsandexecutingcodeonalready-runningthreads.Formoreinformation,see“UsingNSThread”and“UsingNSObjecttoSpawnaThread.”

POSIXthreads

POSIXthreadsprovideaC-basedinterfaceforcreatingthreads.IfyouarenotwritingaCocoaapplication,thisisthebestchoiceforcreatingthreads.ThePOSIXinterfaceisrelativelysimpletouseandoffersampleflexibilityforconfiguringyourthreads.Formoreinformation,see“UsingPOSIXThreads”

MultiprocessingServices

MultiprocessingServicesisalegacyC-basedinterfaceusedbyapplicationstransitioningfromolderversionsofMacOS.ThistechnologyisavailableinOSXonlyandshouldbeavoidedforanynewdevelopment.Instead,youshouldusetheNSThreadclassorPOSIXthreads.Ifyouneedmoreinformationonthistechnology,seeMultiprocessingServicesProgrammingGuide.

一般使用cocoathread技术。

Cocoaoperation

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

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

GCD

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

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

2、NSThread的使用

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

-(id)initWithTarget:(id)targetselector:(SEL)selectorobject:(id)argument

+(void)detachNewThreadSelector:(SEL)aSelectortoTarget:(id)aTargetwithObject:(id)anArgument

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

[cpp]viewplaincopy

1、[NSThreaddetachNewThreadSelector:@selector(doSomething:)toTarget:selfwithObject:nil];

2、NSThread*myThread=[[NSThreadalloc]initWithTarget:self

selector:@selector(doSomething:)

object:nil];

[myThreadstart];

2.2参数的意义:

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

target:selector消息发送的对象

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

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

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

用NSObject的类方法performSelectorInBackground:withObject:创建一个线程:

[ObjperformSelectorInBackground:@selector(doSomething)withObject:nil];

2.4下载图片的例子:

2.4.1新建singeViewapp

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

er.h文件中创建imageViewIBOutlet

ViewController.m中实现:

[cpp]viewplaincopy

//

//ViewController.m

//NSThreadDemo

//

//Createdbyrongfzhon12-9-23.

//Copyright(c)2012年rongfzh.Allrightsreserved.

//

#import"ViewController.h"

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

@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

2.4.2线程间通讯

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

[selfperformSelectorOnMainThread:@selector(updateUI:)withObject:imagewaitUntilDone:YES];

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

用:performSelector:onThread:withObject:waitUntilDone:

运行下载图片:

图片下载下来了。

2.3线程同步

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

.h

[cpp]viewplaincopy

#import<UIKit/UIKit.h>

@classViewController;

@interfaceAppDelegate:UIResponder<UIApplicationDelegate>

{

inttickets;

intcount;

NSThread*ticketsThreadone;

NSThread*ticketsThreadtwo;

NSCondition*ticketsCondition;

NSLock*theLock;

}

@property(strong,nonatomic)UIWindow*window;

@property(strong,nonatomic)ViewController*viewController;

@end

[cpp]viewplaincopy

-(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];发送信号的方式,在一个线程唤醒另外一个线程的等待。

比如:

[cpp]viewplaincopy

#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,加锁并解锁相关代码。

-(void)doSomeThing:(id)anObj

{

@synchronized(anObj)

{

//Everythingbetweenthebracesisprotectedbythe@synchronizeddirective.

}

}

还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习

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

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

相关推荐