Giter Site home page Giter Site logo

ctpersistance's People

Contributors

bignerdcoding avatar bryant1410 avatar casatwy avatar cctv1237 avatar corotata avatar damiansheldon avatar gitter-badger avatar readmecritic avatar welkiner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ctpersistance's Issues

更新还是有问题

类型绑定 addBindKey 函数在更新 BOOL 类型时还是会出现问题。理论上 SQLite 好像是没有 BOOL 类型的,所以绑定代码可以做出部分修改:

if ([bindValue isKindOfClass:[NSNumber class]]) {
    NSNumber *value = (NSNumber *)bindValue;

    valueType = @"INTEGER";
    
    if (strcmp(value.objCType, @encode(float)) == 0
       || strcmp(value.objCType, @encode(double)) == 0
       || strcmp(value.objCType, @encode(CGFloat)) == 0) {

        valueType = @"REAL";
    }
}

并去掉:

if ([valueType isEqualToString:@"BOOLEAN"]) {
        invocation = [NSInvocation invocationWithMethodSignature:[NSMutableArray instanceMethodSignatureForSelector:@selector(bindBooleanWithStatement:value:key:)]];
        invocation.target = self;
        invocation.selector = @selector(bindBooleanWithStatement:value:key:);
        [invocation setArgument:&bindValue atIndex:3];
        [invocation setArgument:&bindKey atIndex:4];
        [invocation retainArguments];
        [self addObject:invocation];
        return;
 }

不然会将 BOOL 类型更新为 NULL,然后你取出后变为 NSNULL,然后就出现运行时错误。

晚上先到这里吧,明天起床再说早点休息

CTPersistanceAsyncExecutor在Release下运行会死循环

while (shouldWait) {
}

这个循环语句在release下编译,编译器会认为shouldWait不会被修改而不会每次去取值,导致死循环。在shouldWait变量前声明volatile可解决。另外,为啥不直接用- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait?

当主键是字符串时,根据主键查询会报错

错误信息的一部分“WHERE primaryKey = 987D5D73-4E98-49D5-A095-19610A3E8EEB
Error Message is: unrecognized token: "987D5D73"”

应该是“- (NSString *)stringWithSQLParams:(NSDictionary *)params”这个方法在拼接参数的使用没有把主键值用“''”单引号包起来的原因。
改成""... WHERE primaryKey = '987D5D73-4E98-49D5-A095-19610A3E8EEB' ”就好了

同样是数据库更新错误

我使用一个 double 字段保存毫秒数时间戳,但是使用 updateRecord 进行操作时候发生异常错误,调用栈为:

  1. updateRecord
  2. updateKeyValueList primaryKeyValue
  3. NSString *valueString = [keyValueList bindToValueList:bindValueList];
  4. [bindValueList addBindKey:valueKey bindValue:value columnDescription:nil];

最终发现错误出现在:

NSString *valueType = [[[columnDescription componentsSeparatedByString:@" "] firstObject] uppercaseString];

if (valueType == nil) {
    if ([bindValue isKindOfClass:[NSNumber class]]) {
        valueType = @"INTEGER";
    } if ([bindValue isKindOfClass:[NSString class]]) {
            valueType = @"TEXT";
    } if ([bindValue isKindOfClass:[NSNull class]]) {
            valueType = @"INTEGER";
    } if ([bindValue isKindOfClass:[NSData class]]) {
         valueType = @"BLOB";
     }
 }

您将 double 类型重置为了整型从而导致,REAL 类型更新出现异常,根本原因在于所有调用 bindToValueList 都会存在这个问题。预估其他操作使用处也会存在问题。

swift 项目中使用 cocoapods 集成 CTPersistance 编译出错

Hi casa,

我想在 Swift 项目中 尝试使用 CTPersistance,通过 cocoapods 集成后,编译出错:

error

error2

libsqlte3.tbd 添加了,我的 Podfile 是这样的:

platform :ios, '8.0'
use_frameworks! 

target 'CTPersistanceDemo' do
pod 'CTPersistance'
end

