多线程

当用户播放音频、下载资源、进行图像处理时往往希望做这些事情的时候其他操作不会被中 断或者希望这些操作过程中更加顺畅。在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势必影响用户体验。早在单核处理器时期 就有多线程,这个时候多线程更多的用于解决线程阻塞造成的用户等待(通常是操作完UI后用户不再干涉,其他线程在等待队列中,CPU一旦空闲就继续执行, 不影响用户其他UI操作),其处理能力并没有明显的变化。如今无论是移动操作系统还是PC、服务器都是多核处理器,于是“并行运算”就更多的被提及。一件 事情我们可以分成多个步骤,在没有顺序要求的情况下使用多线程既能解决线程阻塞又能充分利用多核处理器运行能力。

常见的多线程的开发方式:

1.NSThread

2.NSOperation

3.GCD

NSThread是轻量级的多线程的开发,使用起来很简单。但是使用NSThread需要自己管理线程的生命周期。

启动线程有下面两种方式:

第一种:直接将操作添加到线程中并启动

+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument

第二种:创建一个线程对象,然后调用start方法启动线程

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

解决线路阻塞问题

在资源下载过程中,由于网络原因有时候很难保证下载时间,如果不使用
多线程可能用户完成一个下载操作需要长时间的等待,这个过程中无法进行其他操作。下面演示一个采用多线程下载图片的过程,在这个示例中点击按钮会启动一个
线程去下载图片,下载完成后使用UIImageView将图片显示到界面中。可以看到用户点击完下载按钮后,不管图片是否下载完成都可以继续操作界面,不
会造成阻塞

  1. //
  2. //  NSThread实现多线程
  3. //  MultiThread
  4. //
  5. //  Created by Kenshin Cui on 16-5-20.
  6. //  Copyright (c) 2016年 zhy. All rights reserved.
  7. //
  8. #import "KCMainViewController.h"
  9. @interface KCMainViewController (){
  10. UIImageView *_imageView;
  11. }
  12. @end
  13. @implementation KCMainViewController
  14. - (void)viewDidLoad {
  15. [super viewDidLoad];
  16. [self layoutUI];
  17. }
  18. #pragma mark 界面布局
  19. -(void)layoutUI{
  20. _imageView =[[UIImageView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
  21. _imageView.contentMode=UIViewContentModeScaleAspectFit;
  22. [self.view addSubview:_imageView];
  23. UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
  24. button.frame=CGRectMake(50, 500, 220, 25);
  25. [button setTitle:@"加载图片" forState:UIControlStateNormal];
  26. //添加方法
  27. [button addTarget:self action:@selector(loadImageWithMultiThread) forControlEvents:UIControlEventTouchUpInside];
  28. [self.view addSubview:button];
  29. }
  30. #pragma mark 将图片显示到界面
  31. -(void)updateImage:(NSData *)imageData{
  32. UIImage *image=[UIImage imageWithData:imageData];
  33. _imageView.image=image;
  34. }
  35. #pragma mark 请求图片数据
  36. -(NSData *)requestData{
  37. //对于多线程操作建议把线程操作放到@autoreleasepool中
  38. @autoreleasepool {
  39. NSURL *url=[NSURL URLWithString:@"http://images.apple.com/iphone-6/overview/images/biggest_right_large.png"];
  40. NSData *data=[NSData dataWithContentsOfURL:url];
  41. return data;
  42. }
  43. }
  44. #pragma mark 加载图片
  45. -(void)loadImage{
  46. //请求数据
  47. NSData *data= [self requestData];
  48. /*将数据显示到UI控件,注意只能在主线程中更新UI,
  49. 另外performSelectorOnMainThread方法是NSObject的分类方法,每个NSObject对象都有此方法,
  50. 它调用的selector方法是当前调用控件的方法,例如使用UIImageView调用的时候selector就是UIImageView的方法
  51. Object:代表调用方法的参数,不过只能传递一个参数(如果有多个参数请使用对象进行封装)
  52. waitUntilDone:是否线程任务完成执行
  53. */
  54. [self performSelectorOnMainThread:@selector(updateImage:) withObject:data waitUntilDone:YES];
  55. }
  56. #pragma mark 多线程下载图片
  57. -(void)loadImageWithMultiThread{
  58. //方法1:使用对象方法
  59. //创建一个线程,第一个参数是请求的操作,第二个参数是操作方法的参数
  60. //    NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(loadImage) object:nil];
  61. //    //启动一个线程,注意启动一个线程并非就一定立即执行,而是处于就绪状态,当系统调度时才真正执行
  62. //    [thread start];
  63. //方法2:使用类方法
  64. [NSThread detachNewThreadSelector:@selector(loadImage) toTarget:self withObject:nil];
  65. }
  66. @end

上面的程序比较简单,点击“加载图片”的按钮后会启动一个新的线程,在这个线程没有完全执行完成(图片没有显示出来的时候)的时候,用户依然可以进行其他操作,在图片下载完成之后将图片显示到界面中(这个操作瞬间完成)。更新UI的时候是在UI线程进行更新。

多个线程并发执行:

大家应该注意到不管是使
用+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target
withObject:(id)argument、- (instancetype)initWithTarget:(id)target
selector:(SEL)selector object:(id)argument 方法还是使用-
(void)performSelectorOnMainThread:(SEL)aSelector
withObject:(id)arg
waitUntilDone:(BOOL)wait方法都只能传一个参数,由于更新图片需要传递UIImageView的索引和图片数据,因此这里不妨定
义一个类保存图片索引和图片数据以供后面使用。

KCImageData.h

  1. <span style="font-size:14px;">/
  2. //  KCImageData.h
  3. //  MultiThread
  4. //
  5. //  Created by Kenshin Cui on 16-5-20.
  6. </span><span style="font-size:14px;"></span><pre name="code" class="objc"><span style="font-size:14px;">//  Copyright (c) 2016年 zhy. All rights reserved.
  7. //
  8. #import <Foundation/Foundation.h>
  9. @interface KCImageData : NSObject
  10. #pragma mark 索引
  11. @property (nonatomic,assign) int index;
  12. #pragma mark 图片数据
  13. @property (nonatomic,strong) NSData *data;
  14. @end</span>

接下来将创建多个UIImageView并创建多个线程用于往UIImageView中填充图片。

KCMainViewController.m

  1. //
  2. //  NSThread实现多线程
  3. //  MultiThread
  4. //
  5. //  Created by Kenshin Cui on 16-5-20.
  6. //  Copyright (c) 2016年 zhy. All rights reserved.
  7. //
  8. #import "KCMainViewController.h"
  9. #import "KCImageData.h"
  10. #define ROW_COUNT 5
  11. #define COLUMN_COUNT 3
  12. #define ROW_HEIGHT 100
  13. #define ROW_WIDTH ROW_HEIGHT
  14. #define CELL_SPACING 10
  15. @interface KCMainViewController (){
  16. NSMutableArray *_imageViews;
  17. }
  18. @end
  19. @implementation KCMainViewController
  20. - (void)viewDidLoad {
  21. [super viewDidLoad];
  22. [self layoutUI];
  23. }
  24. #pragma mark 界面布局
  25. -(void)layoutUI{
  26. //创建多个图片控件用于显示图片
  27. _imageViews=[NSMutableArray array];
  28. for (int r=0; r<ROW_COUNT; r++) {
  29. for (int c=0; c<COLUMN_COUNT; c++) {
  30. UIImageView *imageView=[[UIImageView alloc]initWithFrame:CGRectMake(c*ROW_WIDTH+(c*CELL_SPACING), r*ROW_HEIGHT+(r*CELL_SPACING                           ), ROW_WIDTH, ROW_HEIGHT)];
  31. imageView.contentMode=UIViewContentModeScaleAspectFit;
  32. //            imageView.backgroundColor=[UIColor redColor];
  33. [self.view addSubview:imageView];
  34. [_imageViews addObject:imageView];
  35. }
  36. }
  37. UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
  38. button.frame=CGRectMake(50, 500, 220, 25);
  39. [button setTitle:@"加载图片" forState:UIControlStateNormal];
  40. //添加方法
  41. [button addTarget:self action:@selector(loadImageWithMultiThread) forControlEvents:UIControlEventTouchUpInside];
  42. [self.view addSubview:button];
  43. }
  44. #pragma mark 将图片显示到界面
  45. -(void)updateImage:(KCImageData *)imageData{
  46. UIImage *image=[UIImage imageWithData:imageData.data];
  47. UIImageView *imageView= _imageViews[imageData.index];
  48. imageView.image=image;
  49. }
  50. #pragma mark 请求图片数据
  51. -(NSData *)requestData:(int )index{
  52. //对于多线程操作建议把线程操作放到@autoreleasepool中
  53. @autoreleasepool {
  54. NSURL *url=[NSURL URLWithString:@"http://images.apple.com/iphone-6/overview/images/biggest_right_large.png"];
  55. NSData *data=[NSData dataWithContentsOfURL:url];
  56. return data;
  57. }
  58. }
  59. #pragma mark 加载图片
  60. -(void)loadImage:(NSNumber *)index{
  61. //    NSLog(@"%i",i);
  62. //currentThread方法可以取得当前操作线程
  63. NSLog(@"current thread:%@",[NSThread currentThread]);
  64. int i=[index integerValue];
  65. //    NSLog(@"%i",i);//未必按顺序输出
  66. NSData *data= [self requestData:i];
  67. KCImageData *imageData=[[KCImageData alloc]init];
  68. imageData.index=i;
  69. imageData.data=data;
  70. [self performSelectorOnMainThread:@selector(updateImage:) withObject:imageData waitUntilDone:YES];
  71. }
  72. #pragma mark 多线程下载图片
  73. -(void)loadImageWithMultiThread{
  74. //创建多个线程用于填充图片
  75. for (int i=0; i<ROW_COUNT*COLUMN_COUNT; ++i) {
  76. //        [NSThread detachNewThreadSelector:@selector(loadImage:) toTarget:self withObject:[NSNumber numberWithInt:i]];
  77. NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(loadImage:) object:[NSNumber numberWithInt:i]];
  78. thread.name=[NSString stringWithFormat:@"myThread%i",i];//设置线程名称
  79. [thread start];
  80. }
  81. }
  82. @end

NSOperation有两个常用子类用于创建线程操作:NSInvocationOperation和NSBlockOperation,两种方式本质没有区别,但是是后者使用Block形式进行代码组织,使用相对方便

NSInvocationOperation

首先使用NSInvocationOperation进行一张图片的加载演示,整个过程就是:创建一个操作,在这个操作中指定调用方法和参数,然后加入到操作队列。其他代码基本不用修改,直接修加载图片方法如下:

  1. -(void)loadImageWithMultiThread{
  2. /*创建一个调用操作
  3. object:调用方法参数
  4. */
  5. NSInvocationOperation *invocationOperation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(loadImage) object:nil];
  6. //创建完NSInvocationOperation对象并不会调用,它由一个start方法启动操作,但是注意如果直接调用start方法,则此操作会在主线程中调用,一般不会这么操作,而是添加到NSOperationQueue中
  7. //    [invocationOperation start];
  8. //创建操作队列
  9. NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];
  10. //注意添加到操作队后,队列会开启一个线程执行此操作
  11. [operationQueue addOperation:invocationOperation];
  12. }

