iOS多線程編程之NSThread的使用

一、簡介:

1.1 iOS有三種多線程編程的技術,分別是:

1.、NSThread html

二、Cocoa NSOperation (iOS多線程編程之NSOperation和NSOperationQueue的使用ios

三、GCD  全稱:Grand Central Dispatch( iOS多線程編程之Grand Central Dispatch(GCD)介紹和使用編程

這三種編程方式從上到下,抽象度層次是從低到高的,抽象度越高的使用越簡單,也是Apple最推薦使用的。多線程

這篇咱們主要介紹和使用NSThread,後面會繼續二、3 的講解和使用。app

1.2 三種方式的有缺點介紹:

NSThread:分佈式

優勢:NSThread 比其餘兩個輕量級ide

缺點:須要本身管理線程的生命週期,線程同步。線程同步對數據的加鎖會有必定的系統開銷學習

NSThread實現的技術有下面三種:flex


Technologyui

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的使用。

二、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/原創,歡迎轉載分享。請尊重做者勞動,轉載時保留該聲明和做者博客連接,謝謝!

相關文章
相關標籤/搜索