FMDB源码系列(二)

2018-04-28  本文已影响0人  Invoker_M

上一篇讲解了FMDB使用的一些宏与Sqlite3错误码,都是FMDB中常用的。这篇我们开始进入源码的解读过程。

FMResultSet.h

其中常用的方法与属性有这些:

//该结果集的DB实例对象
@property (nonatomic, retain, nullable) FMDatabase *parentDB;
//查询出该结果集所使用的SQL语句
@property (atomic, retain, nullable) NSString *query;
//该结果集的列映射出的数字索引
@property (readonly) NSMutableDictionary *columnNameToIndexMap;
//查询出的结果集的行数
@property (nonatomic, readonly) int columnCount;
//当前结果集中所在的行内数据映射的字典,列名区分大小写
@property (nonatomic, readonly, nullable) NSDictionary *resultDictionary;
//关闭该结果集
- (void)close;
//遍历结果集
- (BOOL)next;
- (BOOL)nextWithError:(NSError * _Nullable *)outErr;
//跟随next方法使用,判断执行Next方法时是否成功检索到另一行
- (BOOL)hasAnotherRow;
//通过FMStatement对象与FMDatabase对象来查询一个结果集,自动打开关闭数据库。
+ (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB;
//根据索引返回该索引的列名
- (NSString * _Nullable)columnNameForIndex:(int)columnIdx;
//判断传入的索引值对应的列是否存在
- (BOOL)columnIndexIsNull:(int)columnIdx;
//判断传入的列名对应的列是否存在
- (BOOL)columnIsNull:(NSString*)columnName;
//将结果集所对行的数据,使用KVC给对象赋值,对象中的属性名要与列名一致。
- (void)kvcMagic:(id)object;
- (int)intForColumn:(NSString*)columnName;
- (int)intForColumnIndex:(int)columnIdx;
- (long)longForColumn:(NSString*)columnName;
- (long)longForColumnIndex:(int)columnIdx;

关于该类取值方法,以intForColumn:与intForColumnIndex:方法为例。
其中intForColumn:的实现方法实际是调用了intForColumnIndex:方法取值的:

- (int)intForColumn:(NSString*)columnName {
    return [self intForColumnIndex:[self columnIndexForName:columnName]];
}

而intForColumnIndex:方法是以使用sqlite3方法来取值的:

- (int)intForColumnIndex:(int)columnIdx {
    return sqlite3_column_int([_statement statement], columnIdx);
}
- (int)columnIndexForName:(NSString*)columnName {
    columnName = [columnName lowercaseString];
    
    NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName];
    
    if (n != nil) {
        return [n intValue];
    }
    
    NSLog(@"Warning: I could not find the column named '%@'.", columnName);
    
    return -1;
}

实现过程很简单,就是根据列名的数组映射,拿到该列的索引值。


- (void)kvcMagic:(id)object {
    //用sqlite3方法取出结果集蕴含的行数
    int columnCount = sqlite3_column_count([_statement statement]);
    //遍历结果集
    int columnIdx = 0;
    for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
        //取出该列的列名
        const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx);
        //在列名不为空的情况下,使用KVC给Object的属性赋值。
        // check for a null row
        if (c) {
            NSString *s = [NSString stringWithUTF8String:c];
            
            [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]];
        }
    }
}

这个方法,只能给NSString类型的属性赋值,实在是令人对这个Magic有些失望。

int rc = sqlite3_step([_statement statement]);

然后根据rc的值来判断异常(报异常的代码已省略),错误码请对照上一篇。

if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
      //报异常
    }
    else if (SQLITE_DONE == rc || SQLITE_ROW == rc) {
        // all is well, let's return.一切正常
    }
    else if (SQLITE_ERROR == rc) {
             //报异常
    }
    else if (SQLITE_MISUSE == rc) {
            //报异常
    }
    else {
           //报异常
    }

最后做终止判断以及返回当前结果

    if (rc != SQLITE_ROW) {
        [self close];
    }
    
    return (rc == SQLITE_ROW);
上一篇 下一篇

猜你喜欢

热点阅读