NSBlockOperation

下面采用NSBlockOperation创建多个线程加载图片。

  1. #import "KCMainViewController.h"
  2. #import "KCImageData.h"
  3. #define ROW_COUNT 5
  4. #define COLUMN_COUNT 3
  5. #define ROW_HEIGHT 100
  6. #define ROW_WIDTH ROW_HEIGHT
  7. #define CELL_SPACING 10
  8. @interface KCMainViewController (){
  9. NSMutableArray *_imageViews;
  10. NSMutableArray *_imageNames;
  11. }
  12. @end
  13. @implementation KCMainViewController
  14. - (void)viewDidLoad {
  15. [super viewDidLoad];
  16. [self layoutUI];
  17. }
  18. #pragma mark 界面布局
  19. -(void)layoutUI{
  20. //创建多个图片控件用于显示图片
  21. _imageViews=[NSMutableArray array];
  22. for (int r=0; r<ROW_COUNT; r++) {
  23. for (int c=0; c<COLUMN_COUNT; c++) {
  24. UIImageView *imageView=[[UIImageView alloc]initWithFrame:CGRectMake(c*ROW_WIDTH+(c*CELL_SPACING), r*ROW_HEIGHT+(r*CELL_SPACING                           ), ROW_WIDTH, ROW_HEIGHT)];
  25. imageView.contentMode=UIViewContentModeScaleAspectFit;
  26. //            imageView.backgroundColor=[UIColor redColor];
  27. [self.view addSubview:imageView];
  28. [_imageViews addObject:imageView];
  29. }
  30. }
  31. UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
  32. button.frame=CGRectMake(50, 500, 220, 25);
  33. [button setTitle:@"加载图片" forState:UIControlStateNormal];
  34. //添加方法
  35. [button addTarget:self action:@selector(loadImageWithMultiThread) forControlEvents:UIControlEventTouchUpInside];
  36. [self.view addSubview:button];
  37. //创建图片链接
  38. _imageNames=[NSMutableArray array];
  39. for (int i=0; i<IMAGE_COUNT; i++) {
  40. [_imageNames addObject:[NSString stringWithFormat:@"http://images.cnblogs.com/cnblogs_com/kenshincui/613474/o_%i.jpg",i]];
  41. }
  42. }
  43. #pragma mark 将图片显示到界面
  44. -(void)updateImageWithData:(NSData *)data andIndex:(int )index{
  45. UIImage *image=[UIImage imageWithData:data];
  46. UIImageView *imageView= _imageViews[index];
  47. imageView.image=image;
  48. }
  49. #pragma mark 请求图片数据
  50. -(NSData *)requestData:(int )index{
  51. //对于多线程操作建议把线程操作放到@autoreleasepool中
  52. @autoreleasepool {
  53. NSURL *url=[NSURL URLWithString:_imageNames[index]];
  54. NSData *data=[NSData dataWithContentsOfURL:url];
  55. return data;
  56. }
  57. }
  58. #pragma mark 加载图片
  59. -(void)loadImage:(NSNumber *)index{
  60. int i=[index integerValue];
  61. //请求数据
  62. NSData *data= [self requestData:i];
  63. NSLog(@"%@",[NSThread currentThread]);
  64. //更新UI界面,此处调用了主线程队列的方法(mainQueue是UI主线程)
  65. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  66. [self updateImageWithData:data andIndex:i];
  67. }];
  68. }
  69. #pragma mark 多线程下载图片
  70. -(void)loadImageWithMultiThread{
  71. int count=ROW_COUNT*COLUMN_COUNT;
  72. //创建操作队列
  73. NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];
  74. operationQueue.maxConcurrentOperationCount=5;//设置最大并发线程数
  75. //创建多个线程用于填充图片
  76. for (int i=0; i<count; ++i) {
  77. //方法1:创建操作块添加到队列
  78. //        //创建多线程操作
  79. //        NSBlockOperation *blockOperation=[NSBlockOperation blockOperationWithBlock:^{
  80. //            [self loadImage:[NSNumber numberWithInt:i]];
  81. //        }];
  82. //        //创建操作队列
  83. //
  84. //        [operationQueue addOperation:blockOperation];
  85. //方法2:直接使用操队列添加操作
  86. [operationQueue addOperationWithBlock:^{
  87. [self loadImage:[NSNumber numberWithInt:i]];
  88. }];
  89. }
  90. }
  91. @end

