iOSには3つのマルチスレッドプログラミング手法があります

1はじめに:

1.1 iOSには、次の3つのマルチスレッドプログラミングテクノロジーがあります。 

1.、NSThread

2. Cocoa NSOperation  (iOSマルチスレッドプログラミングでのNSOperationおよびNSOperationQueueの使用) 

3. GCD  正式名称:Grand Central Dispatch(iOSマルチスレッドプログラミング用のGrand Central Dispatch(GCD)の  紹介と使用) 

これらの3つのプログラミング方法は上から下にあり、抽象化のレベルは低から高です。抽象化が高いほど、より使いやすくなります。これは、Appleによって最も推奨されています。 

この記事では、主にNSThreadを紹介して使用しますが、2と3については後で説明して使用します。 

1.2 3つの方法の長所と短所の紹介: 

NSThread: 

利点:NSThreadは他の2つよりも軽い 

欠点:スレッドのライフサイクルを自分で管理する必要があり、スレッドは同期されます。スレッドの同期には、データロックのための特定のシステムオーバーヘッドがあります。 

NSThreadによって実装される3つのテクノロジーがあります: 

ココアスレッド 

POSIXスレッド 

マルチプロセッシングサービス

通常、カカオ糸技術を使用します。

ココア作戦 

利点:スレッド管理やデータ同期を気にする必要がなく、実行する必要のある操作に集中できます。 

Cocoaオペレーションに関連するクラスは、NSOperationとNSOperationQueueです。NSOperationは抽象クラスです。使用するには、そのサブクラスを使用する必要があります。実装するか、定義された2つのサブクラスNSInvocationOperationとNSBlockOperationを使用できます。NSOperationサブクラスのオブジェクトを作成し、そのオブジェクトをNSOperationQueueに追加して実行します。 

GCD

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

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

2、NSThread的使用 

2.1 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];  
  3. [myThread start]; 

2.2参数的意义: 

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

target  :selector消息发送的对象 

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

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

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

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

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

2.4 下载图片的例子: 

2.4.1  新建singeView app 

新建项目,并在xib文件上放置一个imageView控件。按住control键拖到viewController.h文件中创建imageView IBOutlet  ViewController.m中实现: 

 
  
  1. //  ViewController.m    
  2. //  NSThreadDemo    
  3. //    
  4. //  Created by rongfzh on 12-9-23.    
  5. //  Copyright (c) 2012年 rongfzh. All rights reserved.    
  6. //    
  7. #import "ViewController.h"    
  8. #define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"    
  9. @interface ViewController ()    
  10. @end    
  11. @implementation ViewController    
  12. d)downloadImage:(NSString *) url{    
  13.     NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];    
  14.     UIImage *image = [[UIImage alloc]initWithData:data];    
  15.     if(image == nil){    
  16.     }else{    
  17.         [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];    
  18.     }    
  19. }    
  20. d)updateUI:(UIImage*) image{    
  21.     self.imageView.image = image;    
  22. }    
  23. - (void)viewDidLoad    
  24. {    
  25.     [super viewDidLoad];    
  26. //    [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];    
  27.     NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];    
  28.     [thread start];    
  29. }    
  30. - (void)didReceiveMemoryWarning    
  31. {    
  32.     [super didReceiveMemoryWarning];    
  33.     // Dispose of any resources that can be recreated.    
  34. }    
  35. @end    

2.4.2线程间通讯 

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

 
 
  1. [selfperformSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES]; 

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

用:performSelector:onThread:withObject:waitUntilDone:  

运行下载图片:

图片下载下来了。 

