SDWebImage源码心得

本文介绍了如何使用信号量进行线程同步,并演示了不同宏定义的使用方法。此外,还详细讲解了如何处理耗时操作及申请iOS后台任务的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

信号量的使用(宏定义)

// - 先定义两个宏
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#define UNLOCK(lock) dispatch_semaphore_signal(lock);

// - 初始化一个信号量
dispatch_semaphore_t weakCacheLock = dispatch_semaphore_create(1);
self.weakCacheLock = weakCacheLock;

// - 使用宏定义的信号量
LOCK(self.weakCacheLock);
 NSLog(@"需要线程安全的操作 写在这个位置")
UNLOCK(self.weakCacheLock);

在宏定义中使用bloc k

// - 1. 先定义一个宏定义
#define DYTestBlock(param1, block)\
NSLog(@"param1 : %@", (param1));\
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(9 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\
    int blockParam1 = 1;\
NSString *blockParam2 = [NSString stringWithFormat:@"哈哈 : %@", param1];\
    block(blockParam1, blockParam2);\
});\
// - 2. 调用这个宏定义
    // - 方式1
	void(^block)(int, NSString *) = ^(int a, NSString *str) {
        NSLog(@"%d, %@", a, str);
    };
    
    DYTestBlock(@"xx",block);
    
    // - 方式 2
	DYTestBlock(@"xx",^(int a, NSString *str) {
        NSLog(@"%d, %@", a, str);
    });
    // - 方式三
	DYBlock dyBlock ^(int a, NSString *str) {
        NSLog(@"%d, %@", a, str);
    };
    
    DYTestBlock(@"xx",dyBlock);

耗时操作的处理(任何耗时:包括IO读写、转码等操作,都不应该放到主线程里面使用。)

// - 先定义一个队列
 dispatch_queue_t ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
 self.ioQueue = ioQueue;

// - 在工作线程处理 并同步返回结果
- (BOOL)diskImageDataExistsWithKey:(nullable NSString *)key {
    if (!key) {
        return NO;
    }
    __block BOOL exists = NO;
    dispatch_sync(self.ioQueue, ^{
        exists = [self _diskImageDataExistsWithKey:key];
    });
    
    return exists;
}

 // - 在工作线程处理 并在主线程回调
 dispatch_async(self.ioQueue, ^{
            [self.fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil];
            
            if (completion) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    completion();
                });
            }
        });

申请后台任务

这里有个疑问点要注意,为啥会存在前后两部分都去释放Task任务。
iOS的后台任务有个背景,不管任何时候,都需要手动去调用endBackgroundTask结束后台任务,其实开启一个后台job的时候,因为时长有限,所以会存在两种结局:

  1. 在允许的时间内执行完成
  2. 规定时间内未执行完成
    如上两种情况,在结束后都必须手动调用endBackgroundTask:;
// - 添加通知的监听
[[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(backgroundDeleteOldFiles)
                                                     name:UIApplicationDidEnterBackgroundNotification
                                                   object:nil];

// - 执行后台任务
- (void)backgroundDeleteOldFiles {
    Class UIApplicationClass = NSClassFromString(@"UIApplication");
    if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) {
        return;
    }
    UIApplication *application = [UIApplication performSelector:@selector(sharedApplication)];
    __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
        // Clean up any unfinished task business by marking where you
        // stopped or ending the task outright.
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];

    // Start the long-running task and return immediately.
    [self deleteOldFilesWithCompletionBlock:^{
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
}

声明一个废弃的方法和声明一个建议的初始化方法

// - __deprecated_msg(用于提示此方法或属性已经废弃。)
@property (nonatomic, assign) BOOL shouldUseCredentialStorage __deprecated_msg("Property deprecated. Does nothing. Kept only for backwards compatibility");

// - NS_DESIGNATED_INITIALIZER(用于告诉调用者要用这个方法去初始化类对象)
- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration NS_DESIGNATED_INITIALIZER;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值