AFNetworking 中 GCD 的使用(4)

2020-01-15  本文已影响0人  老猫_2017

GCD in AFNetworking 的使用

AFAutoPurgingImageCache 处理图片缓存

  1. 创建并发队列
- (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;
}
  1. 并发读操作, 此处只是并发读,同步在当前操作线程
- (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;
}
  1. 异步并行屏障写操作,保证,写时操作唯一,
- (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;
        }
    });
}


  1. 同步屏障写操作
- (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;
}

  1. 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)}

总结:

  1. dispatch_sync vs dispatch_barrier_sync 都会同步等待当前线程执行完毕 block,dispatch_barrier_sync 支持单一路径,之前的完毕,之后的要等它执行完毕之后,才能开始
  2. dispatch_sync 只是同步执行,多读
  3. dispatch_barrier_sync 的多读性能要稍微差一点,阻塞多并发
  4. dispatch_barrier_async的也一样,写时单一执行。阻塞多写操作,同时进行。
  5. 最后一个示例,可以看出 sync 的同步,都优化保证在当前线程执行。
上一篇下一篇

猜你喜欢

热点阅读