我有一个使用FMDatabase插入用户收集的数据和一些从Web下载的数据的应用程序。由于对数据库的同步请求过多,我目前遇到了一些崩溃。

我想浏览我的应用程序并将FMDatabaseQueue添加到我的所有数据库操作中,但是我需要为整个应用程序使用一个队列,因为我有一些后台类,这些类可以从Web上下载数据并将其插入到db中,所以我必须访问数据库以填充用户看到的UITableView。

所以我的问题是,您能否创建所有类中都引用的静态FMDatabaseQueue?

我的第二个问题是我的查询当前是否采用以下格式:

 FMResultset *result=  [[databaseModel sharedInstance]executeQuery:@"SELECT * FROM TABLE1"];
if(![result next]){
       [[databaseModel sharedInstance]executeUpdate:@"UPDATE TABLE1 SET foo=bar where 1;"];

这会变成吗?
[dbQueue inDatabase(FMdatabase db) ^{ //dbQueue is declared statically
    FMResultset *result=  [[databaseModel sharedInstance]executeQuery:@"SELECT * FROM TABLE1"];
    if(![result next]){
           [[databaseModel sharedInstance]executeUpdate:@"UPDATE TABLE1 SET foo=bar where 1;"];
    }
}];

在此先感谢您的任何建议,指向进一步阅读的建议或博客。

最佳答案

有两种方法可以使您的FMDatabaseQueue通过不同的类进行访问。将其设为您的应用程序委托(delegate)的属性(可以通过从[[UIApplication sharedApplication] delegate]检索应用程序的委托(delegate)进行检索),或者在您的第一个 View Controller 中创建并传递它。

就我个人而言,我倾向于singleton对象,比如DatabaseManager@interface文件可能如下所示:

//
//  DatabaseManager.h
//  Database Manager Example
//
//  Created by Robert Ryan on 6/24/13.
//  Copyright (c) 2013 Robert Ryan. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "FMDatabaseQueue.h"

@interface DatabaseManager : NSObject

@property (nonatomic, strong) FMDatabaseQueue *databaseQueue;

+ (instancetype)sharedManager;

@end
@implementation可能类似于:
//
//  DatabaseManager.m
//  Database Manager Example
//
//  Created by Robert Ryan on 6/24/13.
//  Copyright (c) 2013 Robert Ryan. All rights reserved.
//

#import "DatabaseManager.h"

@implementation DatabaseManager

+ (instancetype)sharedManager
{
    static id sharedMyManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] init];
    });
    return sharedMyManager;
}

- (id)init
{
    self = [super init];
    if (self) {
        _databaseQueue = [[FMDatabaseQueue alloc] initWithPath:[self databasePath]];
    }
    return self;
}

- (NSString *)databasePath
{
    NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    return [docsPath stringByAppendingPathComponent:@"test.sqlite"];
}

@end

然后,当您要使用此单例时,包括DatabaseManager.h头文件,您可以执行以下操作:
#import "ViewController.h"
#import "DatabaseManager.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    DatabaseManager *databaseManager = [DatabaseManager sharedManager];

    [databaseManager.databaseQueue inDatabase:^(FMDatabase *db) {
        FMResultSet *result = [db executeQuery:@"SELECT * FROM TABLE1"];
        if (!result) {
            NSLog(@"%s: executeQuery error: %@", __FUNCTION__, [db lastErrorMessage]);
            return;
        }

        while ([result next]) {
            // do whatever you want with the results
        }

        [result close];
    }];
}

// the rest of your code here

@end

简而言之,您想退休databaseModel单例(顺便说一句,按照惯例,您的类名应以大写字母开头),并为FMDatabaseQueue对象创建一个单例。然后,在inDatabase块内部,您仅可以引用db参数,而不引用任何外部数据库对象。

注意,我已经将我的单例设为NSObject子类,并且FMDatabaseQueue是该类的公共(public)属性。您在这里有很多选择。例如,您还可以使单例成为FMDatabaseQueue子类本身(类似于您显然对当前的databaseModel对象,它似乎是FMDatabase子类)。另外,根据我的个人喜好,我实际上使FMDatabaseQueue对象成为DatabaseManager的私有(private)属性,并从 Controller 中删除所有FMDB代码,等等。我将所有FMDB代码保留在这个新的单例中,或者可能在我的模型对象中。当您获得大型项目时,您可能不希望到处都是SQL语句。我个人认为FMDB代码和SQL语句是一个实现细节,应该封装在DatabaseManager类或模型类中。这样,大型项目的管理就容易一些。但是您可以按照自己的意愿进行操作。

10-07 18:46