iOS随笔Object-C

多线程

NSThread

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];  

第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息

下载图片的例子:

    //  
    //  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];  
    }  

    @end

NSOperation

一种是用定义好的两个子类:

NSInvocationOperation 和 NSBlockOperation。

另一种是继承NSOperation

如果你也熟悉Java,NSOperation就和java.lang.Runnable接口很相似。和Java的Runnable一样,NSOperation也是设计用来扩展的,只需继承重写NSOperation的一个方法main。相当与java 中Runnalbe的Run方法。然后把NSOperation子类的对象放入NSOperationQueue队列中,该队列就会启动并开始处理它。

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


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

GCD

dispatch queue分为下面三种: Serial

又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。 Concurrent

又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。 Main dispatch queue

它是全局可用的serial queue,它是在应用程序主线程上执行任务的。

1、常用的方法dispatch_async

为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。

用GCD实现这个流程的操作比前面介绍的NSThread NSOperation的方法都要简单。代码框架结构如下:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
        // 耗时的操作  
        dispatch_async(dispatch_get_main_queue(), ^{  
            // 更新界面  
        });  
    });

如果这样还不清晰的话,那我们还是用上两篇博客中的下载图片为例子,代码如下:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
        NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];  
        NSData * data = [[NSData alloc]initWithContentsOfURL:url];  
        UIImage *image = [[UIImage alloc]initWithData:data];  
        if (data != nil) {  
            dispatch_async(dispatch_get_main_queue(), ^{  
                self.imageView.image = image;  
             });  
        }  
    });

2、dispatch_group_async的使用

dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。下面是一段例子代码:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
    dispatch_group_t group = dispatch_group_create();  
    dispatch_group_async(group, queue, ^{  
        [NSThread sleepForTimeInterval:1];  
        NSLog(@"group1");  
    });  
    dispatch_group_async(group, queue, ^{  
        [NSThread sleepForTimeInterval:2];  
        NSLog(@"group2");  
    });  
    dispatch_group_async(group, queue, ^{  
        [NSThread sleepForTimeInterval:3];  
        NSLog(@"group3");  
    });  
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{  
        NSLog(@"updateUi");  
    });  
    dispatch_release(group);

3、dispatch_barrier_async的使用

dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

例子代码如下:

```
dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);  
dispatch_async(queue, ^{  
    [NSThread sleepForTimeInterval:2];  
    NSLog(@"dispatch_async1");  
});  
dispatch_async(queue, ^{  
    [NSThread sleepForTimeInterval:4];  
    NSLog(@"dispatch_async2");  
});  
dispatch_barrier_async(queue, ^{  
    NSLog(@"dispatch_barrier_async");  
    [NSThread sleepForTimeInterval:4];  

});  
dispatch_async(queue, ^{  
    [NSThread sleepForTimeInterval:1];  
    NSLog(@"dispatch_async3");  
});    ```

4、dispatch_apply

执行某个代码片段N次。

dispatch_apply(5, globalQ, ^(size_t index) {
    // 执行5次
});

NSObeject

@interface NSObject (NSThreadPerformAdditions)

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
    // equivalent to the first method with kCFRunLoopCommonModes

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
    // equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg NS_AVAILABLE(10_5, 2_0);

@end