而集成其他的 objc 写的第三方 pod 都没问题,比如 JGProgressHUD

麻烦你看看,先谢谢了。

备注:

  1. cocoapods 从 0.36 这个版本开始就支持 Swift 了,并且支持在 Swift 项目中也集成 Objective-C 的 pod 参考
  2. 这里有个讨论,看看有无帮助。

whereCondition Bug

should differentiate key and value in whereCondition, and only string type of value should have semi-colon.

3002漏了对结果进行判断吗?

/* 3002 */
NSDictionary *keyvalueList = @{@"migration1_0":@"this is migration"};
NSString *whereCondition = @":primaryKey > 0";
NSString *primaryKey = [table primaryKeyName];
NSDictionary *whereConditionParams = NSDictionaryOfVariableBindings(primaryKey);
[table updateKeyValueList:keyvalueList whereCondition:whereCondition whereConditionParams:whereConditionParams error:&error];

/* test 3003 */

NSArray

Hello and thanks for the great source code.
I have a question. How can i handle an NSArray in the testrecord for example in your demo?
as i see it i need to add the column in the testtable.m file as well.
how will i add the array in the table?

thanks

数据存储bug

当存储的字段为字符串类型,且字符串中有 ; 符号的时候, 会被safeSQLEncode 过滤掉,导致数据存储错误

空值对象的改进问题

对于数据库 NULL 值当前设计是在 fetchWithError 函数中将其设置为 [NSNull null] 单例对象。在 OC 环境下这种设计绝大多数情形下不会存在太大的问题,但是对于 Swift 混编环境来说该设计明显对 Optional 值不友好,使用不当存在潜在 Crash 问题。另一个是对于值对象来说:即使是 OC 环境,[NSNull null] 单例对象在动态转化为 long long 等值时存在 Runtime Crash (当然这个在插入记录的时候就存在使用不当,值类型不应使用空值,但是 CT Runtime 提供了这部分操作的能力 )。

如果我们将改部分处理代码改为:

case SQLITE_NULL:
        [result setObject:nil forKey:columnName];
        break;

可能对使用者来说更好一点。

另一个,空值改进的方法我觉得后期可以考虑一下:对 CTPersistanceTableProtocol 进行一个拓展,增加一个 columnDefaultValue 方法用于设置默认值。这样使用者可以通过该协议设置默认值从而避免空值对象问题,而不是在插值之前人为保证。

CTPersistanceDataBase没有提供自己定义数据库路径的接口

Hi,大神!我又来麻烦您了。现在我有一份数据库文件,它是在Bundle中的,是我用来记录了一些常量,其中表都是类似这样子的
image
其中StringForAppDisplay是给App显示用的,CodeForServer是和后台服务器交互用的。主要是为了解决同样的数据,App显示数据和后台交互数据的不同的问题。

之前是自己用FMDB写SQL来查,现在想复用CTPersistance中的查询功能。但是看CTPersistanceDataBase的源码发现,CTPersistance能操作的数据库都只是在App的Library文件夹中,并不能访问到Bundle中的数据库文件。

我想请教一下:
1、如果我想复用CTPersistance的查询功能访问Bundle中的数据库文件,有什么比较优雅的做法没?
2、我用bundle中的数据库文件记录这种常量的设计是否合理(之前我是用Plist做,但是考虑到Plist容易被别人解包直接拿到数据,而且每次加载需要把整个Plist加载进内存。于是我改成了数据库的方式。数据库有设置加密密码,提高了一些数据安全性。并且我有配合NSCache来解决多次重复查询需要大量时间的问题)?如果不合理能否帮忙给点建议?

谢谢。

关于主键是字符串的问题

当主键是字符串的时候,在获取操作中有findAllWithKeyName可以进行查找。但是当需要通过主键删除一条记录的时候就没有相应的方法了,可不可以在删除deleteRecord的系列方法中也添加类似deleteRecordWithKeyName呢,会不会有其他隐患?

你好大神

我一直搞不懂一个问题,如果服务器将错误的数据类型返回给客户端(能使app崩溃),此时客户端将此数据保存了下来,那么对于app来说岂不是很危险。这种情况该怎么避免呢

