• iOS多线程编程之NSThread的使用


    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实现的技术有下面三种: 

    Cocoa threads

    POSIX threads

    Multiprocessing Services

    一般使用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 

    第一个是实例方法,第二个是类方法 

    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

    【编辑推荐】

    【责任编辑:milk TEL:(010)68476606】

     

     

  • 相关阅读:
    进程&多道技术
    linux 三大利器 grep sed awk sed
    linux 三大利器 grep sed awk 正则表达式
    cmd pyhton
    ConfigParser 模块
    几种数据类型的简单概念
    python基础关于字符串的常用操作
    寻租行为
    集约式发展 与 粗放式发展
    最小二乘法
  • 原文地址:https://www.cnblogs.com/hanyis/p/3626002.html
Copyright © 2020-2023  润新知