Storing custom objects in an NSMutableArray in NSUserDefaults

后端 未结 5 1615
情深已故
情深已故 2020-11-22 16:11

I\'ve recently been trying to store the search results of my iPhone app in the NSUserDefaults collection. I also use this to save user registration info successfully, but fo

相关标签:
5条回答
  • 2020-11-22 16:28

    See "Why NSUserDefaults failed to save NSMutableDictionary in iPhone SDK? " (Why NSUserDefaults failed to save NSMutableDictionary in iPhone SDK?)


    If you want to (de)serialize custom objects, you have to provide the functions to (de)serialize the data (NSCoding protocol). The solution you refer to works with the int array because the array is not an object but a contiguous chunk of memory.

    0 讨论(0)
  • 2020-11-22 16:33

    I would recommend against trying to store stuff like this in the defaults db.

    SQLite is fairly easy to pick up and use. I have an episode in one of my screencasts (http://pragprog.com/screencasts/v-bdiphone) about a simple wrapper that I wrote (you can get the code without buying the SC).

    It's much cleaner to store app data in app space.

    All that said if it still makes sense to put this data into the defaults db, then see the post f3lix posted.

    0 讨论(0)
  • 2020-11-22 16:35

    I think you've gotten an error in your initWithCoder method, at least in the provided code you don't return the 'self' object.

    - (id) initWithCoder: (NSCoder *)coder
    {
        if (self = [super init])
        {
            self.locationId = [coder decodeObjectForKey:@"locationId"];
            self.companyName = [coder decodeObjectForKey:@"companyName"];
            self.addressLine1 = [coder decodeObjectForKey:@"addressLine1"];
            self.addressLine2 = [coder decodeObjectForKey:@"addressLine2"];
            self.city = [coder decodeObjectForKey:@"city"];
            self.postcode = [coder decodeObjectForKey:@"postcode"];
            self.telephoneNumber = [coder decodeObjectForKey:@"telephoneNumber"];
            self.description = [coder decodeObjectForKey:@"description"];
            self.rating = [coder decodeObjectForKey:@"rating"];
            self.priceGuide = [coder decodeObjectForKey:@"priceGuide"];
            self.latitude = [coder decodeObjectForKey:@"latitude"];
            self.longitude = [coder decodeObjectForKey:@"longitude"];
            self.userLatitude = [coder decodeObjectForKey:@"userLatitude"];
            self.userLongitude = [coder decodeObjectForKey:@"userLongitude"];
            self.searchType = [coder decodeObjectForKey:@"searchType"];
            self.searchId = [coder decodeObjectForKey:@"searchId"];
            self.distance = [coder decodeObjectForKey:@"distance"];
            self.applicationProviderId = [coder decodeObjectForKey:@"applicationProviderId"];
            self.contentProviderId = [coder decodeObjectForKey:@"contentProviderId"];
        }
    
        return self; // this is missing in the example above
    
    
    }
    

    I use

    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:results];
    [prefs setObject:data forKey:@"lastResults"];
    

    and

    NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
    NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"lastResults"];
    if (dataRepresentingSavedArray != nil)
    {
            NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
            if (oldSavedArray != nil)
                    objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
            else
                    objectArray = [[NSMutableArray alloc] init];
    }
    

    and it works perfect for me.

    With regards,

    Stefan

    0 讨论(0)
  • 2020-11-22 16:38

    I think it looks like the problem with your code is not saving the results array. Its loading the data try using

    lastResults = [prefs arrayForKey:@"lastResults"];
    

    This will return the array specified by the key.

    0 讨论(0)
  • 2020-11-22 16:50

    For loading custom objects in an array, this is what I've used to grab the array:

    NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
    NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"savedArray"];
    if (dataRepresentingSavedArray != nil)
    {
        NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
        if (oldSavedArray != nil)
            objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
        else
            objectArray = [[NSMutableArray alloc] init];
    }
    

    You should check that the data returned from the user defaults is not nil, because I believe unarchiving from nil causes a crash.

    Archiving is simple, using the following code:

    [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:objectArray] forKey:@"savedArray"];
    

    As f3lix pointed out, you need to make your custom object comply to the NSCoding protocol. Adding methods like the following should do the trick:

    - (void)encodeWithCoder:(NSCoder *)coder;
    {
        [coder encodeObject:label forKey:@"label"];
        [coder encodeInteger:numberID forKey:@"numberID"];
    }
    
    - (id)initWithCoder:(NSCoder *)coder;
    {
        self = [super init];
        if (self != nil)
        {
            label = [[coder decodeObjectForKey:@"label"] retain];
            numberID = [[coder decodeIntegerForKey:@"numberID"] retain];
        }   
        return self;
    }
    
    0 讨论(0)
提交回复
热议问题