2015-07-04 2 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; 
} 

я получил аварию encodeWithCoder unrecognized selector sent to instance при выполнении NSKeyedArchiver archivedDataWithRootObject:imapSession

Затем я добавил следующие методы 3-го класса партии 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 .. Пожалуйста, дайте мне знать, как я могу добавить недвижимость сейчас?

Но, я вижу, все тот же крах. Может ли кто-то исправить меня, что я делаю неправильно здесь, когда храня пользовательский класс MCOIMAPSession объект в базе данных sqlite?

ответ

0

Вы не можете позвонить в encodeWithCoder с объектами self. Вам необходимо закодировать (и декодировать) каждое соответствующее свойство класса MCOIMAPSession.

Edit:

Для 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, поэтому у меня нет свойства, чтобы установить там. Я пытаюсь сохранить MCOIMAPSession в Sqlite DB. Как я могу использовать encodeWithCoder в этом случае? – user1953977

+0

NSUserDefaults и Sqlite очень похожи. Они оба принимают только данные конкретных типов. Пользовательские классы, такие как 'MCOIMAPSession', должны быть закодированы для двоичных данных. Вот что делает NSKeyedArchiver. Метод encodeWithCoder используется для кодирования таких свойств, как 'host',' port' 'username'. Дополнительный метод 'initWithCoder' является своего рода' initWithArguments' и создает новый объект MCOIMAPSession, присваивающий значения соответствующим свойствам. Если 'MCOIMAPSession' не соответствует протоколу NSCoding, вы должны добавить категорию, предоставляющую методы NSCoding. – vadian

+0

Я не могу использовать NSUserDefaults, так как в моем приложении динамически создаются несколько объектов MCOIMAPSession. Ключ NSUserDefaults является статическим. – user1953977

2

Неверная реализация методов NSCoding. Вы не кодируете/декодируете self, вы кодируете/декодируете каждое свойство/ivar из self. Что-то вроде:

- (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; 
} 

BTW - ваш вопрос не имеет ничего общего с SQLite. Ваш вопрос должен быть сужен только с проблемой кодирования/декодирования.

+0

Совершенно верно. Кроме того, это также предполагает, что этот класс является подклассом «NSObject» (к которому это относится), иначе вам также нужно будет вызвать методы 'super' и убедиться, что суперкласс тоже соответствует. Кроме того, все свойства этого класса, которые должны быть закодированы, также должны соответствовать «NSCoding» (чего у них нет). Это может занять больше работы, чем думает OP. – Rob

+0

У меня нет собственности здесь, я уже упоминал, что храню в Sqlite DB не в NSUserDefaults. Когда мы храним NSUserDefaults, нам нужно только свойство пары ключей и значений. – user1953977

+1

@ user1953977 - Нет, rmaddy правильно, что при создании архивов поддержки классов (которые вы пытаетесь сделать с NSKeyedArchiver перед вставкой в ​​вашу базу данных) вам необходимо идентифицировать все индивидуальные свойства, которые должны быть закодированы , См. [Объекты кодирования и декодирования] (https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Archiving/Articles/codingobjects.html#//apple_ref/doc/uid/20000948-BCIHBJDE) в _Archives and Serializations. Руководство по программированию. – Rob