在objective-c中归档对象内的对象

Posted

技术标签:

【中文标题】在objective-c中归档对象内的对象【英文标题】:Archiving objects within objects in objective-c 【发布时间】:2014-01-25 05:30:26 【问题描述】:

感谢您的阅读,

PS:我是初学者,所以我不太擅长这个不幸,但任何帮助将不胜感激

所以基本上我想归档一个包含 Account 对象的大数组,这些对象本身包含:

1. NSString 形式的用户名,

2.一个用NSNumbers填充的加密密码数组,和

3.一个填充了服务数据对象的数据数组。

服务数据对象有:

    加密的服务类型(NSArray 用 NSNumbers 填充)(无论用户名和密码用于什么服务)
    加密的用户名(用 NSNumber 填充的 NSArray)
    加密密码(用 NSNumber 填充的 NSArray)

现在奇怪的是,在尝试存档和保存时,我收到了两个错误。有一次它不再让我将服务数据对象添加到 Account 类中的数据数组中,并显示以下错误消息(或者至少它们没有出现在我拥有的 NSTableView 中,但它确实说它们存在):

[<ServiceData 0x60000023bfa0> valueForUndefinedKey:]: this class is not key value
coding-compliant for the key service.

第二,当我尝试从 Account 类登录用户名和密码时,它会正确检索用户名以及我密码的第一对和最后一对 NSNumber,但密码的其余 NSNumber 在数万亿或其他东西,所以我想知道出了什么问题,任何帮助将不胜感激。

这是我的实例变量的代码,我如何使用 NSKeyedArchiver 和 unarchiver,以及我如何保存和加载文件。再次,请帮助我,我已经坚持了一段时间,这是我最后的手段。我不知道发生了什么!


帐户类别:

H 文件:

@interface Account : NSObject <NSCoding>

@private
    NSString *username;
    NSMutableArray *password;
    NSMutableArray *accData;


@property NSString *username;
@property NSArray *password;

完整的 M 文件:

-(id)initWithCoder:(NSCoder *)aDecoder

    self = [super init];
    if(self)
    
        username = [aDecoder decodeObjectForKey:@"username"];
        password = [aDecoder decodeObjectForKey:@"password"];
        accData = [aDecoder decodeObjectForKey:@"data"];
    
    return self;


-(void)encodeWithCoder:(NSCoder *)aCoder

    [aCoder encodeObject:username forKey:@"username"];
    [aCoder encodeObject:password forKey:@"password"];
    [aCoder encodeObject:accData forKey:@"data"];

服务数据类:

H 文件:

@interface ServiceData : NSObject <NSCoding>

@private
    NSArray* serviceData;
    NSArray* usernameData;
    NSArray* passwordData;


@property NSArray* serviceData; 
@property NSArray* usernameData;
@property NSArray* passwordData;

M 文件:

#import "Account.h"
#import "Crypt.h"

NSMutableArray *accounts;
NSInteger accountNumber = -1;


@implementation Account

@synthesize username;
@synthesize password;

- (id)initWithUsername:(NSString *)name withPassword:(NSMutableArray *)key

    self = [super init];
    if (self)
    
        username = name;
        password = key;
        accData = [[NSMutableArray alloc]init];
    
    return self;



/*
setters and getters
*/

-(NSString*)getUsername;

    return username;

-(NSArray*)getPassword;

    return password;

-(void)changePassword:(NSMutableArray*)newPassword;

    NSInteger sizeOldPass = [password count];
    NSInteger sizeNewPass = [newPassword count];
    int changeXObjects = (int)(sizeNewPass - sizeOldPass);
    int changeSize = abs(changeXObjects);
    //adjusts size differences
    if (changeXObjects < 0)
    
        for(int i = 0; i < changeSize; i++)
        
            [password removeLastObject];
        
    
    else if (changeXObjects > 0)
    
        for(int i = 0; i < changeSize; i++)
        
            NSNumber *value = [NSNumber numberWithInt:0];
            [password addObject:value];
        
    

    //change password
    NSInteger sizePass = [password count];
    for (int k = 0; k < sizePass; k++)
    
        [password replaceObjectAtIndex:k withObject:newPassword[k]];
    


-(NSMutableArray*)getAccData;

    return accData;

-(void)setAccData:(NSMutableArray*)input

    [input setArray: accData];


+(NSMutableArray*)getAccounts

    return accounts;


+(NSInteger)getAccountNumber

    return accountNumber;


