天天看點

iOS有三種多線程程式設計的技術

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

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

NSThread:

優點:NSThread 比其他兩個輕量級

缺點:需要自己管理線程的生命周期,線程同步。線程同步對資料的加鎖會有一定的系統開銷

NSThread實作的技術有下面三種:

Technology

Description

Cocoa threads

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 <code>NSThread</code> 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

介紹完這三種多線程程式設計方式,我們這篇先介紹NSThread的使用。

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

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

第一個是執行個體方法,第二個是類方法

1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];  

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

                                        selector:@selector(doSomething:)  

                                        object:nil];  

[myThread start];  

selector :線程執行的方法,這個selector隻能有一個參數,而且不能有傳回值。

target  :selector消息發送的對象

argument:傳輸給target的唯一參數,也可以是nil

第一種方式會直接建立線程并且開始運作線程,第二種方式是先建立線程對象,然後再運作線程操作,在運作線程操作前可以設定線程的優先級等線程資訊

用NSObject的類方法  performSelectorInBackground:withObject: 建立一個線程:

[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];

建立項目,并在xib檔案上放置一個imageView控件。按住control鍵拖到viewControll

er.h檔案中建立imageView IBOutlet 

ViewController.m中實作:

//  

//  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];  

    [thread start];  

- (void)didReceiveMemoryWarning  

    [super didReceiveMemoryWarning];  

    // Dispose of any resources that can be recreated.  

線程下載下傳完圖檔後怎麼通知主線程更新界面呢?

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

performSelectorOnMainThread是NSObject的方法,除了可以更新主線程的資料外,還可以更新其他線程的比如:

用:performSelector:onThread:withObject:waitUntilDone: 

運作下載下傳圖檔:

圖檔下載下傳下來了。

我們示範一個經典的賣票的例子來講NSThread的線程同步:

.h

#import &lt;UIKit/UIKit.h&gt;  

@class ViewController;  

@interface AppDelegate : UIResponder &lt;UIApplicationDelegate&gt;  

    int tickets;  

    int count;  

    NSThread* ticketsThreadone;  

    NSThread* ticketsThreadtwo;  

    NSCondition* ticketsCondition;  

    NSLock *theLock;  

@property (strong, nonatomic) UIWindow *window;  

@property (strong, nonatomic) ViewController *viewController;  

- (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];  

    return YES;  

- (void)run{  

    while (TRUE) {  

        // 上鎖  

//        [ticketsCondition lock];  

        [theLock lock];  

        if(tickets &gt;= 0){  

            [NSThread sleepForTimeInterval:0.09];  

            count = 100 - tickets;  

            NSLog(@"目前票數是:%d,售出:%d,線程名:%@",tickets,count,[[NSThread currentThread] name]);  

            tickets--;  

        }else{  

            break;  

        }  

        [theLock unlock];  

//        [ticketsCondition unlock];  

如果沒有線程同步的lock,賣票數可能是-1.加上lock之後線程同步保證了資料的正确性。

上面例子我使用了兩種鎖,一種NSCondition ,一種是:NSLock。 NSCondition我已經注釋了。

他們都可以通過

        [ticketsCondition signal]; 發送信号的方式,在一個線程喚醒另外一個線程的等待。

比如:

#import "AppDelegate.h"  

@implementation AppDelegate  

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

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

    [ticketsThreadthree start];      

-(void)run3{  

    while (YES) {  

        [ticketsCondition lock];  

        [NSThread sleepForTimeInterval:3];  

        [ticketsCondition signal];  

        [ticketsCondition unlock];  

        [ticketsCondition wait];  

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等等,可以自己看官方文檔學習

本文轉自 卓行天下  51CTO部落格,原文連結:http://blog.51cto.com/9951038/1772539,如需轉載請自行聯系原作者