可变数组归档 - doesNotRecognizeSelector 异常

3
我遇到了一个"doesNotRecognizeSelector"异常,我怀疑我的反归档器返回的是不可变数组而不是可变数组。我是对的吗?应该如何正确地进行归档和反归档?(异常发生位置已经显示)
谢谢!
NSMutableArray* arr;

- (void) write
{
         NSMutableData *data = [[NSMutableData alloc] init];
         NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];

 NSMutableArray *copy = [[NSMutableArray arrayWithArray:self.Arr] copy];
        [archiver encodeObject:copy forKey:@"Key"];
        [archiver finishEncoding];
        [data writeToFile:[Util DataPath] atomically:YES];
        [archiver release];
        [data release];
        [copyOfPaidPacks release];
}




-(NSMutableArray*) read
{
    NSString* DataPath = [Util FilePath];
    NSData *data = [[NSMutableData alloc] initWithContentsOfFile:DataPath];
    NSKeyedUnarchiver *unarchiver = nil;
    if (data != nil)
    {
            unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data];

    if([self.Arr count] <= 0)
    {
        self.Arr = [unarchiver decodeObjectForKey:@"Key"];  
    }
}

[unarchiver finishDecoding];
[unarchiver release];
[data release];
    return self.arr
}

-(void)B
{
     [self write];
     NSMutableArray* SecondArr = [self read];
     [SecondArr sortUsingSelector:@selector(CompareDate:)]; - > `****THIS IS WHERE I GET THE EXCEPTION`
}
  • 编辑

添加比较方法:

- (NSComparisonResult)CompareDate:(T*)p
{
    NSComparisonResult result = [self.changeDate compare:p.changeDate];
    if(result == NSOrderedDescending)
        result = NSOrderedAscending;
    else if(result == NSOrderedAscending)
        result = NSOrderedDescending;

    if(result == NSOrderedSame)
    {
        result = [self CompareName:p];
    }

    return result;
}

选择器无法识别是什么?编辑:好的,我往下滚动看到了。您是否定义了自定义的“CompareDate:”方法?此外,您的数组中有哪些类型的对象? - NSGod
我已经定义了它。我添加了代码,以便您审查它。 - Idan
3个回答

6
NSKeyedUnarchiver确实返回一个不可变的NSArray。如果你真的想要获取一个NSMutableArray,则需要在从decodeObjectForKey:返回的值上调用-mutableCopy
这段代码让我想知道您是否真的需要可变数组。看起来您只是对从-read中获取的不可变NSArray进行排序。为什么不直接在不可变NSArray上调用sortedArrayUsingSelector:呢?

我认为它必须是可变的才能进行排序,因为按定义排序会改变数组中对象的位置(即添加和删除)。我错了吗? - Idan
1
@Idan:在一个不可变的数组上,你无法执行“原地”排序操作,但是你可以要求任何数组根据特定的选择器(或函数)进行排序,并使用sortedArrayUsingSelector:方法来实现。kperryua已经提到了这一点。 - Chuck
好的,我明白了,那你如何解释未识别的选择器异常呢?奇怪的是大多数时候它都能正常工作。有什么想法吗? - Idan
1
NSArray由于是一个变异方法,所以简单地不响应-sortUsingSelector:,因此Objective-C抛出了异常。我不确定为什么这通常会发生。 - kperryua

3

你已经向归档器传递了一个不可变数组,那么为什么希望解档器返回一个可变数组呢?

如果你希望得到一个可变的副本,那么你需要使用

NSMutableArray *copy = [[NSMutableArray arrayWithArray:self.Arr] mutableCopy];

as

NSMutableArray *copy = [[NSMutableArray arrayWithArray:self.Arr] copy];

该方法将创建一个不可变的副本(至少在你应该考虑的范围内是如此)。实际上,框架通常会使用可变的内部表示来处理不可变实例,但这是一些实现细节,你不应该依赖于它们,因为这些表示过去已经发生了变化,Cocoa文档明确告诉你不要检查内部表示。

编辑: 我自己在iOS 5.0模拟器上测试了NSKeyedArchiver:

// this returns a mutable instance at runtime!
NSMutableArray* test0 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:[NSMutableArray array]]];
// this returns an immutable instance at runtime!
NSArray* test1 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:[NSArray array]]];

所以您的问题实际上是由于在归档和解档时使用了复制而不是可变复制,而归档和解档会保留实例的正确可变属性!


0
我遇到了一个问题,即将一个三维可变数组(即一个可变数组的可变数组的可变数组)归档后,解档为一个不可变数组的不可变数组的可变数组。
解决这个问题的关键是子类化NSKeyedUnarchiver并覆盖其中的方法。
- (Class)classForClassName:(NSString *)codedName
{
    Class theClass = [super classForClassName: codeName];

    if ([codeName isEqualToString: NSStringFromClass(NSArray.class))
    {
        theClass = NSMutableArray.class;
    }
    //... more here like NSDictionary
    return theClass;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接