当前位置:首页>优优资讯 > 软件教程 > 电脑软件教程 > iOS开发:多线程编程之NSThread的使用详解

iOS开发:多线程编程之NSThread的使用详解

作者:本站整理 时间:2015-08-31


  1、简介:
 
  1.1 iOS有三种多线程编程的技术,分别是:
 
  1.、NSThread
 
  2、Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的使用)
 
  3、GCD  全称:Grand Central Dispatch( iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用)
 
  这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。
 
  这篇我们主要介绍和使用NSThread,后面会继续2、3 的讲解和使用。
 
  1.2 三种方式的优缺点介绍:
 
  NSThread:
 
  优点:NSThread 比其他两个轻量级
 
  缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销
 
  NSThread实现的技术有下面三种:
 
iOS开发:多线程编程之NSThread的使用详解
 
  一般使用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的使用。
 
  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
 
  第一个是实例方法,第二个是类方法
 
  [NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
  NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:)  object:nil];
  [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键拖到viewController.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
  d)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];
  }
  }
  d)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.
  }
  @end
 
  2.4.2线程间通讯
 
  线程下载完图片后怎么通知主线程更新界面呢?
 
  [selfperformSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
 
  performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:
 
  用:performSelector:onThread:withObject:waitUntilDone:
 
  运行下载图片:

 
  图片下载下来了。
 
  2.3 线程同步
 
  我们演示一个经典的卖票的例子来讲NSThread的线程同步:
 
  .h
  #import <UIKit/UIKit.h>
  @class ViewController;
  @interface AppDelegate : UIResponder <UIApplicationDelegate>
  {
  int tickets;
  int count;
  NSThread* ticketsThreadone;
  NSThread* ticketsThreadtwo;
  NSCondition* ticketsCondition;
  NSLock *theLock;
  }
  @property (strong, nonatomic) UIWindow *window;
  @property (strong, nonatomic) ViewController *viewController;
  @end
 
  - (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 >= 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我已经注释了。
 
  线程的顺序执行
 
  他们都可以通过
 
  [ticketsConditionsignal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。
 
  比如:
 
  #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];
  return YES;
  }
  -(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,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
  tickets--;
  }else{
  break;
  }
  [theLock unlock];
  [ticketsCondition unlock];
  }
  }
 
  wait是等待,我加了一个 线程3 去唤醒其他两个线程锁中的wait
 
  其他同步
 
  我们可以使用指令@synchronized来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。
 
  - (void)doSomeThing:(id)anObj
  {
  @synchronized(anObj)
  {
  // Everything between the braces is protected by the@synchronizeddirective.
  }
  }
 
  还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习
 
  NSThread下载图片的例子代码:http://download.csdn.net/detail/totogo2010/4591149
 

相关文章

相关推荐

最新攻略

用户评论

(已有0条评论)
表情
注:您的评论需要经过审核才能显示哦,请文明发言!
还没有评论,快来抢沙发吧!