dispatch_get_current_queue 废弃

由于在iOS7后dispatch_get_current_queue被废弃,本文探讨了其原因和替代方案。在非GCD线程中,该函数返回的是com.apple.root.default-overcommit-priority队列,这可能与实际执行的队列不符。文章详细分析了不同线程类型与dispatch_queue的关系,并列举了各种API获取的队列及其应用场景。

由于iOS7以后 dispatch_get_current_queue 被废弃,所以需要寻找一个替代的方案。

发现 dispatch_get_current_queue 并没有字面上那么简单。

这个函数一般都会跟 dispatch_async 等API配合,

但是试想一下,我们自己创建的线程(比如 NSThread)跟 dispatch_queue_t 没有关系,

那么在我们的线程中调用 dispatch_get_current_queue 会返回什么呢?

     [NSThread detachNewThreadSelector:@selector(onPlay:) toTarget:self withObject:nil];

     - (void)onPlay
     {
         dispatch_queue_t dispatch_queue = dispatch_get_current_queue(); // 这里会返回什么?
     }

在上面的代码中,我们并没有将onPlay显示投递到某一个dispatch_queue中,

但是dispatch_get_current_queue还是会返回一个dispatch_queue,

一个名字叫 com.apple.root.default-overcommit-priority 的 dispatch_queue!

但是!

如果在 onPlay 中打断点,你会发现,onPlay 并不在 com.apple.root.default-overcommit-priority 这个队列中!

     [NSThread detachNewThreadSelector:@selector(onPlay:) toTarget:self withObject:nil];

     - (void)onPlay
     {
          NSLog(@"1");
          dispatch_async(dispatch_get_current_queue(), ^{
               NSLog(@"2");
          }); 
     }

两句NSLog将不在同一个queue中打印!

好,以下分析dispatch_get_current_queue更深一层的行为。


先分析官方文档的说法:

函数声明:

     dispatch_queue_t dispatch_get_current_queue(void);


描述(description):


     Returns the queue on which the currently executing block is running.

     返回当前所在的队列(dispatch_queue_t)。


详述(discussion):

iOS 开发中,处理图片加载尤其是从相册中加载大量图片时,通常会涉及到多线程操作,以避免阻塞主线程并提高用户体验。`dispatch_async` 和 `TZImageManager` 是实现这一目标的重要工具。以下是对使用 `dispatch_async` 和 `TZImageManager` 实现多线程加载相册数据的代码逻辑进行分析与优化的详细说明。 ### 图片管理与多线程加载的基本逻辑 `TZImageManager` 是一个封装了图片获取与缓存的类,通常用于从相册中读取图片资源。为了防止主线程阻塞,图片的获取和处理通常会使用 `dispatch_async` 将任务提交到后台队列执行。例如: ```objective-c dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 使用 TZImageManager 获取图片 UIImage *image = [tzImageManager getImage:asset]; dispatch_async(dispatch_get_main_queue(), ^{ // 在主线程更新 UI self.imageView.image = image; }); }); ``` 上述代码通过 `dispatch_async` 将图片获取任务提交到全局队列中执行,确保不会阻塞主线程。当图片获取完成后,再次使用 `dispatch_async` 将 UI 更新操作提交到主队列执行,以保证 UI 操作在主线程完成。 ### 优化点分析与建议 #### 1. **使用合适的队列优先级** 在使用 `dispatch_get_global_queue` 时,可以通过指定队列的优先级来优化任务的执行顺序。例如: ```objective-c dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); ``` 将图片加载任务分配到低优先级队列,可以避免影响其他关键任务的执行,同时也能减少对主线程的干扰。 #### 2. **限制并发任务数量** 在加载大量图片时,可能会创建过多的异步任务,导致内存占用过高。可以通过使用 `NSOperationQueue` 或者 `dispatch_semaphore_t` 来限制并发任务的数量。例如,使用信号量控制并发数: ```objective-c dispatch_semaphore_t semaphore = dispatch_semaphore_create(3); // 最多同时执行 3 个任务 for (PHAsset *asset in assets) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); UIImage *image = [tzImageManager getImage:asset]; dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = image; dispatch_semaphore_signal(semaphore); }); }); } ``` 上述代码通过信号量限制了并发执行的任务数量,从而减少内存压力。 #### 3. **优化图片加载与缓存机制** `TZImageManager` 内部通常已经实现了图片缓存机制,但在实际使用中,可以通过自定义缓存策略进一步优化。例如,使用 `NSCache` 或 `SDURLCache` 来缓存已经加载过的图片,避免重复加载。 ```objective-c @interface TZImageManager () @property (nonatomic, strong) NSCache<NSString *, UIImage *> *imageCache; @end @implementation TZImageManager - (instancetype)init { self = [super init]; if (self) { _imageCache = [[NSCache alloc] init]; } return self; } - (UIImage *)getImage:(PHAsset *)asset { NSString *cacheKey = asset.localIdentifier; UIImage *cachedImage = [self.imageCache objectForKey:cacheKey]; if (cachedImage) { return cachedImage; } // 从相册中加载图片 UIImage *image = [self loadFromAsset:asset]; [self.imageCache setObject:image forKey:cacheKey]; return image; } @end ``` 通过缓存机制,可以显著减少重复加载图片的开销,提高应用性能。 #### 4. **使用 `dispatch_barrier_async` 保证线程安全** 当多个线程同时访问共享资源(如缓存)时,可能会导致数据竞争问题。为了避免这种情况,可以使用 `dispatch_barrier_async` 确保写入操作的线程安全性: ```objective-c dispatch_queue_t cacheQueue = dispatch_queue_create("com.example.cacheQueue", DISPATCH_QUEUE_CONCURRENT); - (void)cacheImage:(UIImage *)image forKey:(NSString *)key { dispatch_barrier_async(cacheQueue, ^{ [self.imageCache setObject:image forKey:key]; }); } - (UIImage *)getImageForKey:(NSString *)key { __block UIImage *cachedImage = nil; dispatch_sync(cacheQueue, ^{ cachedImage = [self.imageCache objectForKey:key]; }); return cachedImage; } ``` 通过 `dispatch_barrier_async` 和 `dispatch_sync`,可以确保缓存操作的线程安全,避免数据竞争问题。 #### 5. **避免频繁切换线程** 在多线程环境中,频繁地在后台线程和主线程之间切换可能会引入额外的性能开销。因此,在处理图片数据时,应尽量减少不必要的线程切换。例如,在后台线程完成图片处理后,可以直接将处理好的图片传递给主线程进行 UI 更新,而不是在后台线程中多次切换线程。 ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值