Objective-C 多线程

Posted Jk_Chan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Objective-C 多线程相关的知识,希望对你有一定的参考价值。

ios有三种多线程技术:

  • 1.NSThread
    • 创建方式两种:
      • 1.实例方法:
      • - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
      • 先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息
      • 2.类方法:
      • + (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
      • 直接创建线程并开始运行线程
      • 使用范例:
        • [NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
        • NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil];
        • [myThread start];
      • 参数解释:
      • selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
      • target :selector消息发送的对象
      • argument:传输给target的唯一参数,也可以是nil
      • 不显示创建线程的方法:
      • 调用NSObject的类方法performSelectorInBackground:withObject: 默认在子线程中执行
      • 示范:
        • [Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
      • 示范例子:(子线程异步下载,主线程UI更新)
#import "ViewController.h"
#define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"
@interface ViewController ()


@end


@implementation ViewController
- (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)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;
}
@end

 

  • 2.NSOperation
    • 用以封装执行程序中独立的工作单元,提供异步执行机制。
    • NSOperation类为抽象类,基于模版方法设计模式
    • Operations可以独立运行,也可以与Operation Queue协同运行。
    • 使用方式有两种:
      • 1.用定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。
      • NSInvocationOperation:
        • 创建方式:
        • NSInvocationOperation* operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(customTaskMethod:)object:params];
      • NSBlockOperation:
        • 创建方式:
        • NSBlockOperation* blockOperation = [NSBlockOperation blockOperationWithBlock: ^{
        • // to do the task.
        • }];
      • 在创建blockOperation后可以调用addExecutionBlock:方法添加更多的block
      • 示范例子:

 

#import "ViewController.h"
#define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
[super viewDidLoad];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self
selector:@selector(downloadImage:)
object:kURL];

NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:operation];
// Do any additional setup after loading the view, typically from a nib.
}

-(void)downloadImage:(NSString *)url{
NSLog(@"url:%@", url);
NSURL *nsUrl = [NSURL URLWithString:url];
NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
UIImage * image = [[UIImage alloc]initWithData:data];
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}
-(void)updateUI:(UIImage*) image{
self.imageView.image = image;
}

 

      • 2.继承NSOperation
        • 1.提供一个自定义的初始化方法,在执行operation之前提供初始化流程,准备operation状态
        • 2.只需继承重写NSOperation的一个方法main
        • 3.然后把NSOperation子类的对象放入NSOperationQueue队列中,该队列就会启动并开始处理它
        • 示范例子:
@interface MoveFileOperation : NSOperation

- (id)initWithSrcURL:(NSURL *)srcURL toDestinationURL:(NSURL*)desURL;

@end

// MoveFileOperation.m
@interface MoveFileOperation ()

@property (retain) NSURL *srcURL;

@property (retain) NSURL *desURL;

@end

@implementation MoveFileOperation

@synthesize rootURL, queue;

- (id)initWithSrcURL:(NSURL *)srcURL toDestinationURL:(NSURL*)desURL;
{
self = [super init];
if (self) {
self.srcURL = srcURL;
self.desURL = desURL; 
}
return self;
}

- (void)main
{ 
if ([self isCancelled]){
return;
}
NSDirectoryEnumerator *itr =[[NSFileManager defaultManager] enumeratorAtURL:self.srcURL includingPropertiesForKeys:nil
options:(NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsPackageDescendants)
errorHandler:nil];
NSError *error = [NSError new];
for (NSURL *url in itr) {
if ([self isCancelled]) {//
break; 
}else{
NSString *fileName = [url lastPathComponent];
NSURL *desFileURL = [self.desURL URLByAppendingPathComponent:fileName];
[[NSFileManager defaultManager] copyItemAtURL:url toURL:desFileURL error:&error];
} 
}
}

 

        • 通过isCancelled方法对operation支持线程取消行为:
        • 常见的正确调用isCancelled的位置包括:
          • 1.在实际执行工作之前
          • 2.在每个循环的执行体中,如果一次执行体耗时很长可酌情添加调用次数
          • 3.程序相对容易终止的代码处。
        • 配置operation的依赖关系:
          • 调用addDependency: 方法可以建立两个operation对象间的依赖关系:
          • 这个单向关系表明当前operation对象只有在目标operation对象执行完成之后才能执行。
          • operation对象的依赖关系不限于同一个操作队列。
          • 有依赖关系的operation对象可以添加到不同的操作队列中。
          • 但是operation之间不能添加循环依赖关系。
        • 添加Completion Block:
          • 通过setCompletionBlock: 方法可以完成添加completion block的工作,可以在此处派发operation完成的消息。
        • 执行operation的方式:
          • 1 .将operation对象添加到操作队列NSOperatinQueue对象中:
            • NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
            • 1.// Add a single operation
            • [aQueue addOperation:anOp];
            • 2.// Add multiple operations
            • [aQueue addOperations:anArrayOfOps waitUntilFinished:NO];
            • 3.// Add a block
            • [aQueue addOperationWithBlock:^{
            • /* Do something. */
            • }];
            • NSOperationQueue设计上是用来并发执行operation,setMaxConcurrentOperationCount:方法可以设置操作队列并行执行的最大数量。
            • 需要设置operation间的依赖关系来保证它们的执行顺序是你想要的。
          • 2.手动执行operation:
            • 一个operation只有在其isReady方法返回YES时才被认为是可运行的。
            • isReady方法会被整合进NSOperation的依赖管理系统来保证operation的依赖状态。
            • 只有在依赖关系清楚后,operation才开始运行。
            • 手动执行operation时,必须调用其start方法。
        • 取消operation:
          • 一旦加入操作队列,操作队列就拥有了该operation,并且它不能被删除。
          • 调出operation的唯一方法是取消(cancel)它
          • 在一个operation上调用cancel可以取消其执行,在操作队列对象上调用cancelAllOperations 会取消所有operation。
          • operation的取消行为也会被认为是执行完毕(finished),依赖于它的其它operation对象会收到KVO通知来清除该依赖关系。
        • 等待operation结束:
          • 如果创建operation的进程需要处理operation的结果,可以使用NSOperation的 waitUntilFinished方法来阻塞代码直到operation完成(决不能在主线程上等待一个operation结束)
        • 挂起和回复队列:
          • 调用NSOperationQueue对象的setSuspended: 方法可以操作队列挂起。挂起队列不会阻碍当前正在执行中的operation,它只是阻止新的operation的执行。
  • 3.GCD

以上是关于Objective-C 多线程的主要内容,如果未能解决你的问题,请参考以下文章

如何将这个 Objective-C 代码片段写入 Swift?

多线程 Thread 线程同步 synchronized

objective-c开发——多线程(NSThread)

多个用户访问同一段代码

线程学习知识点总结

Objective-C多线程,当一个对象在其方法被执行时被释放会发生啥? (以及如何预防?)