对比之前NSThread加载张图片很发现核心代码简化了不少,这里着重强调两点:

  1. 使用NSBlockOperation方法,所有的操作不必单独定义方法,同时解决了只能传递一个参数的问题。
  2. 调用主线程队列的addOperationWithBlock:方法进行UI更新,不用再定义一个参数实体(之前必须定义一个KCImageData解决只能传递一个参数的问题)。
  3. 使用NSOperation进行多线程开发可以设置最大并发线程,有效的对线程进行了控制(上面的代码运行起来你会发现打印当前进程时只有有限的线程被创建,如上面的代码设置最大线程数为5,则图片基本上是五个一次加载的)。

GCD是基于C语言开发的一套多线程开发机制,也是目前苹果官方推荐的多线程开发方法。前面也说过三种开发中GCD抽象层次最高,当然是用起来也最简单,只是它基于C语言开发,并不像NSOperation是面向对象的开发,而是完全面向过程的。

GCD中也有一个类似于NSOperationQueue的队列,GCD统一管理整个队列中的任务。但是GCD中的队列分为并行队列和串行队列两类:

  • 串行队列:只有一个线程,加入到队列中的操作按添加顺序依次执行。
  • 并发队列:有多个线程,操作进来之后它会将这些队列安排在可用的处理器上,同时保证先进来的任务优先处理。

