在Sqlite3数据库中存储自定义类对象失败
我想将自定义类MCOIMAPSession
对象存储到sqlite3数据库中。我阅读了大约NSKeyedArchiver
并尝试使用下面的内容。在Sqlite3数据库中存储自定义类对象失败
- (void) updateImapSessionForAccount :(NSString *) emailAddress :(MCOIMAPSession *)imapSession {
const char *dbpath = [databasePath UTF8String];
//SQLIte Statement
NSString *selettablequery = [NSString stringWithFormat:@"select * from MailBoxInfoDBTable"];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
//if(sqlite3_prepare_v2(database, [selettablequery UTF8String], -1, &statement, NULL) == SQLITE_OK)
if (sqlite3_prepare(database, [selettablequery UTF8String], -1, &statement, NULL) ==SQLITE_OK)
{
// Take an array to store all string.
//NSMutableArray *allRows = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
char *emailfield = (char *) sqlite3_column_text(statement,0);
NSString *emailStr = [[NSString alloc] initWithUTF8String: emailfield];
NSLog(@"updateMailMessagesPerAccount: %@", emailStr);
if([emailStr isEqualToString:emailAddress])
{
sqlite3_reset(statement);
NSData *messagesData = [NSKeyedArchiver archivedDataWithRootObject:imapSession];
NSString* stringFromData = [messagesData base64EncodedStringWithOptions:0];
NSString *sqlStr = [NSString stringWithFormat:@"update MailBoxInfoDBTable set imapsession='%@' where emailid='%@'", stringFromData, emailAddress];
const char *updateStatement = [sqlStr UTF8String];
if (sqlite3_prepare(database, updateStatement, -1, &statement, NULL) == SQLITE_OK)
{
if(SQLITE_DONE != sqlite3_step(statement))
NSLog(@"Error while updating. %s", sqlite3_errmsg(database));
sqlite3_finalize(statement);
sqlite3_close(database);
return;
}
else
{
NSLog(@"Error in statement: %s", sqlite3_errmsg(database));
}
}
}
}
sqlite3_finalize(statement);
sqlite3_close(database);
}
}
- (MCOIMAPSession *) retrieveImapSessionForAccount :(NSString *) emailAddress {
MCOIMAPSession *imapsessionObj = nil;
const char *dbpath = [databasePath UTF8String];
//SQLIte Statement
NSString *selettablequery = [NSString stringWithFormat:@"select * from MailBoxInfoDBTable"];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
//if(sqlite3_prepare_v2(database, [selettablequery UTF8String], -1, &statement, NULL) == SQLITE_OK)
if (sqlite3_prepare(database, [selettablequery UTF8String], -1, &statement, NULL) ==SQLITE_OK)
{
// Take an array to store all string.
//NSMutableArray *allRows = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
char *emailfield = (char *) sqlite3_column_text(statement, 0);
NSString *emailStr = [[NSString alloc] initWithUTF8String: emailfield];
NSLog(@"retrieveImapSessionForAccount: Email: %@", emailStr);
if([emailStr isEqualToString:emailAddress])
{
//const void *bytes = sqlite3_column_blob(statement, 3);
char *emailstring = (char *) sqlite3_column_text(statement, 3);
if (emailstring) {
NSString *messageStr = [[NSString alloc] initWithUTF8String: emailstring];
NSData *data = [[NSData alloc] initWithBase64EncodedString:messageStr options:NSDataBase64DecodingIgnoreUnknownCharacters];
imapsessionObj = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
}
}
}
sqlite3_finalize(statement);
sqlite3_close(database);
}
return imapsessionObj;
}
我做NSKeyedArchiver archivedDataWithRootObject:imapSession
然后当了崩溃encodeWithCoder unrecognized selector sent to instance
,我加入了第三方类MCOIMAPSession.mm
文件
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self forKey:@"PROPERTY_KEY"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if(self = [super init]){
self = [aDecoder decodeObjectForKey:@"PROPERTY_KEY"];
}
return self;
}
更新了以下方法:我尝试了以下为好。
@interface MCOIMAPSession : NSObject
....
@end
@interface NSObject (NSCoding)
-(id)initWithCoder:(NSCoder*)decoder;
-(void)encodeWithCoder:(NSCoder*)encoder;
@end
#endif
@implementation MCOIMAPSession
-(id)initWithCoder:(NSCoder *)decoder {
if ((self=[super initWithCoder:decoder])) {
}
return self;
}
@end
@implementation NSObject (NSCoding)
-(id)initWithCoder:(NSCoder*)decoder {
return [self init];
}
-(void)encodeWithCoder:(NSCoder*)encoder {}
@end
这里是MCOIMAPSESSION MCOIMAPSESSION link的文件。请让我知道我怎么可以现在添加属性?
但是,我看到仍然一样的崩溃。在sqlite数据库中存储自定义类MCOIMAPSession
对象时,有人能纠正我在这里做错了什么吗?
您不能拨打encodeWithCoder
与对象self
。您必须对类别MCOIMAPSession
的每个相关属性编码(并解码)。
编辑:
对于MCOIMAPSession
的NSCoding方法应该看起来像
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super initWithCoder:decoder]
if (self) {
self.hostname = [decoder decodeObjectForKey:@"hostname"];
self.port = [decoder decodeIntegerForKey:@"port"];
self.username = [decoder decodeObjectForKey:@"username"];
self.password = [decoder decodeObjectForKey:@"password"];
// etc
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[aCoder encodeObject:self.hostname forKey:@"hostname"];
[aCoder encodeInteger:self.port forKey:@"port"];
[aCoder encodeObject:self.username forKey:@"username"];
[aCoder encodeObject:self.password forKey:@"password"];
// etc
}
添加你需要的所有属性。并且考虑表示其他自定义类的实例的属性也必须符合NSCoding。
您实施NSCoding
方法不正确。您不编码/解码self
,您编码/解码self
的每个属性/ ivar。就像:
- (void)encodeWithCoder:(NSCoder *)aCoder{
// Replace the following with the class's actual properties
[aCoder encodeObject:self.propertyA forKey:@"propertyA"];
[aCoder encodeObject:self.propertyB forKey:@"propertyB"];
[aCoder encodeObject:self.propertyC forKey:@"propertyC"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if(self = [super init]){
// Replace the following with the class's actual properties
_propertyA = [aDecoder decodeObjectForKey:@"propertyA"];
_propertyB = [aDecoder decodeObjectForKey:@"propertyB"];
_propertyC = [aDecoder decodeObjectForKey:@"propertyC"];
}
return self;
}
顺便说一句 - 你的问题与SQLite没有任何关系。你的问题应该缩小到编码/解码的问题。
非常正确。另外,这也假定这个类是'NSObject'的子类(这个就是这种情况),否则你也必须调用'super'方法,并且确保超级类也符合。而且,这个类的所有要编码的属性也必须符合'NSCoding'(他们不这样做)。这可能需要比OP认为的更多的工作。 – Rob
我没有任何财产在这里,我已经提到我存储在Sqlite数据库不在NSUserDefaults。当我们存储NSUserDefaults时,只需要key和value对的属性。 – user1953977
@ user1953977 - 不,rmaddy是正确的,当你创建一个类支持档案(在你插入到你的数据库之前你试图用'NSKeyedArchiver')时,你必须识别所有必须编码的属性。请参阅[编码和解码对象](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Archiving/Articles/codingobjects.html#//apple_ref/doc/uid/20000948-BCIHBJDE) _存档和序列化编程指南._ – Rob
我不打算存储在NSUserDefaults中,所以我没有设置属性。我试图在Sqlite数据库中存储MCOIMAPSession。我如何在这种情况下使用encodeWithCoder? – user1953977
NSUserDefaults和Sqlite非常相似。他们都只接受特定类型的数据。像'MCOIMAPSession'这样的自定义类必须被编码为二进制数据。这就是'NSKeyedArchiver'所做的。 'encodeWithCoder'方法用于编码诸如'host','port''用户名之类的属性。互补方法'initWithCoder'是一种'initWithArguments',并创建一个新的'MCOIMAPSession'对象,将这些值分配给相应的属性。如果'MCOIMAPSession'不符合NSCoding协议,则必须添加一个提供NSCoding方法的类别 – vadian
我无法使用NSUserDefaults,因为在我的应用程序中动态创建了多个MCOIMAPSession对象。 NSUserDefaults键是静态的。 – user1953977