2.3 线程同步 

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

 .h 

 
  
  1. #import <UIKit/UIKit.h>    
  2. @class ViewController;    
  3. @interface AppDelegate : UIResponder <UIApplicationDelegate>    
  4. {    
  5.     int tickets;    
  6.     int count;    
  7.     NSThread* ticketsThreadone;    
  8.     NSThread* ticketsThreadtwo;    
  9.     NSCondition* ticketsCondition;   
  10.     NSLock *theLock;    
  11. }    
  12. @property (strong, nonatomic) UIWindow *window;    
  13. @property (strong, nonatomic) ViewController *viewController;    
  14. @end    

 
  
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions    
  2.      {    
  3.          tickets = 100;    
  4.          count = 0;    
  5.          theLock = [[NSLock alloc] init];    
  6.          // 锁对象    
  7.          ticketsCondition = [[NSCondition alloc] init];    
  8.          ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];    
  9.          [ticketsThreadone setName:@"Thread-1"];    
  10.          [ticketsThreadone start];    
  11.          ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];    
  12.          [ticketsThreadtwo setName:@"Thread-2"];    
  13.          [ticketsThreadtwo start];    
  14.          self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];    
  15.          // Override point for customization after application launch.    
  16.          self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];    
  17.          self.window.rootViewController = self.viewController;    
  18.          [self.window makeKeyAndVisible];    
  19.          return YES;    
  20.      }    
  21.      - (void)run{    
  22.          while (TRUE) {    
  23.              // 上锁    
  24.      //        [ticketsCondition lock];    
  25.              [theLock lock];    
  26.              if(tickets >= 0){    
  27.                  [NSThread sleepForTimeInterval:0.09];    
  28.                  count = 100 - tickets;    
  29.                  NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);    
  30.                  tickets--;    
  31.              }else{    
  32.                  break;    
  33.              }    
  34.              [theLock unlock];    
  35.      //        [ticketsCondition unlock];    
  36.          }    
  37.      }    

如果没有线程同步的lock,卖票数可能是-1.加上lock之后线程同步保证了数据的正确性。
上面例子我使用了两种锁,一种NSCondition ,一种是:NSLock。 NSCondition我已经注释了。

线程的顺序执行 

他们都可以通过 

[ticketsConditionsignal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。

比如:

 
  
  1. #import "AppDelegate.h"    
  2. #import "ViewController.h"    
  3. @implementation AppDelegate    
  4. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions    
  5.  {    
  6.      tickets = 100;    
  7.      count = 0;    
  8.      theLock = [[NSLock alloc] init];    
  9.      // 锁对象    
  10.      ticketsCondition = [[NSCondition alloc] init];    
  11.      ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];    
  12.      [ticketsThreadone setName:@"Thread-1"];    
  13.      [ticketsThreadone start];    
  14.      ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];    
  15.      [ticketsThreadtwo setName:@"Thread-2"];    
  16.      [ticketsThreadtwo start];    
  17.      NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];    
  18.      [ticketsThreadthree setName:@"Thread-3"];    
  19.      [ticketsThreadthree start];        
  20.      self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];    
  21.  
  22.      // Override point for customization after application launch.    
  23.      self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];    
  24.      self.window.rootViewController = self.viewController;    
  25.      [self.window makeKeyAndVisible];    
  26.      return YES;    
  27.  }    
  28.  -(void)run3{    
  29.      while (YES) {    
  30.          [ticketsCondition lock];    
  31.          [NSThread sleepForTimeInterval:3];    
  32.          [ticketsCondition signal];    
  33.          [ticketsCondition unlock];    
  34.      }   
  35.  }    
  36.  - (void)run{    
  37.      while (TRUE) {    
  38.          // 上锁    
  39.          [ticketsCondition lock];    
  40.          [ticketsCondition wait];    
  41.          [theLock lock];    
  42.          if(tickets >= 0){    
  43.              [NSThread sleepForTimeInterval:0.09];    
  44.              count = 100 - tickets;    
  45.              NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);    
  46.              tickets--;    
  47.          }else{    
  48.              break;    
  49.          }    
  50.          [theLock unlock];    
  51.          [ticketsCondition unlock];    
  52.      }    
  53.  }    

wait是等待,我加了一个 线程3 去唤醒其他两个线程锁中的wait

其他同步

我们可以使用指令@synchronized来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。

 
 
  1. - (void)doSomeThing:(id)anObj 
  2.     @synchronized(anObj) 
  3.     { 
  4.         // Everything between the braces is protected by the@synchronizeddirective. 
  5.     } 


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

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


おすすめ

転載: blog.csdn.net/qq_27740983/article/details/50072901