Objective c iOS ARC问题的BWDB SQLite包装器
我正在尝试使用Bill Weinman的BWDB包装器,可在此处下载: 我不能正确地将其转换为ARC,有没有比我更有经验的人可以查看它?主要问题是insertRow和updateRow方法中的va_列表,idk如何处理它。其余的错误很容易消除 提前感谢您的帮助/建议 头文件Objective c iOS ARC问题的BWDB SQLite包装器,objective-c,ios,sqlite,automatic-ref-counting,variadic-functions,Objective C,Ios,Sqlite,Automatic Ref Counting,Variadic Functions,我正在尝试使用Bill Weinman的BWDB包装器,可在此处下载: 我不能正确地将其转换为ARC,有没有比我更有经验的人可以查看它?主要问题是insertRow和updateRow方法中的va_列表,idk如何处理它。其余的错误很容易消除 提前感谢您的帮助/建议 头文件 // BWDB.h // Created by Bill Weinman on 2010-09-25. // Copyright 2010 The BearHeart Group, LLC. All rights re
// BWDB.h
// Created by Bill Weinman on 2010-09-25.
// Copyright 2010 The BearHeart Group, LLC. All rights reserved.
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#define defaultDatabaseFileName @"bwtest.db"
#define BWDB_VERSION @"1.0.5"
@interface BWDB : NSObject <NSFastEnumeration> {
sqlite3 *database;
sqlite3_stmt *statement;
NSString *tableName;
NSString *databaseFileName;
NSFileManager *filemanager;
// for "fast enumeration" (iterator/generator pattern)
NSDictionary * enumRows[1]; // enumerated (iterator) object(s) are passed in a C array
// we only ever pass one at a time
}
@property (nonatomic, retain) NSString *tableName;
// object management
- (BWDB *) initWithDBFilename: (NSString *) fn;
- (BWDB *) initWithDBFilename: (NSString *) fn andTableName: (NSString *) tn;
- (void) openDB;
- (void) closeDB;
- (NSString *) getVersion;
- (NSString *) getDBPath;
// SQL queries
- (NSNumber *) doQuery:(NSString *) query, ...;
- (BWDB *) getQuery:(NSString *) query, ...;
- (void) prepareQuery:(NSString *) query, ...;
- (id) valueFromQuery:(NSString *) query, ...;
// CRUD methods
- (NSNumber *) insertRow:(NSDictionary *) record;
- (void) updateRow:(NSDictionary *) record: (NSNumber *) rowID;
- (void) deleteRow:(NSNumber *) rowID;
- (NSDictionary *) getRow: (NSNumber *) rowID;
- (NSNumber *) countRows;
// Raw results
- (void) bindSQL:(const char *) cQuery arguments:(va_list)args;
- (NSDictionary *) getPreparedRow;
- (id) getPreparedValue;
// Utilities
- (id) columnValue:(int) columnIndex;
- (NSNumber *) lastInsertId;
@end
//BWDB.h
//由比尔·温曼于2010年9月25日创建。
//版权2010熊心集团有限责任公司。保留所有权利。
#进口
#进口
#定义defaultDatabaseFileName@“bwtest.db”
#定义BWDB_版本@“1.0.5”
@接口BWDB:NSObject{
sqlite3*数据库;
sqlite3_stmt*语句;
NSString*表名;
NSString*数据库文件名;
NSFileManager*文件管理器;
//用于“快速枚举”(迭代器/生成器模式)
NSDictionary*enumRows[1];//枚举(迭代器)对象在C数组中传递
//我们一次只能通过一个
}
@属性(非原子,保留)NSString*表名;
//对象管理
-(BWDB*)initWithDBFilename:(NSString*)fn;
-(BWDB*)initWithDBFilename:(NSString*)fn和tablename:(NSString*)tn;
-(无效)openDB;
-(无效)关闭数据库;
-(NSString*)获取版本;
-(NSString*)getDBPath;
//SQL查询
-(NSNumber*)doQuery:(NSString*)query。。。;
-(BWDB*)getQuery:(NSString*)查询。。。;
-(void)prepareQuery:(NSString*)查询。。。;
-(id)valueFromQuery:(NSString*)查询。。。;
//积垢法
-(NSNumber*)插入行:(NSDictionary*)记录;
-(void)updateRow:(NSDictionary*)记录:(NSNumber*)行ID;
-(void)deleteRow:(NSNumber*)rowID;
-(NSDictionary*)getRow:(NSNumber*)rowID;
-(NSNumber*)计数行;
//原始结果
-(void)bindSQL:(const char*)cQuery参数:(va_list)参数;
-(NSDictionary*)getPreparedRow;
-(id)getPreparedValue;
//公用事业
-(id)columnValue:(int)columnIndex;
-(NSNumber*)最后插入的ID;
@结束
实现文件
// BWDB.m
// Created by Bill Weinman on 2010-09-25.
// Copyright 2010 The BearHeart Group, LLC. All rights reserved.
#import "BWDB.h"
@implementation BWDB
@synthesize tableName;
#pragma mark -
#pragma mark Object Management
- (void)dealloc {
// NSLog(@"%s", __FUNCTION__);
[self closeDB];
[super dealloc];
}
// if you're not using the CRUD functions, you don't need a table name
- (BWDB *) initWithDBFilename:(NSString *)fn {
// NSLog(@"%s", __FUNCTION__);
if ((self = [super init])) {
databaseFileName = fn;
tableName = nil;
[self openDB];
}
return self;
}
- (BWDB *) initWithDBFilename: (NSString *) fn andTableName: (NSString *) tn {
// NSLog(@"%s", __FUNCTION__);
if ((self = [super init])) {
databaseFileName = fn;
tableName = tn;
[self openDB];
}
return self;
}
- (void) openDB {
// NSLog(@"%s", __FUNCTION__);
if (database) return;
filemanager = [[NSFileManager alloc] init];
NSString * dbpath = [self getDBPath];
if (![filemanager fileExistsAtPath:dbpath]) {
// try to copy from default, if we have it
NSString * defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseFileName];
if ([filemanager fileExistsAtPath:defaultDBPath]) {
// NSLog(@"copy default DB");
[filemanager copyItemAtPath:defaultDBPath toPath:dbpath error:NULL];
}
}
if (sqlite3_open([dbpath UTF8String], &database) != SQLITE_OK) {
NSAssert1(0, @"Error: initializeDatabase: could not open database (%s)", sqlite3_errmsg(database));
}
[filemanager release];
filemanager = nil;
}
- (void) closeDB {
// NSLog(@"%s", __FUNCTION__);
if (database) sqlite3_close(database);
if (filemanager) [filemanager release];
database = NULL;
filemanager = nil;
}
- (NSString *) getVersion {
return BWDB_VERSION;
}
- (NSString *) getDBPath {
// NSLog(@"%s", __FUNCTION__);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:databaseFileName];
}
// iteration in ObjC is called "fast enumeration"
// this is a simple implementation
- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len {
if (*enumRows = [self getPreparedRow]) {
state->itemsPtr = enumRows;
state->state = 0; // not used, customarily set to zero
state->mutationsPtr = (unsigned long *) self; // also not used, required by the interface
return 1;
} else {
return 0;
}
}
#pragma mark -
#pragma mark SQL Queries
// doQuery:query,...
// executes a non-select query on the SQLite database
// uses SQLbind to bind the variadic parameters
// Return value is the number of affect rows
- (NSNumber *) doQuery:(NSString *) query, ... {
// NSLog(@"%s: %@", __FUNCTION__, query);
va_list args;
va_start(args, query);
const char *cQuery = [query UTF8String];
[self bindSQL:cQuery arguments:args];
if (statement == NULL) return [NSNumber numberWithInt:0];
va_end(args);
sqlite3_step(statement);
if(sqlite3_finalize(statement) == SQLITE_OK) {
return [NSNumber numberWithInt: sqlite3_changes(database)];
} else {
NSLog(@"doQuery: sqlite3_finalize failed (%s)", sqlite3_errmsg(database));
return [NSNumber numberWithInt:0];
}
}
// prepareQuery:query,...
// prepares a select query on the SQLite database
// uses SQLbind to bind the variadic parameters
// use getRow or getValue to get results
- (void) prepareQuery:(NSString *) query, ... {
// NSLog(@"%s: %@", __FUNCTION__, query);
va_list args;
va_start(args, query);
const char *cQuery = [query UTF8String];
[self bindSQL:cQuery arguments:args];
if (statement == NULL) return;
va_end(args);
}
// prepareQuery:query,...
// executes a select query on the SQLite database
// uses SQLbind to bind the variadic parameters
// Returns NSArray of NSDictionary objects
- (BWDB *) getQuery:(NSString *) query, ... {
// NSLog(@"%s: %@", __FUNCTION__, query);
va_list args;
va_start(args, query);
const char *cQuery = [query UTF8String];
[self bindSQL:cQuery arguments:args];
if (statement == NULL) return nil;
va_end(args);
return self;
}
- (id) valueFromQuery:(NSString *) query, ... {
// NSLog(@"%s: %@", __FUNCTION__, query);
va_list args;
va_start(args, query);
const char *cQuery = [query UTF8String];
[self bindSQL:cQuery arguments:args];
if (statement == NULL) return nil;
va_end(args);
return [self getPreparedValue];
}
// bindSQL:arguments
// binds variadic arguments to the SQL query.
// cQuery is a C string, args is a variadic list of ObjC objects
// objects in variadic list are tested for type
// see SQLquery for how to call this
- (void) bindSQL:(const char *) cQuery arguments:(va_list)args {
// NSLog(@"%s: %s", __FUNCTION__, cQuery);
int param_count;
// preparing the query here allows SQLite to determine
// the number of required parameters
if (sqlite3_prepare_v2(database, cQuery, -1, &statement, NULL) != SQLITE_OK) {
NSLog(@"bindSQL: could not prepare statement (%s)", sqlite3_errmsg(database));
statement = NULL;
return;
}
if ((param_count = sqlite3_bind_parameter_count(statement))) {
for (int i = 0; i < param_count; i++) {
id o = va_arg(args, id);
// determine the type of the argument
if (o == nil) {
sqlite3_bind_null(statement, i + 1);
} else if ([o respondsToSelector:@selector(objCType)]) {
if (strchr("islISLB", *[o objCType])) { // integer
sqlite3_bind_int(statement, i + 1, [o intValue]);
} else if (strchr("fd", *[o objCType])) { // double
sqlite3_bind_double(statement, i + 1, [o doubleValue]);
} else { // unhandled types
NSLog(@"bindSQL: Unhandled objCType: %s", [o objCType]);
statement = NULL;
return;
}
} else if ([o respondsToSelector:@selector(UTF8String)]) { // string
sqlite3_bind_text(statement, i + 1, [o UTF8String], -1, SQLITE_TRANSIENT);
} else { // unhhandled type
NSLog(@"bindSQL: Unhandled parameter type: %@", [o class]);
statement = NULL;
return;
}
}
}
va_end(args);
return;
}
#pragma mark -
#pragma mark CRUD Methods
- (NSNumber *) insertRow:(NSDictionary *) record {
// NSLog(@"%s", __FUNCTION__);
int dictSize = [record count];
// the values array is used as the argument list for bindSQL
id keys[dictSize]; // not used, just a side-effect of getObjects:andKeys
id values[dictSize];
[record getObjects:values andKeys:keys]; // convenient for the C array
// construct the query
NSMutableArray * placeHoldersArray = [NSMutableArray arrayWithCapacity:dictSize];
for (int i = 0; i < dictSize; i++) // array of ? markers for placeholders in query
[placeHoldersArray addObject: [NSString stringWithString:@"?"]];
NSString * query = [NSString stringWithFormat:@"insert into %@ (%@) values (%@)",
tableName,
[[record allKeys] componentsJoinedByString:@","],
[placeHoldersArray componentsJoinedByString:@","]];
[self bindSQL:[query UTF8String] arguments:(va_list)values];
sqlite3_step(statement);
if(sqlite3_finalize(statement) == SQLITE_OK) {
return [self lastInsertId];
} else {
NSLog(@"doQuery: sqlite3_finalize failed (%s)", sqlite3_errmsg(database));
return [NSNumber numberWithInt:0];
}
}
- (void) updateRow:(NSDictionary *) record:(NSNumber *) rowID {
// NSLog(@"%s", __FUNCTION__);
int dictSize = [record count];
// the values array is used as the argument list for bindSQL
id keys[dictSize]; // not used, just a side-effect of getObjects:andKeys
id values[dictSize + 1];
[record getObjects:values andKeys:keys]; // convenient for the C array
values[dictSize] = rowID;
NSString * query = [NSString stringWithFormat:@"update %@ set %@ = ? where id = ?",
tableName,
[[record allKeys] componentsJoinedByString:@" = ?, "]];
[self bindSQL:[query UTF8String] arguments:(va_list)values];
sqlite3_step(statement);
sqlite3_finalize(statement);
}
- (void) deleteRow:(NSNumber *) rowID {
// NSLog(@"%s", __FUNCTION__);
NSString * query = [NSString stringWithFormat:@"delete from %@ where id = ?", tableName];
[self doQuery:query, rowID];
}
- (NSDictionary *) getRow: (NSNumber *) rowID {
NSString * query = [NSString stringWithFormat:@"select * from %@ where id = ?", tableName];
[self prepareQuery:query, rowID];
return [self getPreparedRow];
}
- (NSNumber *) countRows {
return [self valueFromQuery:[NSString stringWithFormat:@"select count(*) from %@", tableName]];
}
#pragma mark -
#pragma mark Raw results
- (NSDictionary *) getPreparedRow {
// NSLog(@"%s", __FUNCTION__);
int rc = sqlite3_step(statement);
if (rc == SQLITE_DONE) {
sqlite3_finalize(statement);
return nil;
} else if (rc == SQLITE_ROW) {
int col_count = sqlite3_column_count(statement);
if (col_count >= 1) {
NSMutableDictionary * dRow = [NSMutableDictionary dictionaryWithCapacity:1];
for(int i = 0; i < col_count; i++) {
// can't use NULL with stringWithUTF8String (bw 1.0.5)
const char * sqliteColName = sqlite3_column_name(statement, i);
if(sqliteColName) {
NSString * columnName = [NSString stringWithUTF8String:sqliteColName];
id o = [self columnValue:i];
if (o != nil) [dRow setObject:o forKey:columnName];
else {
NSLog(@"getPreparedRow: columnValue returned nil (%s)", sqlite3_errmsg(database));
return nil;
}
} else {
NSLog(@"getPreparedRow: sqlite3_column_name returned NULL (%s)", sqlite3_errmsg(database));
return nil;
}
}
return dRow;
}
} else { // rc != SQLITE_ROW
NSLog(@"getPreparedRow: could not get row: %s", sqlite3_errmsg(database));
return nil;
}
return nil;
}
// returns one value from the first column of the query
- (id) getPreparedValue {
// NSLog(@"%s", __FUNCTION__);
int rc = sqlite3_step(statement);
if (rc == SQLITE_DONE) {
sqlite3_finalize(statement);
return nil;
} else if (rc == SQLITE_ROW) {
int col_count = sqlite3_column_count(statement);
if (col_count < 1) return nil; // shouldn't really ever happen
id o = [self columnValue:0];
sqlite3_finalize(statement);
return o;
} else { // rc == SQLITE_ROW
NSLog(@"valueFromPreparedQuery: could not get row: %s", sqlite3_errmsg(database));
return nil;
}
}
#pragma mark -
#pragma mark Utility Methods
- (id) columnValue:(int) columnIndex {
// NSLog(@"%s columnIndex: %d", __FUNCTION__, columnIndex);
id o = nil;
switch(sqlite3_column_type(statement, columnIndex)) {
case SQLITE_INTEGER:
o = [NSNumber numberWithInt:sqlite3_column_int(statement, columnIndex)];
break;
case SQLITE_FLOAT:
o = [NSNumber numberWithFloat:sqlite3_column_double(statement, columnIndex)];
break;
case SQLITE_TEXT:
o = [NSString stringWithUTF8String:(const char *) sqlite3_column_text(statement, columnIndex)];
break;
case SQLITE_BLOB:
o = [NSData dataWithBytes:sqlite3_column_blob(statement, columnIndex) length:sqlite3_column_bytes(statement, columnIndex)];
break;
case SQLITE_NULL:
o = [NSNull null];
break;
}
return o;
}
- (NSNumber *) lastInsertId {
return [NSNumber numberWithInt: sqlite3_last_insert_rowid(database)];
}
@end
//BWDB.m
//由比尔·温曼于2010年9月25日创建。
//版权2010熊心集团有限责任公司。保留所有权利。
#导入“BWDB.h”
@BWDB的实现
@综合表名;
#布拉格标记-
#pragma标记对象管理
-(无效)解除锁定{
//NSLog(@“%s”,函数);
[自关闭数据库];
[super dealoc];
}
//如果不使用CRUD函数,则不需要表名
-(BWDB*)initWithDBFilename:(NSString*)fn{
//NSLog(@“%s”,函数);
if((self=[super init])){
databaseFileName=fn;
tableName=nil;
[自我开放数据库];
}
回归自我;
}
-(BWDB*)initWithDBFilename:(NSString*)fn和TableName:(NSString*)tn{
//NSLog(@“%s”,函数);
if((self=[super init])){
databaseFileName=fn;
tableName=tn;
[自我开放数据库];
}
回归自我;
}
-(void)openDB{
//NSLog(@“%s”,函数);
if(数据库)返回;
filemanager=[[NSFileManager alloc]init];
NSString*dbpath=[self-getDBPath];
如果(![filemanager fileExistsAtPath:dbpath]){
//如果有,尝试从默认值复制
NSString*defaultDBPath=[[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:databaseFileName];
如果([filemanager fileExistsAtPath:defaultDBPath]){
//NSLog(@“复制默认数据库”);
[filemanager copyItemAtPath:defaultDBPath-toPath:dbpath错误:NULL];
}
}
if(sqlite3\u打开([dbpath UTF8String],&database)!=SQLITE\u正常){
NSAssert1(0,@“错误:初始化数据库:无法打开数据库(%s)”,sqlite3_errmsg(数据库));
}
[文件管理器发布];
filemanager=nil;
}
-(无效)关闭数据库{
//NSLog(@“%s”,函数);
如果(数据库)sqlite3_关闭(数据库);
if(文件管理器)[文件管理器发布];
数据库=NULL;
filemanager=nil;
}
-(NSString*)getVersion{
返回BWDB_版本;
}
-(NSString*)getDBPath{
//NSLog(@“%s”,函数);
NSArray*Path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,是);
NSString*documentsDirectory=[paths objectAtIndex:0];
返回[DocumentsDirectoryStringByAppendingPathComponent:databaseFileName];
}
//ObjC中的迭代称为“快速枚举”
//这是一个简单的实现
-(nsInteger)countByEnumeratingWithState:(NSFastEnumerationState*)状态对象:(id*)stackbuf count:(nsInteger)len{
if(*enumRows=[self-getPreparedRow]){
state->itemsPtr=enumrrows;
state->state=0;//未使用,通常设置为零
state->mutationsPtr=(unsigned long*)self;//也未使用,为接口所需
返回1;
}否则{
返回0;
}
}
#布拉格标记-
#pragma标记SQL查询
//doQuery:query,。。。
//在SQLite数据库上执行非select查询
//使用SQLbind绑定可变参数
//返回值是受影响的行数
-(NSNumber*)doQuery:(NSString*)查询。。。{
//NSLog(@“%s:%@”,函数,查询);
va_列表参数;
va_开始(参数、查询);
const char*cQuery=[query UTF8String];
[self-bindSQL:cQuery参数:args];
if(statement==NULL)返回[NSNumber numberwhithint:0];
va_端(args);
sqlite3_步骤(语句);
if(sqlite3\u finalize(语句)=SQLITE\u OK){
返回[NSNumber numberWithInt:sqlite3_变更(数据库)];
}否则{
NSLog(@“doQuery:sqlite3_finalize failed(%s)”,sqlite3_errmsg(数据库));
返回[NSNumber numberWithInt:0];
}
}
//准备:查询,。。。
//在SQLite数据库上准备select查询
//使用SQLbind绑定可变参数
//使用getRow或getValue获取结果
-(void)prepareQuery:(NSString*)查询。。。{
//NSLog(@“%s:%@”,函数,查询);
va_列表参数;
va_开始(参数、查询);
const char*cQuery=[query UTF8String];
[self-bindSQL:cQuery参数:args];
if(statement==NULL)返回;