iOS中的线程的总结和GCD

  进程和线程是操作系统中的概念,以我的理解呢 一个CPU就好比是一个工厂,而一个工厂里面可以有多个车间,一个进程就好比是一个工厂中的一个车间,而线程就好比是车间里的工人,也就是说一个进程中可以有多个线程。

  那么在iOS开发过程中,怎么样开始一个线程呢,有以下三种方法:

  1.performSelectorInBackground

  例如:开启一个线程的方法

  - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg

  2.使用NSThread 静态方法 (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument; 

也就是直接创建了一个线程,SEL参数指是这个线程需要执行的作务, 使用这个方法的话,线程直接启动

  例如:[NSThread detachNewThreadSelector:@selector(doThing) toTarget:self  withObject:nil];

  3.创建NSThread 的对象, 然后调用start来启动线程 

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

  例如:NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(doThing) object:nil];

       thread.name = @"QingYun";

     //启动线程

     [thread start];

 

  知道了怎么创建一个线程,那么怎么样创建一个多线程呢?

  有两种方法可以实现多线程

  1. 先创建NSOperation 子类对象, 然后使用NSOperationQueue来实现多线程 

  使用- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;

  例如:

  

   //创建一个多线程的队列

   NSOperationQueue *queue = [[NSOperationQueue alloc] init];

   //创建一个操作对象,这个操作对象定义了多线程需要执行作务

   NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doThing) object:nil];
   //将操作对象放到这个队列里,这样线程就可以直接启动
    [queue addOperation:operation];

  

2.创建NSBlockOperation对象然后使用NSOperationQueue来实现多线程

 

    

    NSOperationQueue *queue = [[NSOperationQueuealloc] init];

    NSBlockOperation *operation = [NSBlockOperationblockOperationWithBlock:^{

        NSLog(@"do thing....");

        //当前线程休眠10

        [NSThreadsleepForTimeInterval:10];

      NSThread *thread = [NSThread currentThread];//查看当前的进程

        if ([thread isMainThread]) {//判断当前进程是不是主线程

            NSLog(@"main thread");

        }else

        {

            NSLog(@"peer thread");

        }

         NSLog(@"DONE.%@",thread.name);

    }];

    [queue addOperation:operation];

 

  单线程和多线程的使用大家都知道了,我们接下来说一个更好用技术,GCD ,什么是GCD呢?

  Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。该方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术,它看起来象就其它语言的闭包(Closure)一样,但苹果把它叫做blocks。

  让我们来看一个编程场景。在iphone上做一个下载网页的功能,该功能非常简单,就是在iphone上放置一个按钮,点击该按钮时,显示一个转动的圆圈,表示正在进行下载,下载完成之后,将内容加载到界面上的一个文本控件中。如果没有提示会给用户带来不好的用户体验。

  

  GCD就是用来解决这个问题的,dispatch是使用C风格的代码写的。

  //创建一个队列 
