2013-10-25 18 views
7

tôi đã dành tất cả các buổi chiều đập đầu vào tường cố gắng tìm ra lý do tại sao giải mã của lớp này đã thất bại. lớp này có một thuộc tính là một NSArray của các đối tượng Foo. Foo tuân theo NSSecureCoding và tôi đã tự mã hóa và giải mã thành công lớp đó. tôi đã nhận được một lỗi trong initWithCoder: mà nói không giải mã lớp Foo. thông qua một số thử nghiệm, tôi phát hiện ra rằng tôi cần thêm [Foo class] vào initWithCoder: để nó hoạt động. có thể điều này sẽ giúp người khác có cùng vấn đề. câu hỏi của tôi là, tại sao điều này lại cần thiết? tôi thấy không có gợi ý rằng điều này là cần thiết trong tài liệu của apple.Hành vi lạ khi giải mã một NSArray qua NSSecureCoding

#import "Foo.h" 

@interface MyClass : NSObject <NSSecureCoding> 
@property (nonatomic) NSArray *bunchOfFoos; 
@end 

@implementation MyClass 

static NSString *kKeyFoo = @"kKeyFoo"; 

+ (BOOL) supportsSecureCoding 
{ 
    return YES; 
} 

- (void) encodeWithCoder:(NSCoder *)encoder 
{ 
    [encoder encodeObject:self.bunchOfFoos forKey:kKeyFoo]; 
} 

- (id) initWithCoder:(NSCoder *)decoder 
{ 
    if (self = [super init]) 
    { 
     [Foo class]; // Without this, decoding fails 
     _bunchOfFoos = [decoder decodeObjectOfClass:[NSArray class] forKey:kKeyFoo]; 
    } 
    return self; 
} 

@end 
+0

Tôi nghĩ rằng đối với những gì bạn đang cố gắng hoàn thành, bạn cần triển khai mã hóa/giải mã trong lớp Foo. – zaph

+0

có, tôi đã nói rằng Foo tuân theo NSSecureCoding, nghĩa là mã hóa/giải mã đã được triển khai trong lớp đó. –

Trả lời

2

tôi nghĩ rằng tôi có thể đã tìm ra điều này. không có dòng [Foo class], không có tham chiếu đến lớp Foo trong tệp này. vì điều này, tôi tin rằng trình biên dịch tối ưu hóa lớp Foo, và sau đó các đối tượng Foo trong mảng không thể được giải mã. có [Foo class] trong đó ngăn cản điều này.

3

Đối với những người vẫn đang vật lộn với điều này: Giải pháp của @Ben H không giải quyết được sự cố của tôi. Và tôi tiếp tục có thông báo lỗi sau:

Ứng dụng chấm dứt do ngoại lệ không được nhận 'NSInvalidUnarchiveOperationException', reason:> 'giá trị cho khóa' NS.objects 'thuộc lớp không mong muốn' ClassA '. Các lớp được phép là '{(
NSArray
)}'. '

Và cuối cùng, tôi nhận ra rằng đối với các lớp tùy chỉnh. Bạn phải sử dụng các chức năng sau đây thay vì decodeObjectOfClasses:

- (id)decodeObjectOfClasses:(NSSet *)classes forKey:(NSString *)key 

Và bạn vượt qua một NSSet của mọi tầng lớp có thể trong NSArray đến chức năng ở trên! Tôi không chắc chắn tại sao @Ben H có thể giải quyết vấn đề bằng cách thêm [Foo class] bên ngoài chức năng. Có lẽ nó là một vấn đề trình biên dịch. Nhưng dù sao, nếu giải pháp của anh ấy không hiệu quả, hãy thử cái này.

+1

Điều này làm việc cho tôi. – Gomfucius

+0

@Gomfucius vui mừng khi biết rằng nó giúp –

+0

Cảm ơn! Những công việc này. –

3

Tôi vừa gặp sự cố tương tự và điều đó thật lạ và tốn thời gian. Tôi muốn kiểm tra lớp của mình là NSSecureCoded đúng với Specta/Expecta. Vì vậy, tôi đã thực hiện mọi thứ khi cần xác định lớp khi được giải mã. Vào cuối thử nghiệm của tôi, tôi có ngoại lệ kỳ lạ nhất:

value for key 'key' was of unexpected class 'MyClass'. Allowed classes are '{(
    MyClass 
)}'. 

thử nhìn một cái gì đó như thế:

kiểm tra
MyClass *myClassInstance = ... 
NSMutableData *data = [NSMutableData data]; 
NSKeyedArchiver *secureEncoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; 
[secureEncoder setRequiresSecureCoding:YES]; // just to ensure things 

NSString *key = @"key"; 
[secureEncoder encodeObject:myClassInstance forKey:key]; 
[secureEncoder finishEncoding]; 

NSKeyedUnarchiver *secureDecoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; 
[secureDecoder setRequiresSecureCoding:YES]; 
MyClass *decodedInstance = [secureDecoder decodeObjectOfClass:[MyClass class] forKey:key]; // exception here 
[secureDecoder finishDecoding]; 

...expect... 

Trong khi đồng bằng NSCoding (requiresSecureCoding = NO) thử nghiệm thành công, NSSecureCoding giữ không. Sau nhiều thử nghiệm, tôi đã tìm ra giải pháp cho điều đó, chỉ cần một dòng:

[secureDecoder setClass:[MyClass class] forClassName:NSStringFromClass([MyClass class])]; 

Sau đó tất cả các thử nghiệm của tôi thành công, các đối tượng được tạo như mong đợi.

Tôi không chắc chắn tại sao điều đó lại xảy ra, tôi đoán rằng lớp học không hiển thị như được đề xuất là Ben H và sử dụng thứ gì đó như NSClassFromString(@"MyClass"). Đoạn mã trên hoạt động tốt trong AppDelegate. MyClass đến từ các nhóm phát triển mà tôi đang phát triển.