標籤:
前段時間看了一遍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】安全執行緒的檔案讀寫