1礁阁、簡介:
1.1 iOS有三種多線程編程的技術(shù)猎塞,分別是:
1.诗舰、NSThread
2、Cocoa NSOperation(iOS多線程編程之NSOperation和NSOperationQueue的使用)
3竿奏、GCD全稱:Grand Central Dispatch(iOS多線程編程之Grand Central Dispatch(GCD)介紹和使用)
這三種編程方式從上到下,抽象度層次是從低到高的腥放,抽象度越高的使用越簡單泛啸,也是Apple最推薦使用的。
這篇我們主要介紹和使用NSThread秃症,后面會繼續(xù)2候址、3 的講解和使用吕粹。
NSThread:
優(yōu)點(diǎn):NSThread 比其他兩個輕量級
缺點(diǎn):需要自己管理線程的生命周期,線程同步岗仑。線程同步對數(shù)據(jù)的加鎖會有一定的系統(tǒng)開銷
NSThread實(shí)現(xiàn)的技術(shù)有下面三種:
Technology
Description
Cocoa threads
Cocoa implements threads using theNSThreadclass. Cocoa also provides methods onNSObjectfor 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 theNSThreadclass or POSIX threads. If you need more information on this technology, seeMultiprocessing Services Programming Guide.
一般使用cocoa thread 技術(shù)匹耕。
Cocoa operation
優(yōu)點(diǎn):不需要關(guān)心線程管理,數(shù)據(jù)同步的事情荠雕,可以把精力放在自己需要執(zhí)行的操作上稳其。
Cocoa operation 相關(guān)的類是?NSOperation ,NSOperationQueue炸卑。NSOperation是個抽象類既鞠,使用它必須用它的子類,可以實(shí)現(xiàn)它或者使用它定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation盖文。創(chuàng)建NSOperation子類的對象嘱蛋,把對象添加到NSOperationQueue隊(duì)列里執(zhí)行。
GCD
Grand Central Dispatch (GCD)是Apple開發(fā)的一個多核編程的解決方法五续。在iOS4.0開始之后才能使用洒敏。GCD是一個替代諸如NSThread, NSOperationQueue, NSInvocationOperation等技術(shù)的很高效和強(qiáng)大的技術(shù)。現(xiàn)在的iOS系統(tǒng)都升級到6了疙驾,所以不用擔(dān)心該技術(shù)不能使用凶伙。
介紹完這三種多線程編程方式,我們這篇先介紹NSThread的使用荆萤。
2.1 NSThread 有兩種直接創(chuàng)建方式:
- (id)initWithTarget:(id)targetselector:(SEL)selectorobject:(id)argument
+ (void)detachNewThreadSelector:(SEL)aSelectortoTarget:(id)aTargetwithObject:(id)anArgument
第一個是實(shí)例方法,第二個是類方法
[cpp]view plaincopy
1链韭、[NSThread?detachNewThreadSelector:@selector(doSomething:)?toTarget:self?withObject:nil];
2偏竟、NSThread*?myThread?=?[[NSThread?alloc]?initWithTarget:self
selector:@selector(doSomething:)
object:nil];
[myThread?start];
selector :線程執(zhí)行的方法,這個selector只能有一個參數(shù)敞峭,而且不能有返回值踊谋。
target ?:selector消息發(fā)送的對象
argument:傳輸給target的唯一參數(shù),也可以是nil
第一種方式會直接創(chuàng)建線程并且開始運(yùn)行線程旋讹,第二種方式是先創(chuàng)建線程對象殖蚕,然后再運(yùn)行線程操作,在運(yùn)行線程操作前可以設(shè)置線程的優(yōu)先級等線程信息
用NSObject的類方法 ?performSelectorInBackground:withObject: 創(chuàng)建一個線程:
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
新建項(xiàng)目沉迹,并在xib文件上放置一個imageView控件睦疫。按住control鍵拖到viewControll
er.h文件中創(chuàng)建imageView IBOutlet
ViewController.m中實(shí)現(xiàn):
[cpp]view plaincopy
//
//??ViewController.m
//??NSThreadDemo
//
//??Created?by?rongfzh?on?12-9-23.
//??Copyright?(c)?2012年?rongfzh.?All?rights?reserved.
//
#import?"ViewController.h"
#define?kURL?@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"
@interface?ViewController?()
@end
@implementation?ViewController
-(void)downloadImage:(NSString?*)?url{
NSData?*data?=?[[NSData?alloc]?initWithContentsOfURL:[NSURL?URLWithString:url]];
UIImage?*image?=?[[UIImage?alloc]initWithData:data];
if(image?==?nil){
}else{
[self?performSelectorOnMainThread:@selector(updateUI:)?withObject:image?waitUntilDone:YES];
}
}
-(void)updateUI:(UIImage*)?image{
self.imageView.image?=?image;
}
-?(void)viewDidLoad
{
[super?viewDidLoad];
//????[NSThread?detachNewThreadSelector:@selector(downloadImage:)?toTarget:self?withObject:kURL];
NSThread?*thread=?[[NSThread?alloc]initWithTarget:self?selector:@selector(downloadImage:)?object:kURL];
[threadstart];
}
-?(void)didReceiveMemoryWarning
{
[super?didReceiveMemoryWarning];
//?Dispose?of?any?resources?that?can?be?recreated.
}
@end
線程下載完圖片后怎么通知主線程更新界面呢?
[selfperformSelectorOnMainThread:@selector(updateUI:)withObject:imagewaitUntilDone:YES];
performSelectorOnMainThread是NSObject的方法鞭呕,除了可以更新主線程的數(shù)據(jù)外蛤育,還可以更新其他線程的比如:
用:performSelector:onThread:withObject:waitUntilDone:
運(yùn)行下載圖片:
圖片下載下來了。
我們演示一個經(jīng)典的賣票的例子來講NSThread的線程同步:
.h
[cpp]view plaincopy
#import?
@classViewController;
@interface?AppDelegate?:?UIResponder?
{
inttickets;
intcount;
NSThread*?ticketsThreadone;
NSThread*?ticketsThreadtwo;
NSCondition*?ticketsCondition;
NSLock?*theLock;
}
@property?(strong,?nonatomic)?UIWindow?*window;
@property?(strong,?nonatomic)?ViewController?*viewController;
@end
[cpp]view plaincopy
-?(BOOL)application:(UIApplication?*)application?didFinishLaunchingWithOptions:(NSDictionary?*)launchOptions
{
tickets?=?100;
count?=?0;
theLock?=?[[NSLock?alloc]?init];
//?鎖對象
ticketsCondition?=?[[NSCondition?alloc]?init];
ticketsThreadone?=?[[NSThread?alloc]?initWithTarget:self?selector:@selector(run)?object:nil];
[ticketsThreadone?setName:@"Thread-1"];
[ticketsThreadone?start];
ticketsThreadtwo?=?[[NSThread?alloc]?initWithTarget:self?selector:@selector(run)?object:nil];
[ticketsThreadtwo?setName:@"Thread-2"];
[ticketsThreadtwo?start];
self.window?=?[[UIWindow?alloc]?initWithFrame:[[UIScreen?mainScreen]?bounds]];
//?Override?point?for?customization?after?application?launch.
self.viewController?=?[[ViewController?alloc]?initWithNibName:@"ViewController"bundle:nil];
self.window.rootViewController?=?self.viewController;
[self.window?makeKeyAndVisible];
returnYES;
}
-?(void)run{
while(TRUE)?{
//?上鎖
//????????[ticketsCondition?lock];
[theLock?lock];
if(tickets?>=?0){
[NSThread?sleepForTimeInterval:0.09];
count?=?100?-?tickets;
NSLog(@"當(dāng)前票數(shù)是:%d,售出:%d,線程名:%@",tickets,count,[[NSThread?currentThread]?name]);
tickets--;
}else{
break;
}
[theLock?unlock];
//????????[ticketsCondition?unlock];
}
}
如果沒有線程同步的lock,賣票數(shù)可能是-1.加上lock之后線程同步保證了數(shù)據(jù)的正確性瓦糕。
上面例子我使用了兩種鎖底洗,一種NSCondition ,一種是:NSLock咕娄。 NSCondition我已經(jīng)注釋了亥揖。
他們都可以通過
[ticketsConditionsignal]; 發(fā)送信號的方式,在一個線程喚醒另外一個線程的等待圣勒。
比如:
[cpp]view plaincopy
#import?"AppDelegate.h"
#import?"ViewController.h"
@implementation?AppDelegate
-?(BOOL)application:(UIApplication?*)application?didFinishLaunchingWithOptions:(NSDictionary?*)launchOptions
{
tickets?=?100;
count?=?0;
theLock?=?[[NSLock?alloc]?init];
//?鎖對象
ticketsCondition?=?[[NSCondition?alloc]?init];
ticketsThreadone?=?[[NSThread?alloc]?initWithTarget:self?selector:@selector(run)?object:nil];
[ticketsThreadone?setName:@"Thread-1"];
[ticketsThreadone?start];
ticketsThreadtwo?=?[[NSThread?alloc]?initWithTarget:self?selector:@selector(run)?object:nil];
[ticketsThreadtwo?setName:@"Thread-2"];
[ticketsThreadtwo?start];
NSThread?*ticketsThreadthree?=?[[NSThread?alloc]?initWithTarget:self?selector:@selector(run3)?object:nil];
[ticketsThreadthree?setName:@"Thread-3"];
[ticketsThreadthree?start];
self.window?=?[[UIWindow?alloc]?initWithFrame:[[UIScreen?mainScreen]?bounds]];
//?Override?point?for?customization?after?application?launch.
self.viewController?=?[[ViewController?alloc]?initWithNibName:@"ViewController"bundle:nil];
self.window.rootViewController?=?self.viewController;
[self.window?makeKeyAndVisible];
returnYES;
}
-(void)run3{
while(YES)?{
[ticketsCondition?lock];
[NSThread?sleepForTimeInterval:3];
[ticketsCondition?signal];
[ticketsCondition?unlock];
}
}
-?(void)run{
while(TRUE)?{
//?上鎖
[ticketsCondition?lock];
[ticketsCondition?wait];
[theLock?lock];
if(tickets?>=?0){
[NSThread?sleepForTimeInterval:0.09];
count?=?100?-?tickets;
NSLog(@"當(dāng)前票數(shù)是:%d,售出:%d,線程名:%@",tickets,count,[[NSThread?currentThread]?name]);
tickets--;
}else{
break;
}
[theLock?unlock];
[ticketsCondition?unlock];
}
}
wait是等待费变,我加了一個 線程3 去喚醒其他兩個線程鎖中的wait
我們可以使用指令 @synchronized 來簡化 NSLock的使用,這樣我們就不必顯示編寫創(chuàng)建NSLock,加鎖并解鎖相關(guān)代碼灾而。
- (void)doSomeThing:(id)anObj
{
@synchronized(anObj)
{
// Everything between the braces is protected by the @synchronized directive.
}
}
還有其他的一些鎖對象胡控,比如:循環(huán)鎖NSRecursiveLock,條件鎖NSConditionLock旁趟,分布式鎖NSDistributedLock等等,可以自己看官方文檔學(xué)習(xí)
NSThread下載圖片的例子代碼:http://download.csdn.net/detail/totogo2010/4591149
著作權(quán)聲明:本文由http://blog.csdn.net/totogo2010/原創(chuàng)昼激,歡迎轉(zhuǎn)載分享。請尊重作者勞動锡搜,轉(zhuǎn)載時保留該聲明和作者博客鏈接橙困,謝謝!