CTPersistanceRecord setValue:forKey:报错

- (BOOL)setPersistanceValue:(id)value forKey:(NSString *)key
{
    BOOL result = YES;
    NSString *setter = [NSString stringWithFormat:@"set%@%@:", [[key substringToIndex:1] capitalizedString], [key substringFromIndex:1]];
    if ([self respondsToSelector:NSSelectorFromString(setter)]) {
        if ([value isKindOfClass:[NSString class]]) {
            [self setValue:[value safeSQLDecode] forKey:key];
        } else if ([value isKindOfClass:[NSNull class]]) {
            [self setValue:nil forKey:key];
        } else {
            [self setValue:value forKey:key];
        }
    } else {
        result = NO;
    }

    return result;
}

在判断 [value isKindOfClass:[NSNull class]]分支里,value被设置为nil,导致crash

could not set nil as the value for the key 

情景:
新建migratorStep,实现

- (void)goUpWithQueryCommand:(CTPersistanceQueryCommand *)queryCommand error:(NSError *__autoreleasing *)error
{
  [[queryCommand addColumn:@"uploadFinishDate" columnInfo:@"INTEGER" tableName:@"LocalMovieTable"] executeWithError:error];
}

数据库中增加一个INTEGER类型的字段。数据库升级之后,由于新添字段,所以会走[value isKindOfClass:[NSNull class]]的分支,然而,这里uploadFinishDate并不是id类型,导致出错。

写long类型的数值到数据库,再次查询时被转换为int

在CTPersistanceQueryCommand.m中

                case SQLITE_INTEGER:
                {
                    int value = sqlite3_column_int(statement, i);
                    [result setObject:[NSNumber numberWithInt:value] forKey:columnName];
                    break;
                }

从数据库中读出的整形,被转化为NSNumber,不是通过@(num),而是通过[NSNumber numberWithInt:value]的方式。
目前遇到的问题是:
我把一个文件的大小存入数据库,size超过4GB(>32位,Int)。从数据库取出来的值出错了。

字符串做主键插入的问题

在插入新数据之后会强制把 lastInsertRowId设置为主键的值,但是这个值类型和数据是错误的, 请问该如何处理这种情况?

当字段值为UUID格式的数据时,数据可插入,但是通过对应字段的值去查询,会查询不到数据

当Record中的某个字段为UUID格式 (如4885D273-C3C6-40AE-9504-A147C4B3ACFB),这条数据,可以插入到数据库,但是通过这个字段的值去查询的时候,查不到这个数据。

然后,我又测试了你的test案例,这种情况同样的是出现的,在insert的例子中
//Insert
NSError error = nil;
/
test 1001 */
TestTable *table = [[TestTable alloc] init];
TestRecord *record = [[TestRecord alloc] init];
record.age = @(1);
record.name = @"4885D273-C3C6-40AE-9504-A147C4B3ACFB";
record.tomas = @"1";
[table insertRecord:record error:&error];
if ([record.primaryKey integerValue] > 0) {
NSLog(@"1001 success");
} else {
NSException *exception = [[NSException alloc] init];
@throw exception;
}
//

//Fetch
error = nil;
NSArray *recordList = [table findAllWithKeyName:@"name" value:@"4885D273-C3C6-40AE-9504-A147C4B3ACFB" error:&error];
if (recordList.count == 0) {
NSException *exception = [[NSException alloc] init];
@throw exception;
} else {
NSLog(@"2021 success");
}

NSLog(@"End Fetch Test");

//

record中的name字段,在我的测试过程中,发现name为UUID格式时,或者也可以说不全为数字时,都是查询不到的,我不知道是不是我使用方式错误,遗漏了某些地方,还是这里是有bug的

update:
原来是这个问题,TEXT类型的数据,需要加‘’,否则如果出现像UUID这种格式的字符串,就无法判别,只拿到前面的那些数字...
不知道这算不算个问题,或者,你可以在你的NSString里面多加一个方法,预防一下这个问题的出现

数据异步操作崩溃

