【iOS】线程安全的文件读写
前段时间看了一遍GCD(Grand Central Dispatch)多线程,GCD是苹果为多核开发提供的解决方案
多线程最常见的问题就是读写,比如数据库读写,文件读写,读取是共享的,写是互斥,允许多个线程进行读操作,当写文件时,阻止队列中所有其他的线程进入,直到文件写完成
本文利用GCD提供的相关API封装(主要有dispatch_barrier_async,dispatch_async,dispatch_queue_create)一个线程安全的文件读写类FileManager
注:这里使用的文件读写使用NSFileManager类,在测试过程发现多个线程同时写文件的时候并没有发现异常和报错,经过一番查阅发现,原来NSFileManager本身就是线程安全的,多个线程对文件进行写操作,并不会报异常
下面代码只作为加深GCD的学习,实际开发如果使用NSFileManager并不需要考虑线程安全问题(使用NSFileManager的delegate的时候需要注意,需要自己定义一个实例维护状态,避免与共享实例冲突)
SGFileManager.h
@interface SGFileManager : NSObject + (instancetype)shareInstance; - (NSData *)readFile:(NSString *)path; - (void)readFileAsync:(NSString *)path complete:(void (^)(NSData *data))complete; - (BOOL)writeFile:(NSString *)path data:(NSData *)data; - (void)writeFileAsync:(NSString *)path data:(NSData *)data complete:(void (^)(BOOL result))complete; @end
SGFileManager.m
#import "SGFileManager.h" //线程队列名称 static char *queueName = "fileManagerQueue"; @interface SGFileManager () { //读写队列 dispatch_queue_t _queue; } @end @implementation SGFileManager + (instancetype)shareInstance { static id instance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; }); return instance; } - (instancetype)init { if(self = [super init]) { _queue = dispatch_queue_create(queueName, DISPATCH_QUEUE_CONCURRENT); } return self; } - (NSData *)readFile:(NSString *)path { __block NSData *data; dispatch_sync(_queue, ^{ if([[NSFileManager defaultManager] fileExistsAtPath:path]){ data = [[NSFileManager defaultManager] contentsAtPath:path]; } }); return data; } - (void)readFileAsync:(NSString *)path complete:(void (^)(NSData *data))complete { dispatch_async(_queue, ^{ NSData *data = nil; if([[NSFileManager defaultManager] fileExistsAtPath:path]){ data = [[NSFileManager defaultManager] contentsAtPath:path]; } if (complete) { complete(data); } }); } - (BOOL)writeFile:(NSString *)path data:(NSData *)data { __block BOOL result = NO; dispatch_barrier_sync(_queue, ^{ NSFileManager *fileManager = [NSFileManager defaultManager]; if([fileManager fileExistsAtPath:path]){ [fileManager removeItemAtPath:path error:nil]; } result = [[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil]; NSLog(@"写文件:"); }); return result; } - (void)writeFileAsync:(NSString *)path data:(NSData *)data complete:(void (^)(BOOL result))complete { __block BOOL result = NO; dispatch_barrier_async(_queue, ^{ NSFileManager *fileManager = [NSFileManager defaultManager]; if([fileManager fileExistsAtPath:path]){ [fileManager removeItemAtPath:path error:nil]; } result = [[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil]; if (complete) { complete(result); } }); } @end
使用:
NSString *documentRoot = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *filePath = [documentRoot stringByAppendingPathComponent:@"test.txt"]; [[SGFileManager shareInstance] writeFileAsync:filePath data:data complete:^(BOOL result) { if (result) { NSLog(@"异步写入文件成功"); } }]; [[SGFileManager shareInstance] readFileAsync:filePath complete:^(NSData *data) { if (data) { NSLog(@"异步读取文件成功"); } }];
使用GCD进行多线程开发还是挺方便的,不需要考虑锁的问题,并且性能也比较高,在开发中可以尽量使用GCD进行多线程的开发,并且GCD对从后台到UI的调用也非常方便
分类:
iOS
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥
2014-07-22 【WP8】图片缓存控件