创建单例数据库帮助程序类

时间:2013-02-19 10:14:16

标签: ios sqlite helper

我正在尝试编写一个Master-Detail应用程序,它从sqlite数据库中获取数据。作为其中的一部分,我正在尝试创建一个帮助程序类,它创建我的数据库的单例实例。我想要它做的就是初始化数据库,以便我可以从应用程序的不同视图中引用它。 我按照教程执行了此操作:http://www.raywenderlich.com/913/sqlite-101-for-iphone-developers-making-our-app

我得到了教程,但是现在我正在尝试修改它以适应我的应用程序,我似乎无法让它工作。我没有错误或警告,但是当我在模拟器上运行应用程序时,我执行的调试文本都没有。所以它看起来像我的init函数没有执行。我只是想不通为什么。 任何人都可以在下面的代码中发现我的问题吗?

LoyaltyProgramDatabase.h

#import <Foundation/Foundation.h>
#import <sqlite3.h>

@interface LoyaltyProgramDatabase : NSObject {
    sqlite3 *_loyaltyProgDB;
}

@property (strong, nonatomic) NSString *databasePath; //Path file of our database
@property (nonatomic) sqlite3 *loyaltyProgDB; //Reference to the database

+ (LoyaltyProgramDatabase*)loyaltyProgDB;

@end

LoyaltyProgramDatabase.m

#import "LoyaltyProgramDatabase.h"

@implementation LoyaltyProgramDatabase

static LoyaltyProgramDatabase *_loyaltyProgDB;

//Create a singleton instance of loyaltyProgDB
+ (LoyaltyProgramDatabase*)loyaltyProgDB {
    if (_loyaltyProgDB == nil) {
        _loyaltyProgDB = [[LoyaltyProgramDatabase alloc] init];
    }
    return _loyaltyProgDB;
}

- (id)init {
    NSLog(@"Inside init function");
    if ((self = [super init])) {

        NSString *docsDir;
        NSArray *dirPaths;

        // Get the documents directory
        dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    docsDir = dirPaths[0];

    // Build the path to the database file
    _databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent:@"loyaltyProg.db"]];

    NSFileManager *filemgr = [NSFileManager defaultManager];

    if ([filemgr fileExistsAtPath: _databasePath ] == NO)
    {
        const char *dbpath = [_databasePath UTF8String];

        if (sqlite3_open(dbpath, &_loyaltyProgDB) == SQLITE_OK)
        {
            char *errMsg;
            const char *sql_stmt = "CREATE TABLE IF NOT EXISTS scoreCard (ID INTEGER PRIMARY KEY AUTOINCREMENT, campaignID INTEGER, merchantName TEXT)";

            if (sqlite3_exec(_loyaltyProgDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
            {
                //_status.text = @"Failed to create table";
                NSLog(@"Failed to create table");
            }
            sqlite3_close(_loyaltyProgDB);
        } else {
            //_status.text = @"Failed to open/create database";
            NSLog(@"Failed to open/create database");
        }
    }        
}    
return self;
}

- (void)dealloc {
    sqlite3_close(_loyaltyProgDB);
}

@end

2 个答案:

答案 0 :(得分:0)

试试这个:

   + (id)allocWithZone:(NSZone *)zone
{
    return [self loyaltyProgDB];
}

+ (LoyaltyProgramDatabase*)loyaltyProgDB
{
    static BNRImageStore *loyaltyProgDB = nil;
    if (!loyaltyProgDB) {
        // Create the singleton
        loyaltyProgDB = [[super allocWithZone:NULL] init];
    }
    return loyaltyProgDB;
}

- (id)init {
    self = [super init];
    if (self) {

        NSString *docsDir;
        NSArray *dirPaths;

        // Get the documents directory
        dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

        docsDir = dirPaths[0];

        // Build the path to the database file
        _databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent:@"loyaltyProg.db"]];

        NSFileManager *filemgr = [NSFileManager defaultManager];

        if ([filemgr fileExistsAtPath: _databasePath ] == NO)
        {
            const char *dbpath = [_databasePath UTF8String];

            if (sqlite3_open(dbpath, &_loyaltyProgDB) == SQLITE_OK)
            {
                char *errMsg;
                const char *sql_stmt = "CREATE TABLE IF NOT EXISTS scoreCard (ID INTEGER PRIMARY KEY AUTOINCREMENT, campaignID INTEGER, merchantName TEXT)";

                if (sqlite3_exec(_loyaltyProgDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
                {
                    //_status.text = @"Failed to create table";
                    NSLog(@"Failed to create table");
                }
                sqlite3_close(_loyaltyProgDB);
            } else {
                //_status.text = @"Failed to open/create database";
                NSLog(@"Failed to open/create database");
            }
        }
    }
    return self;
}

答案 1 :(得分:0)

如果您还没有编写一行代表[[LoyaltyProgramDatabase alloc] init][LoyaltyProgramDatabase loyaltyProgDB]的代码,那么您的init函数永远不会被调用。

启动应用时,系统不会自动调用init。自动调用任何init函数的唯一情况是,如果您在nib / xib / storyboard文件中有UI元素,并且应用程序使用各种初始化函数创建元素,但从不使用您自己的init函数。但是对于像你所写的那样,要初始化数据库对象,你需要自己调用init函数。

在您的app委托中,在didFinishLaunching函数下,输入以下行:

[LoyaltyProgramDatabase loyaltyProgDB];

顺便说一下,这不是一个真正的最新单身人士模式。这实际上是一个懒惰的加载器功能。如果您想要更安全的单例,请使用此代码。

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

这将确保数据库只被初始化一次并且它是线程安全的。要创建/使用单例,代码将从上面改为

[LoyaltyProgramDatabase sharedInstance]