dispatch_queue_t queque
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   dispatch_async (queque,
^{ NSLog(@"do thing...."); //当前线程休眠10秒 [NSThread sleepForTimeInterval:5]; NSThread *thread = [NSThread currentThread]; if ([thread isMainThread]) { NSLog(@"main thread"); }else { NSLog(@"peer1 thread"); } NSLog(@"DONE.%@",thread.name); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ NSLog(@"do another thing...."); //当前线程休眠10秒 [NSThread sleepForTimeInterval:5]; NSThread *thread = [NSThread currentThread]; if ([thread isMainThread]) { NSLog(@"main thread"); }else { NSLog(@"peer2 thread"); } NSLog(@"DONE.%@",thread.name); });

  其中,dispatch_get_global_queue(dispatch_queue_priority_t priority,unsignedlong flags);中第一个参数的优先级有如下几种:

   define DISPATCH_QUEUE_PRIORITY_HIGH 2

  #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0

  #define DISPATCH_QUEUE_PRIORITY_LOW (-2)

  #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN

  上述例子中使用的是dispatch_async(dispatch_queue_t queue, dispatch_block_t block),这个方法是异部的,即相当于使用的多线程,多线程的优先级是在程序最开始优先级级别高的会先调用,因为这两个线程都是子线程,有使用的过程中会存在竟争状态。 ,还有一个方法是dispatch_sync(dispatch_queue_t queue, dispatch_block_t block),这个方法模拟的是单线程。

 

程序运行的结果是:

2014-05-15 16:29:54.070 ThreadSample[4465:60b] BUTTON ACTION

2014-05-15 16:29:54.070 ThreadSample[4465:1303] do thing....

2014-05-15 16:29:54.070 ThreadSample[4465:3903] do another thing....

2014-05-15 16:29:59.073 ThreadSample[4465:1303] peer1 thread

2014-05-15 16:29:59.074 ThreadSample[4465:1303] DONE.

2014-05-15 16:29:59.073 ThreadSample[4465:3903] peer2 thread

2014-05-15 16:29:59.075 ThreadSample[4465:3903] DONE.

 

 

  下面来模拟一个从服务器上获取数据的例子:


#import "QYViewController.h"
@interface
QYViewController ()
//在函数中定义的全局变量 @property (weak, nonatomic) IBOutlet UIButton
*buttonStart; @property (weak, nonatomic) IBOutlet UITextView *resultTextView; @property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator; @end
@implementation QYViewController

- (void)viewDidLoad

{

[superviewDidLoad];

}

- (void)didReceiveMemoryWarning

{

    [superdidReceiveMemoryWarning];

    // Dispose of any resources that can be recreated

}

@end

 

  然后在@implementation 和@end之间添加模拟的方法:如下所示:

//模拟从服务器上获取数据
- (NSString*)fetchSomeThingFromServer
{
    [NSThread sleepForTimeInterval:1];
    return @"Hi there";
}

//模拟处理从服务器上取下的数据的过程
- (NSString*)processData:(NSString*)data
{
    [NSThread sleepForTimeInterval:2];
//    主功能是:如果取下的数据是大不写, 全部转换成大写
    return [data uppercaseString];
}

//模拟第一次处理从服务器获取的数据
- (NSString*)calculateFirstResult:(NSString*)data
{
    [NSThread sleepForTimeInterval:3];
    return [NSString stringWithFormat:@"Number of chars: %d",data.length];
}

//模拟第二次处理从服务器取下的值
- (NSString*)calculateSecondResult:(NSString*)data
{
    [NSThread sleepForTimeInterval:4];
//    将字符串data中的所有大写的E字母转换成小写
    return [data stringByReplacingOccurrencesOfString:@"E" withString:@"e"];
}

 

  添加- (IBAction)doSomeWork:(id)sender {


// 计算一下从开始工作, 到结束一共花费了多少CPU的时间 NSDate *startTime = [NSDate date];
//当获取数据的时候将按钮设置为不可点击 self.buttonStart.enabled
= NO; self.buttonStart.alpha = 0.5;
//添加一个风火轮,当获取数据的时候开始转动 [self.activityIndicator startAnimating]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0), ^{

    //以下两个程序的执行顺序不能改变,所以不能使用分组 NSString
*fetchData = [self fetchSomeThingFromServer]; NSString *processData = [self processData:fetchData]; // NSString *firstResult = [self calculateFirstResult:processData]; // NSString *secondResult = [self calculateSecondResult:processData]; // 关于block块的变量作用范围
//     block块中可以使用block块外的变量,但是它使用的时候是把block外的变量拷贝过来当做常量使用,若不想当做就是使用应该在变量定义的时候前面加上__block  
    __block NSString *firstResult; __block NSString *secondResult; // 创建一个group dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ firstResult = [self calculateFirstResult:processData]; NSLog(@"%@",firstResult); }); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ secondResult = [self calculateSecondResult:processData]; NSLog(@"%@",secondResult); }); // 根据计算后的结果, 拼接成新的包含换行的字符串 dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSString *resultSummary = [NSString stringWithFormat:@"First:[%@] \n Second:[%@]",firstResult,secondResult]; // 将计算好的结果的字符串放在我们的界面上。
      //这是需要注意的是所有的关于视图的操作均会在主线程上操作
          dispatch_sync(dispatch_get_main_queue(), ^{ self.resultTextView.text = resultSummary; self.buttonStart.enabled = YES; self.buttonStart.alpha = 1.0f; [self.activityIndicator stopAnimating]; });
      //结束时间必须放在第一个异步的数据块里面,因为使用的异步操作,就相当于是多线程,如果放在外面会直接走下一步,计算不出准确的时间 NSDate
*endTime = [NSDate date]; NSLog(@"Completed in %f seconds",[endTime timeIntervalSinceDate:startTime]); }); }); }

 

  模拟的结果如下:

        

 

 

 

 

posted @ 2014-05-15 17:05  WeBLTogether  阅读(207)  评论(0编辑  收藏  举报