其实在GCD中还有一个特殊队列就是主队列,用来执行主线程上的操作任务

串行队列

使用串行队列时首先要创建一个串行队列,然后调用异步调用方法,在此方法中传入串行队列和线程操作即可自动执行。下面使用线程队列演示图片的加载过程,你会发现多张图片会按顺序加载,因为当前队列中只有一个线程。

  1. #import "KCMainViewController.h"
  2. #import "KCImageData.h"
  3. #define ROW_COUNT 5
  4. #define COLUMN_COUNT 3
  5. #define ROW_HEIGHT 100
  6. #define ROW_WIDTH ROW_HEIGHT
  7. #define CELL_SPACING 10
  8. @interface KCMainViewController (){
  9. NSMutableArray *_imageViews;
  10. NSMutableArray *_imageNames;
  11. }
  12. @end
  13. @implementation KCMainViewController
  14. - (void)viewDidLoad {
  15. [super viewDidLoad];
  16. [self layoutUI];
  17. }
  18. #pragma mark 界面布局
  19. -(void)layoutUI{
  20. //创建多个图片控件用于显示图片
  21. _imageViews=[NSMutableArray array];
  22. for (int r=0; r<ROW_COUNT; r++) {
  23. for (int c=0; c<COLUMN_COUNT; c++) {
  24. UIImageView *imageView=[[UIImageView alloc]initWithFrame:CGRectMake(c*ROW_WIDTH+(c*CELL_SPACING), r*ROW_HEIGHT+(r*CELL_SPACING                           ), ROW_WIDTH, ROW_HEIGHT)];
  25. imageView.contentMode=UIViewContentModeScaleAspectFit;
  26. //            imageView.backgroundColor=[UIColor redColor];
  27. [self.view addSubview:imageView];
  28. [_imageViews addObject:imageView];
  29. }
  30. }
  31. UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
  32. button.frame=CGRectMake(50, 500, 220, 25);
  33. [button setTitle:@"加载图片" forState:UIControlStateNormal];
  34. //添加方法
  35. [button addTarget:self action:@selector(loadImageWithMultiThread) forControlEvents:UIControlEventTouchUpInside];
  36. [self.view addSubview:button];
  37. //创建图片链接
  38. _imageNames=[NSMutableArray array];
  39. for (int i=0; i<ROW_COUNT*COLUMN_COUNT; i++) {
  40. [_imageNames addObject:[NSString stringWithFormat:@"http://images.cnblogs.com/cnblogs_com/kenshincui/613474/o_%i.jpg",i]];
  41. }
  42. }
  43. #pragma mark 将图片显示到界面
  44. -(void)updateImageWithData:(NSData *)data andIndex:(int )index{
  45. UIImage *image=[UIImage imageWithData:data];
  46. UIImageView *imageView= _imageViews[index];
  47. imageView.image=image;
  48. }
  49. #pragma mark 请求图片数据
  50. -(NSData *)requestData:(int )index{
  51. NSURL *url=[NSURL URLWithString:_imageNames[index]];
  52. NSData *data=[NSData dataWithContentsOfURL:url];
  53. return data;
  54. }
  55. #pragma mark 加载图片
  56. -(void)loadImage:(NSNumber *)index{
  57. //如果在串行队列中会发现当前线程打印变化完全一样,因为他们在一个线程中
  58. NSLog(@"thread is :%@",[NSThread currentThread]);
  59. int i=[index integerValue];
  60. //请求数据
  61. NSData *data= [self requestData:i];
  62. //更新UI界面,此处调用了GCD主线程队列的方法
  63. dispatch_queue_t mainQueue= dispatch_get_main_queue();
  64. dispatch_sync(mainQueue, ^{
  65. [self updateImageWithData:data andIndex:i];
  66. });
  67. }
  68. #pragma mark 多线程下载图片
  69. -(void)loadImageWithMultiThread{
  70. int count=ROW_COUNT*COLUMN_COUNT;
  71. /*创建一个串行队列
  72. 第一个参数:队列名称
  73. 第二个参数:队列类型
  74. */
  75. dispatch_queue_t serialQueue=dispatch_queue_create("myThreadQueue1", DISPATCH_QUEUE_SERIAL);//注意queue对象不是指针类型
  76. //创建多个线程用于填充图片
  77. for (int i=0; i<count; ++i) {
  78. //异步执行队列任务
  79. dispatch_async(serialQueue, ^{
  80. [self loadImage:[NSNumber numberWithInt:i]];
  81. });
  82. }
  83. //非ARC环境请释放
  84. //    dispatch_release(seriQueue);
  85. }
  86. @end