大神帮忙看下。
一个socket请求,返回数据保存到本地数据库,偶尔会崩溃,不知道什么问题

代码我贴一下:
1、请求数据
2017-07-11 2 54 10

2017-07-11 2 47 55

2、保存数据
2017-07-11 2 48 16

3、崩溃点
2017-07-11 2 48 24

报错信息:
2017-07-11 2 51 37

update 操作可能出现问题

在进行数据库记录更新时,如果存在 BLOB 字段,那么可能出现问题。默认情形下,数据更新操作并不会调用 bindBlobWithStatement 函数,也就是说 sqlite3_bind_blob 不会被执行,这样会导致一个 BLOB 类型字段不会被更新,甚至被更新为 NULL。除非再额外调用一次 BLOB 类型字段 对应的更新操作。

// 该操作不会更新  BLOB 类型字段
[table updateRecord:record error:&error];

// 需要以下操作才能实现真正的更新
[table updateRecord:record error:&error];
[table updateValue:record.bleData forKey:@"bleData" primaryKeyValue:record.identifier error:&error];

不知道作者能否在后面对 updateRecord 进行补充?

updateRecordList 异常

CTPersistanceTable+Update.m的方法
- (void)updateRecordList:(NSArray <NSObject <CTPersistanceRecordProtocol> *> *)recordList error:(NSError **)error,

