Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Archiving mutable array - doesNotRecognizeSelector exception

I'm having an "doesNotRecognizeSelector" exception and I suspect that maybe my unarchiver return immutable array intstead of mutable. Am I right ? how should I do the archiving and archiving properly ? (place of exception is show down)

Thanks!!!

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`
}
  • Edit

Adding the compare method:

- (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;
}
like image 486
Idan Avatar asked Aug 12 '26 21:08

Idan


2 Answers

NSKeyedUnarchiver does indeed return an immutable NSArray. If you really want to get an NSMutableArray, you'd need to call -mutableCopy on the return value from decodeObjectForKey:.

This code snippet makes me wonder if you really even need a mutable array though. It looks like you're just sorting the array you get from -read. Why not just call sortedArrayUsingSelector: on the immutable NSArray instead?

like image 183
kperryua Avatar answered Aug 15 '26 12:08

kperryua


You already pass an immutable array to the archiver, so why would you expect the unarchiver to return a mutable one then?

If you want a copy to be mutable, then you have to use

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

as

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

will create an immutable copy (at least as far, as you should be concerned. In reality the framework will often use a mutable internal representation for immutable instances, but this is an implementation detail and you should not count on it, as these representations have changed in the past and the Cocoa docs explicitly tell you, to not check for the internal representation).

EDIT: just tested with NSKeyedArchiver myself on iOS 5.0 simulator:

// 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]]];

So your problem is really exclusively caused by using copy instead of mutableCopy, while archiving and unarchiving keeps the correct mutability-attributes of the instances!

like image 35
Kaiserludi Avatar answered Aug 15 '26 12:08

Kaiserludi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!