在上面的代码中更新UI还使用了GCD方法的主线程队列dispatch_get_main_queue(),其实这与前面两种主线程更新UI没有本质的区别。

并发队列

并发队列同样是使用dispatch_queue_create()方法创建,只是最后一个参数指定为DISPATCH_QUEUE_CONCURRENT
行创建,但是在实际开发中我们通常不会重新创建一个并发队列而是使用dispatch_get_global_queue()方法取得一个全局的并发队列
(当然如果有多个并发队列可以使用前者创建)。下面通过并行队列演示一下多个图片的加载。代码与上面串行队列加载类似,只需要修改照片加载方法如下:

  1. -(void)loadImageWithMultiThread{
  2. int count=ROW_COUNT*COLUMN_COUNT;
  3. /*取得全局队列
  4. 第一个参数:线程优先级
  5. 第二个参数:标记参数,目前没有用,一般传入0
  6. */
  7. dispatch_queue_t globalQueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  8. //创建多个线程用于填充图片
  9. for (int i=0; i<count; ++i) {
  10. //异步执行队列任务
  11. dispatch_async(globalQueue, ^{
  12. [self loadImage:[NSNumber numberWithInt:i]];
  13. });
  14. }
  15. }

GCD执行任务的方法并非只有简单的同步调用方法和异步调用方法,还有其他一些常用方法:

    1. dispatch_apply():重复执行某个任务,但是注意这个方法没有办法异步执行(为了不阻塞线程可以使用dispatch_async()包装一下再执行)。
    2. dispatch_once():单次执行一个任务,此方法中的任务只会执行一次,重复调用也没办法重复执行(单例模式中常用此方法)。
    3. dispatch_time():延迟一定的时间后执行。
    4. dispatch_barrier_async():
      使用此方法创建的任务首先会查看队列中有没有别的任务要执行,如果有,则会等待已有任务执行完毕再执行;同时在此方法后添加的任务必须等待此方法中任务执
      行后才能执行。(利用这个方法可以控制执行顺序,例如前面先加载最后一张图片的需求就可以先使用这个方法将最后一张图片加载的操作添加到队列,然后调用
      dispatch_async()添加其他图片加载任务)
    5. dispatch_group_async():实现对任务分组管理,如果一组任务全部完成可以通过dispatch_group_notify()方法获得完成通知(需要定义dispatch_group_t作为分组标识)。

