2015-07-04 154 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