- 概念
- 多线程在iOS中应用
- 线程的生命周期和安全问题
@property (assign, atomic) int age;
- (void)setAge:(int)age
{
@synchronized(self) {
_age = age;
}
}
- pthread
-
NSThread
- NSThread的创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
主线程相关用法 + (NSThread *)mainThread; // 获得主线程
- (BOOL)isMainThread; // 是否为主线程
+ (BOOL)isMainThread; // 是否为主线程
获得当前线程 NSThread *current = [NSThread currentThread];
- 线程的调度优先级
-
调度优先级的取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高
- (BOOL)setThreadPriority:(double)p;
- (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
+ (double)threadPriority;
- 线程的名字
-
- (NSString *)name;
- (void)setName:(NSString *)n;
- 创建线程后自动启动线程
-
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
- 隐式创建并启动线程
- 上述2种创建线程方式的优缺点 优点:简单快捷 缺点:无法对线程进行更详细的设置
[self performSelectorInBackground:@selector(run) withObject:nil];
- 线程中的通信
//回到主线程
[self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
//去到任意线程
[self performSelector:<#(SEL)#> onThread:<#(NSThread *)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#> modes:<#(NSArray *)#>]
- GCD
- 任务和队列: 任务:执行的操作 队列:用来存放任务
定制任务,将任务添加到队列当中。(GCD自动将队列中的任务放到对应的线程中,遵循FIFO原则)
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
3.GCD默认提供了全局并发队列,供整个应用使用,不需要手动创建
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); // 获得全局并发队列
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需要释放手动创建的队列
dispatch_queue_t queue = dispatch_get_main_queue()
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程,执行UI刷新操作
});
});
5. GCD的其它函数
延迟执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒后异步执行这里的代码..
});
一次性代码
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只执行1次的代码(这里面默认是线程安全的)
});
队列组:
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(), ^{
// 等前面的异步操作都执行完毕后,回到主线程...
});
- NSOperation
NSLog ( @"%@—2-------" ,[ NSThread currentThread ]);
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
// 当 blockOperation 中的操作完成后 在当前线程中执行下面操作
blockOperation. completionBlock = ^{
* 下载图片的队列
*/
@property (nonatomic, strong) NSOperationQueue *queue;
/** key:url value:operation对象 */
{
if (!_apps) {
NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]];
NSMutableArray *appArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
HMApp *app = [HMApp appWithDict:dict];
[appArray addObject:app];
}
_apps = appArray;
}
return _apps;
}
- (NSOperationQueue *)queue
{
if (!_queue) {
_queue = [[NSOperationQueue alloc] init];
_queue.maxConcurrentOperationCount = 3; // 最大并发数 == 3
}
return _queue;
}
- (NSMutableDictionary *)operations
{
if (!_operations) {
_operations = [NSMutableDictionary dictionary];
}
return _operations;
}
- (NSMutableDictionary *)images
{
if (!_images) {
_images = [NSMutableDictionary dictionary];
}
return _images;
// 保证一个url对应一个HMDownloadOperation
// 保证一个url对应UIImage对象
UIImage *image = self.images[app.icon];
if (image) { // 内存缓存中有图片
cell.imageView.image = image;
} else { // 内存缓存中没有图片, 得下载
// cell.imageView.image = [UIImage imageNamed:@"57437179_42489b0"];
HMDownloadOperation *operation = self.operations[app.icon];
if (operation) { // 正在下载
// ... 暂时不需要做其他事
} else { // 没有正在下载
// 创建操作
operation = [[HMDownloadOperation alloc] init];
operation.url = app.icon;
operation.delegate = self;
operation.indexPath = indexPath;
[self.queue addOperation:operation]; // 异步下载
self.operations[app.icon] = operation;
}
- ( void )downloadOperation:( HMDownloadOperation *)operation didFinishDownload:( UIImage *)image
{
// 1. 移除执行完毕的操作
[ self . operations removeObjectForKey :operation. url ];
if (image) {
// 2. 将图片放到缓存中 (images)
self . images [operation. url ] = image;
// 3. 刷新表格
[ self . tableView reloadRowsAtIndexPaths : @[ operation. indexPath ] withRowAnimation : UITableViewRowAnimationNone ];
// 3. 将图片写入沙盒
// NSData *data = UIImagePNGRepresentation(image);
// [data writeToFile:@"" atomically:<#(BOOL)#>];
}
{
// 开始拖拽
// 暂停队列
[self.queue setSuspended:YES];
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
[self.queue setSuspended:NO];
@protocol HMDownloadOperationDelegate <NSObject>
@optional
- (void)downloadOperation:(HMDownloadOperation *)operation didFinishDownload:(UIImage *)image;
@end
@interface HMDownloadOperation : NSOperation
@property (nonatomic, copy) NSString *url;
@property (nonatomic, strong) NSIndexPath *indexPath;
@property (nonatomic, weak) id<HMDownloadOperationDelegate> delegate;
* 在main方法中实现具体操作
*/
- (void)main
{
@autoreleasepool {
if (self.isCancelled) return;
NSURL *downloadUrl = [NSURL URLWithString:self.url];
NSData *data = [NSData dataWithContentsOfURL:downloadUrl]; // 这行会比较耗时
if (self.isCancelled) return;
UIImage *image = [UIImage imageWithData:data];
if (self.isCancelled) return;
if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) {
dispatch_async(dispatch_get_main_queue(), ^{ // 回到主线程, 传递图片数据给代理对象
[self.delegate downloadOperation:self didFinishDownload:image];
});
}
}