ios 多线程开关,有关线程的一些用法和详细讲解,NSThread , NSOperation ,Grand Central Dispatch ( GCD )

IOS支持的多线程技术:

一、Thread:

1)显式创建线程:NSThreed

2)隐式创建线程:NSObject

二、Cocoa operations:

NSOperation类是一个抽象类,因为我们必须使用它的两个子类。

  1)NSInvocationOperation

2)NSBlockOperation

————————————————————————————

3)NSOperationQueue(继承于NSObject)

三、Grand Central Dispatch (GCD):

1)GCD的创建

2)重复执行线程:dispatch_apply

3)操作(串行)队列:dispatch_queue_create

4)GCD群组通知:dispatch_group_t

5)GCD实现计时器

以上三种多线程技术的对比:

一、Thread: 

优点:量级较轻。

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

二、Cocoa operations:

优点:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。

三、Grand Central Dispatch (GCD):

优点:GCD基于C语言的框架,可以充分利用多核,它能够轻松在多核系统上高效运行并发代码,是苹果推荐使用的多线程技术。

以上三种线程技术,抽象层次从低到高,抽象度越高使用则越简单,因此苹果推荐我们使用GCD。

Other、线程间通讯:

  在多线程中,所有修改有关于UI界面的东西,必须切换到主线程中修改,不能直接在多线程中修改,不然很容易会出现异常或修改不成功。本文会对三个线程技术说明如何切换至主线程修改UI,具体方法请往下看。

一、Thread

我们可以使用NSTherad或NSObject类去调用:

1)显式创建线程:NSThread

创建NSThread有两个办法

1.1)创建之后需要使用start方法,才会执行方法:

NSThread *threadAlloc = [[NSThread alloc] initWithTarget:self selector:@selector(threadAlloc) object:nil];
[threadAlloc start];

1.2)创建并马上执行方法:

[NSThread detachNewThreadSelector:@selector(threadAlloc:) toTarget:self withObject:nil];

2)隐式创建线程:NSObject

我们也可以使用NSObject类的方法直接调用方法

[self performSelectorInBackground:@selector(threadAlloc) withObject:nil];

取消线程的方法:

实际上并没有真正提供取消线程的API。苹果提供了一个cancel的api,但它不能作用于取消线程,它只能改变线程的运行状态。我们可以使用它来进行条件判断。

- (void)threadCancel
{
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadCancelNow) object:nil];
    [thread start];
}

- (void)threadCancelNow
{
    int a = 0;
    while (![[NSThread currentThread] isCancelled]) {
        NSLog(@"a - %d", a);
        a++;
        if (a == 5000) {
            NSLog(@"终止循环");
            [[NSThread currentThread] cancel];
            break;
        }
    }
}

程序效果:循环输出5000次,线程就会被终止。

NSThread线程间通讯-调用主线程修改UI:

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; 

NSThread相关属性及方法:

// 获取/设置线程的名字
@property (copy) NSString *name NS_AVAILABLE(10_5, 2_0);

/**
 *  获取当前线程的线程对象
 *
 *  通过这个属性可以查看当前线程是第几条线程,主线程为1。
 *  可以看到当前线程的序号及名字,主线程的序号为1,依次叠加。
 */
+ (NSThread *)currentThread;

// 线程休眠(秒)
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

// 线程休眠,指定具体什么时间休眠
+ (void)sleepUntilDate:(NSDate *)date;

// 退出线程
// 注意:这里会把线程对象销毁!销毁后就不能再次启动线程,否则程序会崩溃。
+ (void)exit;

二、Cocoa operations

1)NSInvocationOperation

// 创建线程任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

// 线程A
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
                                    initWithTarget:self
                                    selector:@selector(operation1)
                                    object:nil];
// 线程B
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]
                                    initWithTarget:self
                                    selector:@selector(operation2)
                                    object:nil];

// 把线程A/B添加至队列
[queue addOperations:@[operation, operation2] waitUntilFinished:YES];

必须使用addOperations:方法把线程添加至队列,不然线程不会执行,队列是并行执行。或者,你也可以使用addOperation:方法添加单个线程。

2)NSBlockOperation

举个简单的使用例子介绍,都写了备注,就不再说明了:

// 创建线程任务
NSBlockOperation *blockOperation = [NSBlockOperation
                                    blockOperationWithBlock:^{
                                        [NSThread sleepForTimeInterval:2];
                                        NSLog(@"one - %@", [NSThread currentThread]);
                                    }];;
// 添加新的操作
[blockOperation addExecutionBlock:^{
    NSLog(@"two - %@", [NSThread currentThread]);
}];

