AFNetworking 中 GCD 的使用(4)
2020-01-15 本文已影响0人
老猫_2017
GCD in AFNetworking 的使用
AFAutoPurgingImageCache 处理图片缓存
- 创建并发队列
- (instancetype)initWithMemoryCapacity:(UInt64)memoryCapacity preferredMemoryCapacity:(UInt64)preferredMemoryCapacity {
if (self = [super init]) {
...
NSString *queueName = [NSString stringWithFormat:@"com.alamofire.autopurgingimagecache-%@", [[NSUUID UUID] UUIDString]];
self.synchronizationQueue = dispatch_queue_create([queueName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT);
...
}
return self;
}
- 并发读操作, 此处只是并发读,同步在当前操作线程
- (UInt64)memoryUsage {
__block UInt64 result = 0;
dispatch_sync(self.synchronizationQueue, ^{
result = self.currentMemoryUsage;
});
return result;
}
// dispatch_sync 在此处时同步等待block 执行完毕
- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier {
__block UIImage *image = nil;
dispatch_sync(self.synchronizationQueue, ^{
AFCachedImage *cachedImage = self.cachedImages[identifier];
image = [cachedImage accessImage];
});
return image;
}
- 异步并行屏障写操作,保证,写时操作唯一,
- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier {
dispatch_barrier_async(self.synchronizationQueue, ^{
// 更新访问时间 如果已存在
AFCachedImage *cacheImage = [[AFCachedImage alloc] initWithImage:image identifier:identifier];
AFCachedImage *previousCachedImage = self.cachedImages[identifier];
if (previousCachedImage != nil) {
self.currentMemoryUsage -= previousCachedImage.totalBytes;
}
self.cachedImages[identifier] = cacheImage;
self.currentMemoryUsage += cacheImage.totalBytes;
});
dispatch_barrier_async(self.synchronizationQueue, ^{
// 如果满容量,清理
if (self.currentMemoryUsage > self.memoryCapacity) {
UInt64 bytesToPurge = self.currentMemoryUsage - self.preferredMemoryUsageAfterPurge;
NSMutableArray <AFCachedImage*> *sortedImages = [NSMutableArray arrayWithArray:self.cachedImages.allValues];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastAccessDate"
ascending:YES];
[sortedImages sortUsingDescriptors:@[sortDescriptor]];
UInt64 bytesPurged = 0;
for (AFCachedImage *cachedImage in sortedImages) {
[self.cachedImages removeObjectForKey:cachedImage.identifier];
bytesPurged += cachedImage.totalBytes;
if (bytesPurged >= bytesToPurge) {
break;
}
}
self.currentMemoryUsage -= bytesPurged;
}
});
}
- 同步屏障写操作
- (BOOL)removeImageWithIdentifier:(NSString *)identifier {
__block BOOL removed = NO;
dispatch_barrier_sync(self.synchronizationQueue, ^{
AFCachedImage *cachedImage = self.cachedImages[identifier];
if (cachedImage != nil) {
[self.cachedImages removeObjectForKey:identifier];
self.currentMemoryUsage -= cachedImage.totalBytes;
removed = YES;
}
});
return removed;
}
//dispatch_barrier_sync 的含义,会阻塞并发,之前的已执行完毕,等待我执行完毕,后面在开始其他提交到 queue里的操作
- (BOOL)removeAllImages {
__block BOOL removed = NO;
dispatch_barrier_sync(self.synchronizationQueue, ^{
if (self.cachedImages.count > 0) {
[self.cachedImages removeAllObjects];
self.currentMemoryUsage = 0;
removed = YES;
}
});
return removed;
}
- dispatch_barrier_sync` 同步屏障,依然在当前线程,但是保证独一操作。
dispatch_queue_t concurrentQueue = dispatch_queue_create("current", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"0 %@", NSThread.currentThread);
dispatch_async(concurrentQueue, ^{
NSLog(@"1 %@", NSThread.currentThread);
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i< 10000; i++) {
;
}
NSLog(@"2 %@", NSThread.currentThread);
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i< 1000; i++) {
;
}
NSLog(@"3 %@", NSThread.currentThread);
});
NSLog(@"4.0 %@", NSThread.currentThread);
dispatch_barrier_sync(concurrentQueue, ^{
NSLog(@"4 %@", NSThread.currentThread);
});
NSLog(@"4.1 %@", NSThread.currentThread);
dispatch_async(concurrentQueue, ^{
for (int i = 0; i< 100000; i++) {
;
}
NSLog(@"5 %@", NSThread.currentThread);
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i< 10; i++) {
;
}
NSLog(@"6 %@", NSThread.currentThread);
});
dispatch_async(concurrentQueue, ^{
NSLog(@"7 %@", NSThread.currentThread);
});
dispatch_barrier_async(concurrentQueue, ^{
NSLog(@"8 %@", NSThread.currentThread);
});
NSLog(@"9 %@", NSThread.currentThread);
// 输出如下,不能保证每次都如下,
2020-01-15 13:29:51.449188+0800 QueueDemo[66791:2112131] 0 <NSThread: 0x600000426240>{number = 1, name = main}
2020-01-15 13:29:51.449729+0800 QueueDemo[66791:2112131] 4.0 <NSThread: 0x600000426240>{number = 1, name = main}
2020-01-15 13:29:51.449750+0800 QueueDemo[66791:2112204] 2 <NSThread: 0x600000441080>{number = 4, name = (null)}
2020-01-15 13:29:51.449773+0800 QueueDemo[66791:2112206] 1 <NSThread: 0x60000046cd40>{number = 3, name = (null)}
2020-01-15 13:29:51.449815+0800 QueueDemo[66791:2112205] 3 <NSThread: 0x60000046eec0>{number = 5, name = (null)}
2020-01-15 13:29:51.451601+0800 QueueDemo[66791:2112131] 4 <NSThread: 0x600000426240>{number = 1, name = main}
2020-01-15 13:29:51.451799+0800 QueueDemo[66791:2112131] 4.1 <NSThread: 0x600000426240>{number = 1, name = main}
2020-01-15 13:29:51.452183+0800 QueueDemo[66791:2112131] 9 <NSThread: 0x600000426240>{number = 1, name = main}
2020-01-15 13:29:51.452277+0800 QueueDemo[66791:2112203] 7 <NSThread: 0x6000004646c0>{number = 6, name = (null)}
2020-01-15 13:29:51.452347+0800 QueueDemo[66791:2112206] 6 <NSThread: 0x60000046cd40>{number = 3, name = (null)}
2020-01-15 13:29:51.452456+0800 QueueDemo[66791:2112205] 5 <NSThread: 0x60000046eec0>{number = 5, name = (null)}
2020-01-15 13:29:51.453771+0800 QueueDemo[66791:2112205] 8 <NSThread: 0x60000046eec0>{number = 5, name = (null)}
总结:
- dispatch_sync vs dispatch_barrier_sync 都会同步等待当前线程执行完毕 block,dispatch_barrier_sync 支持单一路径,之前的完毕,之后的要等它执行完毕之后,才能开始
- dispatch_sync 只是同步执行,多读
- dispatch_barrier_sync 的多读性能要稍微差一点,阻塞多并发
dispatch_barrier_async
的也一样,写时单一执行。阻塞多写操作,同时进行。- 最后一个示例,可以看出 sync 的同步,都优化保证在当前线程执行。