+(void)setAccounts:(id)accs

    accounts = accs;


+(void)setAccountNumber:(NSInteger)number

    accountNumber = number;



/*
other methods
*/

+(void)addAccount:(id)acc

    [accounts addObject:acc];

+(void)deleteAccount:(NSInteger)index

    [accounts removeObjectAtIndex:index];



-(void)addAccData:(id)input

    [accData addObject:input];


-(void)deleteAccDataAt:(NSInteger)index

    [accData removeObjectAtIndex:index];


+(bool)checkPassword:(NSString*)passwordIn accountNumber:(NSInteger)index

    NSMutableArray *passwordInputCrypt = [Crypt encrypt:passwordIn];
    NSMutableArray *passwordCrypt = [accounts[index] getPassword];

    NSInteger lengthPassword = [passwordInputCrypt count];

    bool correctPassword = true;
    if([passwordCrypt count] == [passwordInputCrypt count])
    
        for(int i = 0; i < lengthPassword; i++)
        
            if(passwordCrypt[i]!=passwordInputCrypt[i])
                correctPassword = false;
        
    
    else
    
        correctPassword = false;
    

    if(correctPassword == true)
    
        return true;
    
    return false;



-(id)initWithCoder:(NSCoder *)aDecoder

    self = [super init];
    if(self)
    
        username = [aDecoder decodeObjectForKey:@"username"];
        password = [aDecoder decodeObjectForKey:@"password"];
        accData = [aDecoder decodeObjectForKey:@"data"];
    
    return self;


-(void)encodeWithCoder:(NSCoder *)aCoder

    [aCoder encodeObject:username forKey:@"username"];
    [aCoder encodeObject:password forKey:@"password"];
    [aCoder encodeObject:accData forKey:@"data"];

@end

正在加载文件(已给出文件路径):

NSData *data = [[NSFileManager defaultManager] contentsAtPath:filePath];

if(data != nil)

    NSArray *arrayFromData = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    NSMutableArray *initArray = [NSMutableArray arrayWithArray:arrayFromData];
    [Account setAccounts:initArray];

else

    NSMutableArray *accountsInit = [[NSMutableArray alloc] init];
    [Account setAccounts:accountsInit];

保存文件:

NSArray *accounts = [Account getAccounts];
NSString *filePath = [AppController getFilePath];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:accounts];

[data writeToFile:filePath atomically:YES];

【问题讨论】:

【参考方案1】:

一些事情:

    您不应该将密码数据存档到磁盘(即使您正在对其进行加密)。这就是钥匙链的用途。查看SSKeychain 以获得良好的包装类。 您得到的键值编码错误表明您正试图在某处将您的 serviceData 数组引用为“服务”。检查您的 valueForKey 和 setValueForKey 语句。

您可以发布其余的 Account 课程吗?该方法 setAccounts 看起来可能是相关的。

还有你使用 Keyed Archiving 而不是 Core Data 的原因吗?

【讨论】:

我是一个非常初学者,我不知道有Core Data这样的东西,而setAccounts方法只是通过指针将一个帐户连接到另一个帐户,它实际上并没有复制它,但是是的,我会更新它,非常感谢。 还有只是“服务”,这不会导致编译错误吗?,因为它确实编译 不,键值编码背后的原理是它添加了各种动态类型,因此您可以设置任何您喜欢的值,即使接收者不存在。这就是您收到该错误的原因 - 正在发生的事情是在您的代码中的某处尝试使用键“服务”设置或获取 ServiceData 类上的键。这几乎可以肯定是你代码中的某个地方的错字。 顺便说一句,你在那里使用了一些非常奇怪的技术,你真的不应该这样做。首先,当您拥有属性时,您不需要生成这样的 ivars ......如果您想让它们只能由相关类设置,那么正确的方法是将它们设置为只读头文件,然后在 .m 文件的接口扩展名中再次声明它们,但为读写。您也不再需要合成,因为属性具有自动合成的 ivars,您可以使用 _propertyName 访问。 哦,我明白了,非常感谢!你很有帮助,我看看能不能找到错误。

以上是关于在objective-c中归档对象内的对象的主要内容,如果未能解决你的问题,请参考以下文章

从 iCloud 文件中取消归档对象时出错

Objective-C之成魔之路19-归档

Objective-C 中的分段错误是啥?

在目标 C 中归档多个对象并将它们作为对象数组取消归档

iOS 对象的归档

对象归档与KVC KVO