// 添加新的操作
[blockOperation addExecutionBlock:^{
    NSLog(@"three - %@", [NSThread currentThread]);
}];

// 执行线程任务
[blockOperation start];

例子效果:使用类方法blockOperationWithBlock:创建的块代码,是在主线程当中执行的,我们可以从打印出来的信息看到。其它使用addExecutionBlock:添加的子线程为并发线程。

3)NSOperationQueue

这里介绍一下NSOperation的依赖关系,依赖关系会影响线程的执行顺序:

// 创建操作队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

// 线程A
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"op1");
    [NSThread sleepForTimeInterval:2];
}];

// 线程B
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"op2");
}];

// 线程C
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"op3");
    [NSThread sleepForTimeInterval:2];
}];

// 线程B依赖线程C,也就是等线程C执行完之后才会执行线程B
[op2 addDependency:op3];
// 线程C依赖线程A,同上,只不过依赖对象改成了线程A
[op3 addDependency:op1];

// 为队列添加线程
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];

当你没添加依赖时,队列是并行执行的。

注意:依赖关系可以多重依赖,但不要建立循环依赖。

Cocoa operations线程间通信-调用主线程修改UI:

// 创建线程对象(并发)
NSBlockOperation *blockOperation = [[NSBlockOperation alloc] init];

// 添加新的操作
[blockOperation addExecutionBlock:^{
    NSLog(@"two - %@", [NSThread currentThread]);
}];

// 添加新的操作
[blockOperation addExecutionBlock:^{
    NSLog(@"three - %@", [NSThread currentThread]);
    // 在主线程修改UI
    NSOperationQueue *queue = [NSOperationQueue mainQueue];
    [queue addOperationWithBlock:^{
        [self editUINow];
    }];
}];

[blockOperation start];

NSOperation方法及属性:

// 设置线程的最大并发数
@property NSInteger maxConcurrentOperationCount;

// 线程完成后调用的Block
@property (copy) void (^completionBlock)(void);

// 取消线程
- (void)cancel;

只列举上面那些,其它的方法就不全列出来了。

注意:在NSOperationQueue类中,我们可以使用cancelAllOperations方法取消所有的线程。这里需要说明一下,不是执行cancelAllOperations方法时就会马上取消,是等当前队列执行完,下面的队列不会再执行。

三、Grand Central Dispatch (GCD)

1)GCD的创建:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"线程 - %@", [NSThread currentThread]);
});

GCD也可以创建同步的线程,只需要把async改成sync即可。

2)重复执行线程:dispatch_apply

以下代码会执行4次:

dispatch_apply(4, DISPATCH_QUEUE_PRIORITY_DEFAULT, ^(size_t index) {
    // index则为执行的次数 0开始递增
    NSLog(@"one - %ld", index);
});

index参数为执行的次数,从0开始递增

3)操作队列:dispatch_queue_create

// 创建队列
// 第一个参数是“字符串标识”,第二个参数是可选的,可以是NULL
dispatch_queue_t queue = dispatch_queue_create("com.garvey.post", NULL);

// 传入一个队列并执行队列(顺序执行)
dispatch_async(queue, ^{
    NSLog(@"aaa");
    [NSThread sleepForTimeInterval:2];
});
dispatch_async(queue, ^{
    NSLog(@"bbb");
    [NSThread sleepForTimeInterval:1];
});
dispatch_async(queue, ^{
    NSLog(@"ccc");
});

代码效果:以上会先执行aaa-》bbb-》ccc,是一个串行队列。

4)GCD群组通知:dispatch_group_t

GCD的高级用法,等所有线程都完成工作后,再作通知。

// 创建群组
dispatch_group_t group = dispatch_group_create();

// 线程A
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"group1");
    [NSThread sleepForTimeInterval:2];
});

// 线程B
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"group2");
});

// 待群组里的线程都完成之后调用的通知
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"group success");
});

群组里的线程也是并行队列。线程A和线程B都执行完之后,会调用通知打印group success。

5)GCD实现计时器

__block int time = 30;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(timer, ^{
    time--;
    NSLog(@"%d", time);
    if (time == 0) {
        dispatch_source_cancel(timer);
    }
});
dispatch_resume(timer);

代码效果:创建了一个计时器,计时器运行30秒,每过一秒会调用一次block,我们可以在block里面写代码。因为dispatch_source_t默认是挂起状态,因此我们使用时需要使用dispatch_resume方法先恢复,不然线程不会执行。

GCD线程间通信-调用主线程修改UI:

有时候我们请求后台作数据处理,数据处理是异步的,数据处理完成后需要更新UI,这时候我们需要切换到主线程修改UI,例子如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"异步数据处理 - %@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:2];
    NSLog(@"数据处理完成");

    // 调用主线程更新UI
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"更新UI - %@", [NSThread currentThread]);
        [self editUINow];
    });
});