iOS多线程开发--NSThread NSOperation GCD的更多相关文章

  1. iOS的三种多线程技术NSThread/NSOperation/GCD

    1.iOS的三种多线程技术 1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 2.以下两点是苹果专门开发的"并发"技术,使得程序员可以不再去关心 ...

  2. iOS 多线程(NSThread、GCD、NSOperation)

    ios中得多线程技术主要使用3种:NSThread.NSOperation和GCD 一.NSThread: 最轻量级方法,但是不安全需要手动加锁,需要自己管理生命周期 NSThread的使用方法有2种 ...

  3. 多线程技术 NSThread & NSOperation & GCD

    多线程:在iOS开发中,用到多线程的处理问题的时候有很多,比如异步下载数据时刷新界面等等. 引入多线程来处理问题的关键就是,基于多线程可以使界面更加流畅,防止界面假死. 界面假死:比如你单击一个按钮来 ...

  4. 多线程&NSObject&NSThread&NSOperation&GCD

    1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 以下两点是苹果专门开发的“并发”技术,使得程序员可以不再去关心线程的具体使用问题 2.NSOperation/NS ...

  5. iOS多线程开发

    概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的,一个复杂的多步操 ...

  6. 多线程之pthread, NSThread, NSOperation, GCD

    关于多线程会有一系列如下:多线程之概念解析 多线程之pthread, NSThread, NSOperation, GCD 多线程之NSThread 多线程之NSOperation 多线程之GCD p ...

  7. iOS 多线程学习笔记 —— NSOperation

    本文复制.参考自文章:iOS多线程编程之NSOperation和NSOperationQueue的使用 ,主要为了加强个人对知识的理解和记忆,不做他用.原作者声明: 著作权声明:本文由http://b ...

  8. iOS之多线程开发NSThread、NSOperation、GCD

    原文出处: 容芳志的博客   欢迎分享原创到伯乐头条 简介iOS有三种多线程编程的技术,分别是:(一)NSThread(二)Cocoa NSOperation(三)GCD(全称:Grand Centr ...

  9. iOS 多线程 简单学习NSThread NSOperation GCD

    1:首先简单介绍什么叫线程 可并发执行的,拥有最小系统资源,共享进程资源的基本调度单位. 共用堆,自有栈(官方资料说明iOS主线程栈大小为1M,其它线程为512K). 并发执行进度不可控,对非原子操作 ...

随机推荐

  1. CSS属性值一览

    牢记内联式>嵌入式(嵌入式中设置各种文字字体.大小.位置.颜色.外距.内距最好用选择器)>外部式(外联式)的使用 属性和属性值(点击可展开) font-family(字体) Microso ...

  2. USACO4.13Fence Loops(无向图最小环)

    最近脑子有点乱 老是不想清楚就啪啪的敲 敲完之后一看 咦..样例都过不去 仔细一想 这样不对啊 刚开始就写了一SPFA 最后发现边跟点的关系没处理好 删了..写dfs..还是没转化好 开始搜解题方法 ...

  3. hadoop 序列化源码浅析

    1.Writable接口         Hadoop 并没有使用 JAVA 的序列化,而是引入了自己实的序列化系统, package org.apache.hadoop.io 这个包中定义了大量的可 ...

  4. jquery easyui datebox 的使用

    看了jquery easyui databox的官方api,还可以加入倒是很简单,但是想要获得他的值和修改值就很费劲,不知道怎么弄,试了n次终于搞定.这里总结一下,供有相同问题的人查询. 1. 官方a ...

  5. 【转】MFC中用CFile读取和写入文件2

    原文网址:http://blog.sina.com.cn/s/blog_623a7fa40100hh1u.html CFile提供了一些常用的操作函数,如表1-2所示. 表1-2  CFile操作函数 ...

  6. json-lib反序列化时(JSONObject.toBean),时间类型为空的处理

    需求: 在我们的项目里希望JsonString传入日期类型值为空时,JSONObject.toBean时可以将Java对象的该日期属性设为null. 解决过程: json-lib反序列化Json字符串 ...

  7. JDK1.5新特性(三)……Varargs

    援引 Varargs - This facility eliminates the need for manually boxing up argument lists into an array w ...

  8. BP神经网络分类器的设计

    1.BP神经网络训练过程论述 BP网络结构有3层:输入层.隐含层.输出层,如图1所示. 图1 三层BP网络结构 3层BP神经网络学习训练过程主要由4部分组成:输入模式顺传播(输入模式由输入层经隐含层向 ...

  9. (转)如何在Excel2013中制作条形码

    文章来源:http://www.officezhushou.com/excel2013/3905.html 注意:如果发现条形码不能移动的情况,请点击开发工具-设计模式,那么你就可以移动你的条形码了 ...

  10. [转]强大的vim配置文件,让编程更随意

    转自:http://www.cnblogs.com/ma6174/archive/2011/12/10/2283393.html 花了很长时间整理的,感觉用起来很方便,共享一下. 我的vim配置主要有 ...