2015-07-04 113 views
0

我想将自定义类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对象时,有人能纠正我在这里做错了什么吗?

回答

0

您不能拨打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。

+0

我不打算存储在NSUserDefaults中,所以我没有设置属性。我试图在Sqlite数据库中存储MCOIMAPSession。我如何在这种情况下使用encodeWithCoder? – user1953977

+0

NSUserDefaults和Sqlite非常相似。他们都只接受特定类型的数据。像'MCOIMAPSession'这样的自定义类必须被编码为二进制数据。这就是'NSKeyedArchiver'所做的。 'encodeWithCoder'方法用于编码诸如'host','port''用户名之类的属性。互补方法'initWithCoder'是一种'initWithArguments',并创建一个新的'MCOIMAPSession'对象,将这些值分配给相应的属性。如果'MCOIMAPSession'不符合NSCoding协议,则必须添加一个提供NSCoding方法的类别 – vadian

+0

我无法使用NSUserDefaults,因为在我的应用程序中动态创建了多个MCOIMAPSession对象。 NSUserDefaults键是静态的。 – user1953977

2

您实施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没有任何关系。你的问题应该缩小到编码/解码的问题。

+0

非常正确。另外,这也假定这个类是'NSObject'的子类(这个就是这种情况),否则你也必须调用'super'方法,并且确保超级类也符合。而且,这个类的所有要编码的属性也必须符合'NSCoding'(他们不这样做)。这可能需要比OP认为的更多的工作。 – Rob

+0

我没有任何财产在这里,我已经提到我存储在Sqlite数据库不在NSUserDefaults。当我们存储NSUserDefaults时,只需要key和value对的属性。 – user1953977

+1

@ user1953977 - 不,rmaddy是正确的,当你创建一个类支持档案(在你插入到你的数据库之前你试图用'NSKeyedArchiver')时,你必须识别所有必须编码的属性。请参阅[编码和解码对象](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Archiving/Articles/codingobjects.html#//apple_ref/doc/uid/20000948-BCIHBJDE) _存档和序列化编程指南._ – Rob