若直接传入error值是nil或NULL,运行到这个方法会崩溃Thread 1: EXC_BAD_ACCESS (code=1, address=0x0),错误定位在29行 if (*error != nil) { ,若传入的error 为 &error 则正常。

objectRepresentationWithDictionary方法名的理由

从CTPersistanceRecordProtocol文件的的声明config your record with dictionary和CTPersistanceRecord的实现来看这个方法都偏向于是一个动作,是不是名称改成- (void)setPersistanceValuesForKeysWithDictionary:(NSDictionary *)keyedValues会更合适?还是这里这么命名是有其他深层的原因?

1.3.2数据查询失效

今天更新插件的时候升级到了1.3.2,发现数据库操作全都失效了。看了下楼主的提交更新才明白了又是之前那个''的问题。
针对这种 NSString *sqlString = @"SELECT * FROM ':tableName' WHERE conversationId = ':conversationId' ORDER BY messageTime DESC limit ':index',':count'";
语法,前面带:冒号的参数都增加了'',查询OK了
但是
NSArray *recordList = [self.contactInfoTable findAllWithKeyName:@"shortName" value:shortName error:&error];
这种查询又失效了,点进去看了一下,分类里面参数楼主没有加''
2016-11-25 4 38 22

这里似乎又回到了1.3.0的缺少''语法问题

之前的问题 #37 就是这个问题
数据库我不熟,语法也不太懂,只是测试出来是这个问题,楼主看下

CTPersistanceAsyncExecutor 线程安全

CTPersistanceAsyncExecutor 的 operationQueue 是不是应该在单例初始化的时候就初始化好?否则多线程同时调用这个单例会出问题。

CTPersistanceTable没有Merge数据的API

我需要实现一个功能:向一个数据库表中merge数据。如果表中已有该数据就update数据,如果表中没有就insert数据。当前在CTPersistanceTable以及他的类目中没找到提供该功能的API,暂时打算自己写一个CTPersistanceTable+Merge的类目来实现。
希望大神后续有空能更新出该API。如果现有的API能解决这个需求,又不影响性能的话,也请不吝赐教。
多谢!

常量声明忘加`const`了


static NSString * kCTPersisatanceConfigurationFileName
->
static NSString * const kCTPersisatanceConfigurationFileName

Escape character of single quote doesn't work

Query Error:
Origin Query is : INSERT INTO BBCMessageDetailTable (id,isReaded,sendTime,fromId,toId,owner,msgType,orderId,orderType,peer,status,content) VALUES (NULL,'0','1467975653','16122','22','16122','0','157','2','22','2','I'm ');

Error Message is: near "m": syntax error

sqlite> INSERT INTO BBCMessageDetailTable (id,isReaded,sendTime,fromId,toId,owner,msgType,orderId,orderType,peer,status,content) VALUES (NULL,'0','1467975653','16122','22','16122','0','157','2','22','2','I'm ');
...> );
...> ');
Error: near "m": syntax error

sqlite> INSERT INTO BBCMessageDetailTable (id,isReaded,sendTime,fromId,toId,owner,msgType,orderId,orderType,peer,status,content) VALUES (NULL,'0','1467975653','16122','22','16122','0','157','2','22','2','I''m ');
sqlite> select * from BBCMessageDetailTable;
0|0|1467972148|22|Q really |16122|0|156|2|22|1|16122
1|0|1467972118|22|The best |16122|0|156|2|22|2|16122
2|0|1467975594|22|Even |16122|0|157|2|22|1|16122
3|0|1467975622|22|Do not |16122|0|157|2|22|1|16122
4|0|1467975653|22|Im |16122|0|157|2|22|2|16122
5|0|1467975653|22|I'm |16122|0|157|2|22|2|16122

如果有多个数据库,都有数据迁移的需求,如何配置CTPersistanceConfiguration.plist文件?

场景:我有多个业务模块,分别做成不同的私有Pod。其中每个业务模块都使用CTPersistance创建自己模块数据库,每个数据库也都有对应的Migrator。但是有个问题,CTPersistance提供的配置文件CTPersistanceConfiguration.plist只有一份,如果在私有库中的CTPersistanceConfiguration.plist文件配置,当合并到主工程时,如果主工程或者别的私有库也有CTPersistanceConfiguration.plist文件,那么就会出现文件重复。这样的场景下,即如果有分库的需求时,如何进行数据迁移的配置呢?

谢谢~~

CTPersistanceDatabasePool 中的一些问题

数据库链接池存在一些问题,我提一下:

  1. databaseWithName 方法构造链接时使用的 Key 与 closeDatabaseWithName 不一致,所以存在 closeDatabaseWithName 失败甚至 Crash 问题 (database 为 nil 无法响应 closeDatabase )
  2. 如果使用当前线程与 databaseName 为 Key ,那么多线程环境下同一数据库存在多个链接的可能,而 CT 本身并没有使用 WAL 模式所以可能存在同时写以及读写竞争问题
  3. 建议数据库链接池采用 databasePath 作为 Key (可能存在同名数据库,所以不能使用 databaseName),这样能保证同一个数据库只有一个链接
  4. 不要内部自动关闭数据库链接,而且当前关闭也存在问题(同一线程下创建的多个链接可能只会关闭第一个,而且未从 databaseList 中移除)。关闭链接操作交由上层处理。
  5. 如果用户手动删除数据库文件,但是没有关闭链接,则该情形属于使用不当,不作容错处理。

NSMutableArray+CTPersistanceBindValue中-addBindKey:bindValue:columnDescription有内存泄漏

以这段代码为例:

if ([valueType isEqualToString:@"INTEGER"]) {
        invocation = [NSInvocation invocationWithMethodSignature:[NSMutableArray instanceMethodSignatureForSelector:@selector(bindIntegerWithStatement:value:key:)]];
        invocation.target = self;
        invocation.selector = @selector(bindIntegerWithStatement:value:key:);
        [invocation setArgument:&bindValue atIndex:3];
        [invocation setArgument:&bindKey atIndex:4];
        [invocation retainArguments];
        [self addObject:invocation];
        return;
    }
invocation = [NSInvocation invocationWithMethodSignature:[NSMutableArray instanceMethodSignatureForSelector:@selector(bindIntegerWithStatement:value:key:)]];
invocation.target = self;

这两句造成了循环引用,建议转为单例调用

多线程test 6002中table是在Async block外创建,但运行成功?

我在文档里看到
方法:

  • (void)performAsyncAction:(void (^)(void))action shouldWaitUntilDone:(BOOL)shouldWaitUntilDone;
    的注释里写到:
    you must always create CTPersistanceTable in action block, do not use outside table instance in this block
    但是在test 6002里面发现mainTestTable是在block外创建的,运行测试仍然成功。想问下这里是否与冲突?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.