Search code examples
iosarraysnskeyedarchiver

Are objects modified when Archived/Unarchived?


So here is my problem. I am trying to archive an array of objects and when I unarchive them although the count is the same and the objects inside the root object are the same it does not find the specified object in the unarchived array.

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"self.vendors.count = %d", self.vendors.count);
    [NSKeyedArchiver archiveRootObject:self.vendors toFile:[self vendorsArchivePath]];

    NSMutableArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:[self
                                vendorsArchivePath]];
    NSLog(@"array.count = %d", array.count);
    NSLog(@"%d", [self.vendors indexOfObject:self.vendors[indexPath.row]]);
    NSLog(@"%d", [array indexOfObject:self.vendors[indexPath.row]]);
}

In order to troubleshoot myself; I have the counts of both arrays listed and at the bottom and the index of the object in each array in an NSLog.

Here is the log...

2014-04-27 12:53:04.813 Inventory[12272:907] self.vendors.count = 5
2014-04-27 12:53:04.827 Inventory[12272:907] array.count = 5
2014-04-27 12:53:04.828 Inventory[12272:907] 0
2014-04-27 12:53:04.831 Inventory[12272:907] 2147483647

So my question is: Why in the world is the last NSLog not finding the same object, that I archived and unarchived in the SAME function not being found in the array? Are objects modified when archived and unarchived? Or is there something else that I am missing.

EDIT: Here are my vendor.h and vendor.m files:

//vendor.h
#import <Foundation/Foundation.h>

@interface SELVendor : NSObject <NSCoding>

@property (nonatomic) NSMutableArray *itemsAvailable;
@property (nonatomic) NSString *name;
@property (nonatomic) NSString *phoneNumber;
@property (nonatomic) NSString *email;
@property (nonatomic) NSString *vendorKey;

@end

//vendor.m
#import "SELVendor.h"

@implementation SELVendor

-(instancetype) init {
    self = [super init];
    if (self) {
        self.name = @"Unnamed Vendor";
        self.itemsAvailable = [[NSMutableArray alloc] init];

        NSUUID *uuid = [[NSUUID alloc] init];
        self.vendorKey = [uuid UUIDString];
    }
    return self;
}

-(void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeObject:self.itemsAvailable forKey:@"itemsAvailable"];
    [aCoder encodeObject:self.phoneNumber forKey:@"phoneNumber"];
    [aCoder encodeObject:self.email forKey:@"email"];
    [aCoder encodeObject:self.vendorKey forKey:@"vendorKey"];
}

-(instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.itemsAvailable = [aDecoder decodeObjectForKey:@"itemsAvailable"];
        self.phoneNumber = [aDecoder decodeObjectForKey:@"phoneNumber"];
        self.email = [aDecoder decodeObjectForKey:@"email"];
        self.vendorKey = [aDecoder decodeObjectForKey:@"vendorKey"];
    }
    return self;
}

@end

Solution

  • This means that the object wasn't found 2147483647 == NSNotFound

    What you're trying to do is save a array of objects, and then read them back out to a varaible. Doing this will create (alloc/init) the objects again so they won't occupy the same location in memory. Depending on how you implement your encoder/decode methods, the object might be exactly the same as the other one (content wise). What you need to do is override isEqual: (and hash) in your class and check the objects in there.

    If you're objects have some kind of ID property you can just do:

    -(BOOL)isEqual:(id)object
    {
        if (self == object) {
            return YES;
        }
        if (![object isKindOfClass:[self class]]) {
            return NO;
        }
        return [self.ID isEqual:object.ID];
    }
    

    If none of your properties on your object are unique, you can check each one in the isEqual: method.

    See this answer for more info.