`

不能随意封装FMDatabase

 
阅读更多

初学ios的时候,只用了几天原生的sqlite API,就换了FMDatabase。那会对ios的线程不熟悉,对FMDatabase也不熟悉,只是觉得需要频繁open & close Database太麻烦,就直接照搬别的语言的经验,封装了一个FMDatabase的单例

@implementation YLSDatabaseHelper

{
    FMDatabase* db;
}

-(id) init
{
    self = [super init];
    if(self){
        NSString *dbFilePath = [YLSGlobalUtils getDatabaseFilePath];
        db = [[FMDatabase alloc] initWithPath:dbFilePath];
    }
    return self;
}

+(YLSDatabaseHelper*) sharedInstance
{
    static dispatch_once_t pred = 0;
    __strong static id _sharedObject = nil;
    dispatch_once(&pred, ^{
        _sharedObject = [[self alloc] init];
    });
    return _sharedObject;
}

+(void) refreshDatabaseFile
{
    YLSDatabaseHelper *instance = [self sharedInstance];
    [instance doRefresh];
}

-(void) doRefresh
{
    NSString *dbFilePath = [YLSGlobalUtils getDatabaseFilePath];
    db = [[FMDatabase alloc] initWithPath:dbFilePath];
}

-(void) doOperation:(void(^)(FMDatabase*))block
{
    [db open];
    block(db);
    [db close];
}

@end

原本觉得单例用起来很方便,也不需要经常open close了。直到最近收到几次Crashlytics的crash report,再上FMDatabase的网站看了下,才知道这种封装方式在多线程环境下是很有问题的:

Using a single instance of FMDatabase from multiple threads at once is a bad idea. It has always been OK to make a FMDatabase objectper thread. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. Bad things will eventually happen and you'll eventually get something to crash, or maybe get an exception, or maybe meteorites will fall out of the sky and hit your Mac Pro.This would suck.

So don't instantiate a single FMDatabase object and use it across multiple threads.

在多线程情况下,共享同一个FMDatabase实例就是一个最差实践,我原本这种封装的方式完全就是错误的。正确的做法是每个线程创建一个新的FMDatabase的实例,或者使用FMDatabaseQueue类

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics