前言
基本概念
- 进程: 一个具有一定独立功能的程序关于某个数据集合的一次运行活动。可以理解成一个运行中的应用程序。
- 线程: 程序执行流的最小单元,线程是进程中的一个实体。
- 同步: 只能在当前线程按先后顺序依次执行,不开启新线程。
- 异步: 可以在当前线程开启多个新线程执行,可不按顺序执行。
- 队列: 装载线程任务的队形结构。
- 并发: 线程执行可以同时一起进行执行。
- 串行: 线程执行只能依次逐一先后有序的执行。
I、 多线程
- Your application does not need to create these objects explicitly;
1)each thread, including the application’s main thread, has an associated run loop object. 2)Only secondary threads need to run their run loop explicitly, however. The app frameworks automatically set up and run the run loop on the main thread as part of the application startup proces
1、1 pthread_t
- pthread_t 的定义和演示
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
//01 pthread的定义 >typedef __darwin_pthread_t pthread_t; >typedef struct _opaque_pthread_t *__darwin_pthread_t; >struct _opaque_pthread_t { long __sig; struct __darwin_pthread_handler_rec *__cleanup_stack; char __opaque[__PTHREAD_SIZE__]; }; struct __darwin_pthread_handler_rec { void (*__routine)(void *); // Routine to call void *__arg; // Argument to pass struct __darwin_pthread_handler_rec *__next; }; //02-pthread(演示) #import <pthread.h> void *run(void *data) { for (int i = 0; i<10000; i++) { NSLog(@"touchesBegan----%d-----%@", i, [NSThread currentThread]); } return NULL; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // 创建线程 pthread_t myRestrict; pthread_create(&myRestrict, NULL, run, NULL); }
1、2 NSThread
一个NSThread对象就代表一条线程
- 创建、启动NSThread线程
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
//1、创建、启动线程 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [thread start];//启动线程 // 线程一启动,就会在线程thread中执行self的run方法 // 2、主线程相关用法 + (NSThread *)mainThread; // 获得主线程 - (BOOL)isMainThread; // 是否为主线程 + (BOOL)isMainThread; // 是否为主线程 //3、 其他用法 // 1)获得当前线程 NSThread *current = [NSThread currentThread]; // 2)线程的调度优先级 + (double)threadPriority; + (BOOL)setThreadPriority:(double)p; - (double)threadPriority; - (BOOL)setThreadPriority:(double)p;//调度优先级的取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高 // 3)线程的名字 - (void)setName:(NSString *)n; - (NSString *)name; //4、其他创建线程方式 // 创建线程后自动启动线程 [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil]; // 隐式创建并启动线程 [self performSelectorInBackground:@selector(run) withObject:nil]; // 上述2种创建线程方式的优缺点:优点:简单快捷 ; 缺点:无法对线程进行更详细的设置
- 线程的状态
- 控制线程状态
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// 一、控制线程状态 //1、 启动线程 - (void)start; // 进入就绪状态 -> 运行状态。当线程任务执行完毕,自动进入死亡状态 // 2、阻塞(暂停)线程 + (void)sleepUntilDate:(NSDate *)date; + (void)sleepForTimeInterval:(NSTimeInterval)ti;// 进入阻塞状态 // 3、强制停止线程 + (void)exit;// 进入死亡状态// 注意:一旦线程停止(死亡)了,就不能再次开启任务 // 多线程的安全隐患: // 1) 资源共享:1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源;比如多个线程访问同一个对象、同一个变量、同一个文件。当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题 // 2)安全隐患解决 – 互斥锁 // 二、互斥锁使用格式 @synchronized(锁对象) { // 需要锁定的代码 }//注意:锁定1份代码只用1把锁,用多把锁是无效的 // 1、互斥锁的优缺点: // 优点:能有效防止因多线程抢夺资源造成的数据安全问题 // 缺点:需要消耗大量的CPU资源 //2、 互斥锁的使用前提:多条线程抢夺同一块资源 //3、 相关专业术语: // 1)线程同步:线程同步的意思是:多条线程在同一条线上执行(按顺序地执行任务) // 2)互斥锁,就是使用了线程同步技术
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// OC在定义属性时有nonatomic和atomic两种选择 1)atomic:原子属性,为setter方法加锁(默认就是atomic) 2)nonatomic:非原子属性,不会为setter方法加锁 //一、原子和非原子属性的选择 1、nonatomic和atomic对比 1)atomic:线程安全,需要消耗大量的资源 2)nonatomic:非线程安全,适合内存小的移动设备 //2、 iOS开发的建议 1)所有属性都声明为nonatomic 2)尽量避免多线程抢夺同一块资源 3)尽量将加锁、资源抢夺的业务逻辑交给服务
1、3 GCD(Grand Central Dispatch)
- 纯C语言,提供了非常多强大的函数。GCD是苹果公司为多核的并行运算提出的解决方案
GCD会自动利用更多的CPU内核(比如双核、四核) GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程) 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
1、3、1 任务和队列
- GCD中有2个核心概念
任务:执行什么操作 队列:用来存放任务
- GCD的使用就2个步骤
1)定制任务:确定想做的事情 2) 将任务添加到队列中: GCD会自动将队列中的任务取出,放到对应的线程中执行 任务的取出遵循队列的FIFO原则:先进先出,后进后出
- 执行任务
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// GCD中有2个用来执行任务的函数 //1) 用同步的方式执行任务 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);//queue:队列 block:任务 //2) 用异步的方式执行任务 dispatch_async(dispatch_queue_t queue, dispatch_block_t block); // 同步和异步的区别 同步:只能在当前线程中执行任务,不具备开启新线程的能力 异步:可以在新的线程中执行任务,具备开启新线程的能力
队列的类型:Concurrent Dispatch Queue、Serial Dispatch Queue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
//0、 GCD的队列可以分为2大类型 // 1)并发队列(Concurrent Dispatch Queue) 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务);并发功能只有在异步(dispatch_async)函数下才有效 // 2)串行队列(Serial Dispatch Queue) 让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务) //1、 容易混淆的术语:有4个术语比较容易混淆:同步、异步、并发、串行 //1) 同步和异步主要影响:能不能开启新的线程 同步:在当前线程中执行任务,不具备开启新线程的能力 异步:在新的线程中执行任务,具备开启新线程的能力 //2) 并发和串行主要影响:任务的执行方式 并发:多个任务并发(同时)执行 串行:一个任务执行完毕后,再执行下一个任务 //一、 并发队列 // GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建 // 1)使用dispatch_get_global_queue函数获得全局的并发队列 dispatch_queue_t dispatch_get_global_queue( dispatch_queue_priority_t priority, // 队列的优先级 unsigned long flags); // 此参数暂时无用,用0即可 // 例子: dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获得全局并发队列 // 2)全局并发队列的优先级 #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高 #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中) #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低 #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台 // 二、串行队列 //1) GCD中获得串行有2种途径 //1)) 使用dispatch_queue_create函数创建串行队列 dispatch_queue_t dispatch_queue_create(const char *label, // 队列名称 dispatch_queue_attr_t attr); // 队列属性,一般用NULL即可 dispatch_queue_t queue = dispatch_queue_create("cn.itcast.queue", NULL); // 创建 dispatch_release(queue); // 非ARC需要释放手动创建的队列 //2)) 使用主队列(跟主线程相关联的队列) 主队列是GCD自带的一种特殊的串行队列 放在主队列中的任务,都会放到主线程中执行 使用dispatch_get_main_queue()获得主队列 dispatch_queue_t queue = dispatch_get_main_queue(); - 各种队列的执行效果
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
从子线程回到主线程 dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 执行耗时的异步操作... dispatch_async(dispatch_get_main_queue(), ^{ // 回到主线程,执行UI刷新操作 }); }); - 延时执行
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// 调用NSObject的方法 [self performSelector:@selector(run) withObject:nil afterDelay:2.0];// 2秒后再调用self的run方法 // 使用GCD函数 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒后执行这里的代码... 在哪个线程执行,跟队列类型有关 }); - 一次性代码
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// 使用dispatch_once函数能保证某段代码在程序运行过程中只被执行1次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 只执行1次的代码(这里面默认是线程安全的) }); - 队列组:等2个异步操作都执行完毕后,再回到主线程执行操作
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// 有这么1种需求 首先:分别异步执行2个耗时的操作 其次:等2个异步操作都执行完毕后,再回到主线程执行操作 // 如果想要快速高效地实现上述需求,可以考虑用队列组 dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 执行1个耗时的异步操作 }); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 执行1个耗时的异步操作 }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // 等前面的异步操作都执行完毕后,回到主线程... }); - 单例模式
pod KNIosCommonTool
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// 单例模式的作用 可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问;从而方便地控制了实例个数,并节约系统资源 // 单例模式的使用场合 在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次) //1、 单例模式在ARC\MRC环境下的写法有所不同,需要编写2套不同的代码 // 1)可以用宏判断是否为ARC环境 #if __has_feature(objc_arc) // ARC #else // MRC #endif // 一、单例模式 - ARC // ARC中,单例模式的实现 // 1)在.m中保留一个全局的static的实例 static id _instance; //2) 重写allocWithZone:方法,在这里创建唯一的实例(注意线程安全) + (id)allocWithZone:(struct _NSZone *)zone { if (_instance == nil) { // 防止频繁加锁 @synchronized(self) { if (_instance == nil) { // 防止创建多次 _instance = [super allocWithZone:zone]; } } } return _instance; } //3) 提供1个类方法让外界访问唯一的实例 + (instancetype)sharedMusicTool { if (_instance == nil) { // 防止频繁加锁 @synchronized(self) { if (_instance == nil) { // 防止创建多次 _instance = [[self alloc] init]; } } } return _instance; } // 4)实现copyWithZone:方法 - (id)copyWithZone:(struct _NSZone *)zone { return _instance; } // 二、单例模式 – 非ARC // 非ARC中(MRC),单例模式的实现(比ARC多了几个步骤) // 实现内存管理方法 - (id)retain { return self; } - (NSUInteger)retainCount { return 1; } - (oneway void)release {} - (id)autorelease { return self; } // 三、>pod KNIosCommonTool,整合之后的代码 // // HSSingleton.h // // Created by devzkn on 5/4/16. // #ifndef HSSingleton_h #define HSSingleton_h //头文件的单例内容 #define HSSingletonH(classname) +(instancetype)share##classname //.m文件的单例代码 #if __has_feature(objc_arc) #define HSSingletonM(classname) \ static id _instance;\ +(instancetype)share##classname{\ static dispatch_once_t onceToken;\ dispatch_once(&onceToken, ^{\ _instance = [[self alloc]init];\ });\ return _instance;\ }\ - (id)copyWithZone:(NSZone *)zone{\ return _instance;\ }\ + (instancetype)allocWithZone:(struct _NSZone *)zone{\ static dispatch_once_t onceToken;\ dispatch_once(&onceToken, ^{\ _instance = [super allocWithZone:zone];\ });\ return _instance;\ } #else #define HSSingletonM(classname) \ static id _instance;\ +(instancetype)share##classname{\ static dispatch_once_t onceToken;\ dispatch_once(&onceToken, ^{\ _instance = [[self alloc]init];\ });\ return _instance;\ }\ - (id)copyWithZone:(NSZone *)zone{\ return _instance;\ }\ + (instancetype)allocWithZone:(struct _NSZone *)zone{\ static dispatch_once_t onceToken;\ dispatch_once(&onceToken, ^{\ _instance = [super allocWithZone:zone];\ });\ return _instance;\ }\ - (oneway void)release{\ }\ - (instancetype)retain{\ return self;\ }\ - (NSUInteger)retainCount{\ return 1;\ }\ - (instancetype)autorelease{\ return self;\ } #endif #endif /* HSSingleton_h */
1.4 NSOperation
- 简介
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// NSOperation的作用 配合使用 NSOperation 和NSOperationQueue也能实现多线程编程 // NSOperation和NSOperationQueue实现多线程的具体步骤 1)先将需要执行的操作封装到一个NSOperation对象中 2)然后将NSOperation对象添加到NSOperationQueue中 3)系统会自动将NSOperationQueue中的NSOperation取出来 4)将取出的NSOperation封装的操作放到一条新线程中执行
1.4.0 NSOperation的子类
NSOperation的子类
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类 //使用NSOperation子类的方式有3种 1)NSInvocationOperation 2)NSBlockOperation 3)自定义子类继承NSOperation,实现内部相应 - 1) NSInvocationOperation *
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// 创建 NSInvocationOperation 对象 - (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg; // 调用start方法开始执行操作 - (void)start;//一旦执行操作,就会调用target的sel方法 // 注意 默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作 只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作 - 2) NSBlockOperation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// 创建NSBlockOperation对象 + (id)blockOperationWithBlock:(void (^)(void))block; // 通过addExecutionBlock:方法添加更多的操作 - (void)addExecutionBlock:(void (^)(void))block; // 注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作 - 3)自定义子类继承NSOperation,实现内部相应
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// 自定义 NSOperation 的步骤很简单 1)重写- (void)main方法,在里面实现想执行的任务 2)重写- (void)main方法的注意点 // 自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池) // 经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应 //一、 例子 @class HMDownloadOperation; @protocol HMDownloadOperationDelegate <NSObject> @optional - (void)downloadOperation:(HMDownloadOperation *)operation didFinishDownload:(UIImage *)image; @end @interface HMDownloadOperation : NSOperation @property (nonatomic, copy) NSString *imageUrl; @property (nonatomic, strong) NSIndexPath *indexPath; @property (nonatomic, weak) id<HMDownloadOperationDelegate> delegate; @end @implementation HMDownloadOperation - (void)main { @autoreleasepool { if (self.isCancelled) return; NSURL *url = [NSURL URLWithString:self.imageUrl]; NSData *data = [NSData dataWithContentsOfURL:url]; // 下载 UIImage *image = [UIImage imageWithData:data]; // NSData -> UIImage if (self.isCancelled) return; // 回到主线程 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) { [self.delegate downloadOperation:self didFinishDownload:image]; } }]; } } - NSOperationQueue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// NSOperationQueue的作用 1)NSOperation可以调用start方法来执行任务,但默认是同步执行的 2)如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作 // 1、添加操作到NSOperationQueue中 - (void)addOperation:(NSOperation *)op; - (void)addOperationWithBlock:(void (^)(void))block; // 最大并发数:同时执行的任务数;比如,同时开3个线程执行3个任务,并发数就是3 // 2、最大并发数的相关方法 - (NSInteger)maxConcurrentOperationCount; - (void)setMaxConcurrentOperationCount:(NSInteger)cnt; //3、 队列的取消、暂停、恢复 // 1)取消队列的所有操作 - (void)cancelAllOperations;//提示:也可以调用NSOperation的- (void)cancel方法取消单个操作 //2) 暂停和恢复队列 - (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列 - (BOOL)isSuspended;
1.4.1 NSOperation的方法
- 操作优先级
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// 设置NSOperation在queue中的优先级,可以改变操作的执行优先级 - (NSOperationQueuePriority)queuePriority; - (void)setQueuePriority:(NSOperationQueuePriority)p; // 优先级的取值 NSOperationQueuePriorityVeryLow = -8L, NSOperationQueuePriorityLow = -4L, NSOperationQueuePriorityNormal = 0, NSOperationQueuePriorityHigh = 4, NSOperationQueuePriorityVeryHigh = 8 - 操作的监听
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
可以监听一个操作的执行完毕 - (void (^)(void))completionBlock; - (void)setCompletionBlock:(void (^)(void))block; - 操作依赖
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
1)NSOperation之间可以设置依赖来保证执行顺序 比如一定要让操作A执行完后,才能执行操作B,可以这么写 [operationB addDependency:operationA]; // 操作B依赖于操作A 2)可以在不同queue的NSOperation之间创建依赖关系: 注意:不能相互依赖;比如A依赖B,B依赖A
1.4.2 cell下载图片思路 – 用沙盒缓存(使用md5生成图片名称,保证唯一;或者使用url)
- 使用operations实现下载操作
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
#define HMAppImageFile(url) [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[url lastPathComponent]] #import "HMAppsViewController.h" #import "HMApp.h" @interface HMAppsViewController () /** * 所有的应用数据 */ @property (nonatomic, strong) NSMutableArray *apps; /** * 存放所有下载操作的队列 */ @property (nonatomic, strong) NSOperationQueue *queue; /** * 存放所有的下载操作(url是key,operation对象是value) */ @property (nonatomic, strong) NSMutableDictionary *operations; /** * 存放所有下载完的图片 */ @property (nonatomic, strong) NSMutableDictionary *images; @end @implementation HMAppsViewController #pragma mark - 懒加载 - (NSMutableArray *)apps { if (!_apps) { // 1.加载plist NSString *file = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"]; NSArray *dictArray = [NSArray arrayWithContentsOfFile:file]; // 2.字典 --> 模型 NSMutableArray *appArray = [NSMutableArray array]; for (NSDictionary *dict in dictArray) { HMApp *app = [HMApp appWithDict:dict]; [appArray addObject:app]; } // 3.赋值 self.apps = appArray; // _apps = appArray; } return _apps; } - (NSOperationQueue *)queue { if (!_queue) { self.queue = [[NSOperationQueue alloc] init]; } return _queue; } - (NSMutableDictionary *)operations { if (!_operations) { self.operations = [[NSMutableDictionary alloc] init]; } return _operations; } - (NSMutableDictionary *)images { if (!_images) { self.images = [[NSMutableDictionary alloc] init]; } return _images; } #pragma mark - 初始化方法 - (void)viewDidLoad { [super viewDidLoad]; // 这里仅仅是block对self进行了引用,self对block没有任何引用 [UIView animateWithDuration:2.0 animations:^{ self.view.frame = CGRectMake(0, 0, 100, 100); }]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // 移除所有的下载操作缓存 [self.queue cancelAllOperations]; [self.operations removeAllObjects]; // 移除所有的图片缓存 [self.images removeAllObjects]; } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.apps.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID = @"app"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } // 取出模型 HMApp *app = self.apps[indexPath.row]; // 设置基本信息 cell.textLabel.text = app.name; cell.detailTextLabel.text = app.download; // 先从images缓存中取出图片url对应的UIImage UIImage *image = self.images[app.icon]; if (image) { // 说明图片已经下载成功过(成功缓存) cell.imageView.image = image; } else { // 说明图片并未下载成功过(并未缓存过) // 获得caches的路径, 拼接文件路径 NSString *file = HMAppImageFile(app.icon); // 先从沙盒中取出图片 NSData *data = [NSData dataWithContentsOfFile:file]; if (data) { // 沙盒中存在这个文件 cell.imageView.image = [UIImage imageWithData:data]; } else { // 沙盒中不存在这个文件 // 显示占位图片 cell.imageView.image = [UIImage imageNamed:@"placeholder"]; // 下载图片 [self download:app.icon indexPath:indexPath]; } } return cell; } /** * 下载图片 * * @param imageUrl 图片的url */ - (void)download:(NSString *)imageUrl indexPath:(NSIndexPath *)indexPath { // 取出当前图片url对应的下载操作(operation对象) NSBlockOperation *operation = self.operations[imageUrl]; if (operation) return; // 创建操作,下载图片 __weak typeof(self) appsVc = self; operation = [NSBlockOperation blockOperationWithBlock:^{ NSURL *url = [NSURL URLWithString:imageUrl]; NSData *data = [NSData dataWithContentsOfURL:url]; // 下载 UIImage *image = [UIImage imageWithData:data]; // NSData -> UIImage // 回到主线程 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ // 存放图片到字典中 if (image) { appsVc.images[imageUrl] = image; #warning 将图片存入沙盒中 // UIImage --> NSData --> File(文件) NSData *data = UIImagePNGRepresentation(image); // 获得caches的路径, 拼接文件路径 // NSString *file = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[imageUrl lastPathComponent]]; [data writeToFile:HMAppImageFile(imageUrl) atomically:YES]; // UIImageJPEGRepresentation(<#UIImage *image#>, 1.0) } // 从字典中移除下载操作 (防止operations越来越大,保证下载失败后,能重新下载) [appsVc.operations removeObjectForKey:imageUrl]; // 刷新表格 [appsVc.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; }]; }]; // 添加操作到队列中 [self.queue addOperation:operation]; // 添加到字典中 (这句代码为了解决重复下载) self.operations[imageUrl] = operation; } /** * 当用户开始拖拽表格时调用 */ - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { // 暂停下载 [self.queue setSuspended:YES]; } /** * 当用户停止拖拽表格时调用 */ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { // 恢复下载 [self.queue setSuspended:NO]; } @end - SDWebImage
图片下载、图片缓存、下载进度监听、gif处理
II、Thread Costs
- The core structures needed to manage your thread and coordinate its scheduling are stored in the kernel using wired memory.
Your thread’s stack space and per-thread data is stored in your program’s memory space. Most of these structures are created and initialized when you first create the thread—a process that can be relatively expensive because of the required interactions with the kernel.
2.1 Thread creation costs
- Kernel data structures
Approximately 1 KB
- Stack space
512 KB (secondary threads) 8 MB (OS X main thread) 1 MB (iOS main thread)
- Creation time
Approximately 90 microseconds
- see Concurrency Programming Guide.
III、Creating a Thread
3.1 Using NSThread
- There are two ways to create a thread using the NSThread class:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
//1)Use the detachNewThreadSelector:toTarget:withObject: class method to spawn the new thread. [NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil]; //2) Create a new NSThread object and call its `start `method. (Supported only in iOS and OS X v10.5 and later.) NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(myThreadMainMethod:) object:nil]; [myThread start]; // Actually create the thread 3.2 Using POSIX Threads
- OS X and iOS provide C-based support for creating threads using the
POSIX thread API
This technology can actually be used in any type of application (including Cocoa and Cocoa Touch applications) and might be more convenient if you are writing your software for multiple platforms
- Creating a thread in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
#include <assert.h> #include <pthread.h> void* PosixThreadMainRoutine(void* data) { // Do some work here. return NULL; } void LaunchThread() { // Create the thread using POSIX routines. pthread_attr_t attr; pthread_t posixThreadID; int returnVal; returnVal = pthread_attr_init(&attr); assert(!returnVal); returnVal = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); assert(!returnVal); int threadError = pthread_create(&posixThreadID, &attr, &PosixThreadMainRoutine, NULL); returnVal = pthread_attr_destroy(&attr); assert(!returnVal); if (threadError != 0) { // Report an error. } }
IV、Using NSObject to Spawn a Thread
- Using NSObject to Spawn a Thread
[myObj performSelectorInBackground:@selector(doSomething) withObject:nil];
V、Writing Your Thread Entry Routine
5.1 Creating an Autorelease Pool
- Defining your thread entry point routine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
- (void)myThreadMainRoutine { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Top-level pool // Do thread work here. [pool release]; // Release the objects in the pool. }
VI、 Terminating a Thread
- Checking for an exit condition during a long job
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
- (void)threadMainRoutine { BOOL moreWorkToDo = YES; BOOL exitNow = NO; NSRunLoop* runLoop = [NSRunLoop currentRunLoop]; // Add the exitNow BOOL to the thread dictionary. NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary]; [threadDict setValue:[NSNumber numberWithBool:exitNow] forKey:@"ThreadShouldExitNow"]; // Install an input source. [self myInstallCustomInputSource]; while (moreWorkToDo && !exitNow) { // Do one chunk of a larger body of work here. // Change the value of the moreWorkToDo Boolean when done. // Run the run loop but timeout immediately if the input source isn't waiting to fire. [runLoop runUntilDate:[NSDate date]]; // Check to see if an input source handler changed the exitNow value. exitNow = [[threadDict valueForKey:@"ThreadShouldExitNow"] boolValue]; } }
See Also
/Users/devzkn/bin/knpost Thread_Management an overview of the thread technologies available in OS X and iOS along with examples of how to use those technologies in your applications -t Thread #原来""的参数,需要自己加上""
转载请注明:张坤楠的博客 > Thread_Management
Related Issues not found
Please contact @zhangkn to initialize the comment