iOS多线程编程及简单封装图片下载

一、多线程概述

1. 程序:由源代码生成的可执行应用。(wechat就是一个程序)
2. 进程:一个正在运行的程序可以看做一个进程。(正在运行的wechat就是一个进程)
3. 线程:程序中独立运行的代码段。(接收wechat消息的代码)

一个进程由一个或多个线程组成。进程只负责调度与分配,线程才是真正的执行单元,负责代码的执行。

4. 单线程:
4.1 每个正在运行的进程,至少包括一个线程,这个线程就是主线程。
4.2 主线程在程序启动时被创建,用于执行main函数。
4.3 只有一个主线程的程序被称为单线程程序。
4.4 主线程负责执行程序的所有代码,这些代码只能顺序执行,无法并发执行。
4.5 UI的展现只能由主线程修改。

5. 多线程:
5.1:拥有多个线程的程序,称为多线程程序。
5.2:iOS允许开辟新的进程, 但是相对于主线程而言,这些线程被称为子线程。
5.3:子线程与主线程都是独立运行的单元,各自的执行互不影响,因此能够并发执行。

6. 单线程与多线程区别:
单线程程序只有一个线程,代码顺序执行,容易出现阻塞。(页面卡住不动)
多线程程序有多个线程,线程间独立运行,避免了阻塞,也提高了程序的运行性能。


eg.模拟主线程阻塞:
创建了一个按钮, 点击触发一个方法,方法计算1加到635500000。

// 创建一个按钮
- (void)createButton
{
    UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
    aButton.frame =CGRectMake(100, 100, 150, 50);
    [aButton setTitle:@"click" forState:UIControlStateNormal];
    [aButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [aButton setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
    [aButton addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:aButton];
}
// 触发事件
- (void)buttonAction:(id)sender
{
    NSInteger sum = 0;
    for (int i = 1; i <= 635500000; i++) {
        sum += i;
        NSLog(@"%ld", sum);
    }
}

二、iOS多线程实现

1. NSThread
NSTread是一个轻量级的多线程,它有两种创建方法。
注意:在多线程方法中需要添加自动释放池;在程序开始系统会为主线程创建自动释放池;手动创建的子线程需要手动添加释放池。
NSThread主要由两种初始化方法:
// 实例化方法
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(calculator) object:nil];
    [thread start];
    [thread release];
    // 类方法
    [NSThread detachNewThreadSelector:@selector(calculator) toTarget:self withObject:nil];

2. NSOperation & NSOperationQueue
2.1  NSOperation类在MVC中属于model类,是用来封装单个任务相关的代码和数据的抽象类。由于是抽象类,我们不能够直接使用这个类,而是使用子类来执行任务。通常与NSOperationQueue结合使用。

eg.NSOperation与NSOperationQueue结合使用
注意:当最大并发数设置为1的时候,能实现线程同步。
<span style="white-space:pre">	</span>CustomOperation *operation = [[CustomOperation alloc] init];
//     将opration放入queue中时不能start, queue会自动调用它的方法开始;
        CustomOperation *operation1 = [[CustomOperation alloc] init];
        NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
//<span style="white-space:pre">	</span>maxConcurrentOperationCount设置最大并发数量
        opQueue.maxConcurrentOperationCount = 1;
    
        [opQueue addOperation:operation];
        [opQueue addOperation:operation1];
    
        [operation release];
        [operation1 release];
        [opQueue release];

2.2 NSInvocationOperation
NSInvocationOperationNSOperation的子类。封装了执行操作的target和action。
eg.
    NSInvocationOperation *invoOpr = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(calculator) object:nil];
    NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
    [queue1 addOperation:invoOpr];
    [invoOpr release];
    [queue1 release];

2.3 NSBlockOperation
NSBlockOperationNSOperation的子类。封装了需要执行操作的代码块。
eg.封装了一个输出0~99的代码块
    NSBlockOperation *blockOpr = [NSBlockOperation blockOperationWithBlock:^{
        @autoreleasepool {
        // block内容就是多线程所要执行的代码;
        for (int i = 0; i < 100; i++) {
            NSLog(@"%d", i);
        }
    }];
    }
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:blockOpr];
    [queue release];
    

3. NSObject实现异步后台执行
NSObject中存在一个最简单的后台执行方法。
eg.
[self performSelectorInBackground:@selector(calculator) withObject:self];

4. GCD(Grand Central Dispatch)
4.1 简介:GCD是苹果公司开发的技术。以优化应用程序支持多核心处理器和其他的对称多处理系统的系统。GCD输入函数级的多线程,性能更高。iOS4以上可用。
GCD以队列的方式工作,先进先出。
GCD中有两种队列:SerialQueue,Concurrent。其中serial一次只执行一个任务。Concurrent可以并发执行多个任务。

