zoukankan      html  css  js  c++  java
  • 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最推荐使用的。

    1.2 三种方式的优缺点介绍:

    NSThread:

    优点:NSThread 比其他两个轻量级

    缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销

    NSThread实现的技术有下面三种:

    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];  
    [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  
    -(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.  
    }  
    @end   
     

    2.4.2线程间通讯

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

    [self performSelectorOnMainThread:@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我已经注释了。 

    线程的顺序执行

    他们都可以通过   [ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。

    比如:

    #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 @synchronized directive.
        }
    }

    还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习
    转载:http://blog.csdn.net/totogo2010/article/details/8010231

  • 相关阅读:
    C++ Compress Floder
    C语言: 两个int变量相除,结果保留两位小数
    过滤Windows文件名中的非法字符
    判断两个vector是否相等
    顶级操盘手是怎样准确把握入场时机的
    短线黑马选股绝技
    短线黑马选股绝技 一
    每日一招:短线炒股实用技巧
    高抛低吸T+0操作要领(目前行情短线炒作的必备技能)
    如何买开盘即涨停的个股
  • 原文地址:https://www.cnblogs.com/lxlx1798/p/6642924.html
Copyright © 2011-2022 走看看