• 【iOS】线程安全的文件读写


    前段时间看了一遍GCD(Grand Central Dispatch)多线程,GCD是苹果为多核开发提供的解决方案

    多线程最常见的问题就是读写,比如数据库读写,文件读写,读取是共享的,写是互斥,允许多个线程进行读操作,当写文件时,阻止队列中所有其他的线程进入,直到文件写完成

    本文利用GCD提供的相关API封装(主要有dispatch_barrier_asyncdispatch_asyncdispatch_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的调用也非常方便

  • 相关阅读:
    三分钟学会.NET微服务之Polly
    redis设置密码和redis主从复制
    程序员工作之外,如何再赚一份工资?
    吞吐量(TPS)、QPS、并发数、响应时间(RT)概念
    TPS和QPS的区别和理解
    制定一套适合自己团队的GITflow标准化工作流
    UvaLive 6600 Spanning trees in a secure lock pattern 矩阵行列式
    从零開始学Xamarin.Forms(一) 概述
    Unity 之 C# 利用回调函数实现C++匿名函数
    hdu 4324 Triangle LOVE(拓扑判环)
  • 原文地址:https://www.cnblogs.com/bomo/p/4668599.html
Copyright © 2020-2023  润新知