4.2 Serial
e.g Serial实例

- (void)createSerialGCD
{
    // 第一步: 创建一个同步线程GCD队列;
    dispatch_queue_t queue = dispatch_queue_create("first", DISPATCH_QUEUE_SERIAL);
    // 第二步: 异步执行同步线程队列
    dispatch_async(queue, ^{
        // 多线程的代码, 与主线程异步执行;
        // GCD中不能使用自动释放池;----C语言
        // 子线程不可以对view修改;
        // 下载一张图片, 并显示到界面上, (下载用同步下载方式);
        NSString *str1 = @"http://g.hiphotos.baidu.com/image/scrop%3D100/sign=94ffc93249fbfbedd807712008cdc606/21a4462309f7905256721f330ef3d7ca7bcbd54a.jpg";
        // 中文字符显示
        NSString *str2 = [str1 stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSURL *url = [NSURL URLWithString:str2];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        [request setHTTPMethod:@"GET"];
        NSURLResponse *response = nil;
        NSError *error = nil;
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
        UIImage *image = [UIImage imageWithData:data];

        // 显示到界面上, 所有跟UI相关的内容全部都要在主线程运行
        // 返回主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            // 在主线程运行
            UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 150, 375, 300)];
            imgView.image = image;
            [self.view addSubview:imgView];
            [imgView release];
        });
    });
}

4.3 Concurrent
e.g Concurrent实例
- (void)createConcurrentGCD
{
    // global_queue默认并行队列
    //DISPATCH_QUEUE_PRIORITY_DEFAULT,有四种级别

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSURL *url = [NSURL URLWithString:@"http://img.hb.aicdn.com/258541cf3d0b5dc5c68f9f3096a830b68288d2011f65f-00EuvV_fw658"];
        //    同步下载
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 350, 60, 60)];
            imgView.image = image;
            [self.view addSubview:imgView];
            [imgView release];
        });
        
    });
    
}




SDWebImage的简单实现

#import "ToolsModel.h"

@implementation ToolsModel
// 获取图片路径
+ (NSString *)libraryPathWithImageName:(NSString *)imageStr
{
    NSArray *array = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
    NSString *rootPath = [array firstObject];
    rootPath = [NSString stringWithFormat:@"%@/%@", rootPath, imageStr];
    NSLog(@"%@", rootPath);
    return rootPath;
}
// 判断文件是否存在
+ (BOOL)imageExist:(NSString *)imageStr
{
    NSString *path = [ToolsModel libraryPathWithImageName:imageStr];
    
    NSFileManager *imageManager = [NSFileManager defaultManager];
    
    return [imageManager fileExistsAtPath:path];
    
}

// 文件存储
+ (void)saveimage:(NSData *)data imageName:(NSString *)imageName
{
    
    NSString *path = [ToolsModel libraryPathWithImageName:imageName];
    [data writeToFile:path atomically:YES];
}
// 获取本地文件
+ (NSData *)readimage:(NSString *)imageStr
{
    if ([ToolsModel imageExist:imageStr]) {
        
        NSString *path = [ToolsModel libraryPathWithImageName:imageStr];
        NSData *data = [NSData dataWithContentsOfFile:path];
        return data;
    }
    return [NSData data];
    
}
@end
#import "UIImageView+WebCache.h"
#import "ToolsModel.h"
@implementation UIImageView (WebCache)


- (void)setImageWithUrl:(NSString *)urlStr placeholder:(NSString *)placeholder
{
    
    NSString *aStr = [urlStr stringByReplacingOccurrencesOfString:@"/" withString:@"a"];
    NSString *bStr = [aStr stringByReplacingOccurrencesOfString:@":" withString:@"b"];
    NSString *str = [bStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    if (![ToolsModel imageExist:str]) {
        NSString *str = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSURL *url = [NSURL URLWithString:str];
        [self downloadWithUrl:url imageName:str];
        
    } else {
        NSData *data = [ToolsModel readimage:str];
        UIImage *image = [UIImage imageWithData:data];
        self.image = image;
    }
}

- (void)downloadWithUrl:(NSURL *)url imageName:(NSString *)imagename
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSData *data = [NSData dataWithContentsOfURL:url];
        [ToolsModel saveimage:data imageName:imagename];
        dispatch_async(dispatch_get_main_queue(), ^{
            UIImage *image = [UIImage imageWithData:data];
            self.image = image;
        });
    });
}
@end
#import "ViewController.h"
#import "UIImageView+WebCache.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self createImageView];
}


- (void)createImageView
{
    UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 200, 360, 200)];
    [imgView setImageWithUrl:@"http://img.hb.aicdn.com/258541cf3d0b5dc5c68f9f3096a830b68288d2011f65f-00EuvV_fw658" placeholder:nil];
    [self.view addSubview:imgView];
    [imgView release];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}



                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值