因为是在主线程修改UI,所以我们最好是使用同步的GCD方法dispatch_sync。但这还不够,我们还需要使用dispatch_get_main_queue()方法来获得主线程,之后就是作UI的更新工作了。

GCD方法及属性:

// 获取主线程
dispatch_get_main_queue()

// 创建队列:第一个参数是“字符串标识”,第二个参数是可选的,可以是NULL
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

// 创建异步调度队列
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

// 恢复队列
void dispatch_resume(dispatch_object_t object);

// 暂停队列
void dispatch_suspend(dispatch_object_t object);

转自作者:GarveyCalvin

原文链接:http://www.cnblogs.com/GarveyCalvin/

时间: 2024-11-10 01:48:32

ios 多线程开关,有关线程的一些用法和详细讲解,NSThread , NSOperation ,Grand Central Dispatch ( GCD )的相关文章

【转载】iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

[转载]http://blog.csdn.net/totogo2010/article/details/8016129 iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用 分类: iOS开发进阶2012-09-25 16:22 35382人阅读 评论(32) 收藏 举报 目录(?)[+] 介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程

iOS Grand Central Dispatch(GCD) 的简单理解

引言: GCD的全称是Grand Central Dispatch,是苹果在iOS4.0发布的一套处理并发运算方面的API.其用途是为了提高处理器多核运算的能力. GCD有点像NSOperationQueue,它们都允许程序将任务切分为多个单一任务然后提交至工作队列来并发地或者串行地执行,但GCD比之NSOpertionQueue更底层更高效. GCD的工作原理: GCD的工作原理是让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务. 一个任务可以是一个函数(

iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术.以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的.它首次公布在Mac OS X 10.6 ,iOS 4及以上也可用. 设计: GCD的工作原理是:让程序平行排队的特定任务.依据可用的处理资源,安排他们在不论什么可用的处理器核心上运行任务. 一个任务能够是一个函数(function)或者是一个block. GCD的底层依旧是用线程实现,只是这样能够让程序

iOS 多线程编程之Grand Central Dispatch(GCD)

介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用. 设计: GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务. 一个任务可以是一个函数(function)或者是一个block. GCD的底层依然是用线程实现,不过这样可以让程序员不

[转]iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用. 设计: GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务. 一个任务可以是一个函数(function)或者是一个block. GCD的底层依然是用线程实现,不过这样可以让程序员不

iOS开发-多线程之GCD(Grand Central Dispatch)

Grand Central Dispatch(GCD)是一个强有力的方式取执行多线程任务,不管你在回调的时候是异步或者同步的,可以优化应用程序支持多核心处理器和其他的对称多处理系统的系统.开发使用的过程中只需要将执行的任务并添加到到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务.Dispatch Queue更简单而且在实现符合需求的多线程任务时更有效率.Dispatch  Queue一般来说有三种方式,如下图: Serial执行的时候的先进先出,Concurrent

iOS学习篇之Grand Central Dispatch(GCD)

我这里做一个简单的记录,担心现在看完了如果不做记录将来还得重头看,太浪费时间了. 全文翻译可谓是漏斗百出,将就着理解一下吧. 一些比较通俗易懂的文章推荐: GCD (Grand Central Dispatch) 笔记.Grand Central Dispatch(GCD).block && Grand Central Dispatch) 原文地址:Grand Central Dispatch (GCD) Reference CGD包含语法特征(直译是语法特征/功能),运行时库和系统增强即

iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用

目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 多线程的四种解决方案:pthread,NSThread,GCD,NSOperation 线程安全问题 NSThread的使用 GCD的理解与使用 NSOperation的理解与使用 Demo在这里:WHMultiThreadDemo Demo的运行gif图如下: 一.多线程的基本概念 进程:可以理解成一个运行中的应用程序,是系统进行资源分配和调度的基本单位,是操作

iOS多线程编程(四)------ GCD(Grand Central Dispatch)

一.简介 是基于C语言开发的一套多线程开发机制,也是目前苹果官方推荐的多线程开发方法,用起来也最简单,只是它基于C语言开发,并不像NSOperation是面向对象的开发,而是完全面向过程的.如果使用GCD,完全由系统管理线程,我们不需要编写线程代码.只需定义想要执行的任务,然后添加到适当的调度队列(dispatch_queue).GCD会负责创建线程和调度你的任务,系统会直接提供线程管理. 二.任务和队列 GCD中有两个核心概念 (1)任务:执行什么操作 (2)队列:用来存放任务 GCD的使用就