开发者

Writing an NSMutableArray to my documents directory fails

I am attempting to cache a web request. Basically I have an app that uses a facebook user's friend list but I don't want to grab it every single time they log in. Maybe refresh once per month. Caching the friend list in a plist in the documents directory seems to make sense for this functionality. I do this as follows:

- (void)writeToDisk {
    NSLog(@"writing cache to disk, where cache = %@", cache);
    BOOL res = [cache writeToFile:[FriendCache persistentPath] atomically:YES];
    NSLog(@"reading cache from disk immediately after writing, res = %d", res);
    NSMutableArray *temp = [[NSMutableArray alloc] initWithContentsOfFile:[FriendCache persistentPath]];
    NSLog(@"cache read in = %@", temp);
}

+ (NSString *)persistentPath {
    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    return [documentsDirectory stringByAppendingPathComponent:@"FriendCache.plist"];
}

These are members of a FriendCache singleton I am using which basically wraps an NSMutableArray. I have verified that the peristentPath method is returning a valid path. As you you can see in the writeToDisk method, I verify there is data in the cache and then I print the result of the write and check if any data could be read back in. There is never data read back in, because the result of the file write is 0.

The output of the cache print is very long, but here is the abbreviated version:

2010-12-28 13:35:23.006 AppName[51607:207] writing cache to disk, where cache = (
        {
        birthday = "<null>";
        name = "Some Name1";
        pic = "http://profile.ak.fbcdn.net/hprofile-ak-snc4/hs1324.snc4/7846385648654.jpg";
        "pic_big" = "http://profile.ak.fbcdn.net/hprofile-ak-snc4/hs442.snc4/784365789465746.jpg";
        "pic_square" = "http://profile.ak.fbcdn.net/hprofile-ak-snc4/hs1324.snc4/7846357896547.jpg";
        sex = female;
        status = "<null>";
        uid = 892374897165;
    },
        {
        birthday = "<null>";
        name = "Some Name2";
        pic = "http://profile.ak.fbcdn.net/hprofile-ak-snc4/hs625.ash1/54636536547_s.jpg";
        "pic_big" = "http://profile.ak.fbcdn.net/hprofile-ak-snc4/hs170.ash2/65465656365666_n.jpg";
        "pic_square" = "http://profile.ak.fbcdn.net/hprofile-ak-snc4/hs625.ash1/654635656547_q.jpg";
        sex = female;
        status = "<null>";
        uid = 7658436;
    },

...

One thin开发者_StackOverflowg I checked out is when using writeToFile, I must make sure the object I am writing has valid plist objects. I did check this and here is how I construct the cache object:

- (void)request:(FBRequest*)request didLoad:(id)result{
    NSMutableArray *friendsInfo = [[[NSMutableArray alloc] init] autorelease];

    for (NSDictionary *info in result) {
        NSString *friend_id = [NSString stringWithString:[[info objectForKey:@"uid"] stringValue]];
        NSString *friend_name = nil;
        NSString *friend_sex = nil;
        NSString *friend_relationship_status = nil;
        NSString *friend_current_location = nil;
        if ([info objectForKey:@"name"] != [NSNull null]) {
            friend_name = [NSString stringWithString:[info objectForKey:@"name"]];
        }
        if ([info objectForKey:@"relationship_status"] != [NSNull null]) {
            friend_relationship_status = [NSString stringWithString:[info objectForKey:@"relationship_status"]];
        }
        if ([info objectForKey:@"sex"] != [NSNull null]) {
            friend_sex = [NSString stringWithString:[info objectForKey:@"sex"]];
        }
        if ([info objectForKey:@"current_location"] != [NSNull null]) {
            friend_current_location = [[info objectForKey:@"current_location"] objectForKey:@"name"];
        }
        NSString *friend_pic_square = [info objectForKey:@"pic_square"];
        NSString *friend_status = [info objectForKey:@"status"];
        NSString *friend_pic = [info objectForKey:@"pic"];
        NSString *friend_pic_big = [info objectForKey:@"pic_big"];
        NSString *friend_birthday = [info objectForKey:@"birthday"];
        NSDictionary *friend_info = [NSDictionary dictionaryWithObjectsAndKeys:
                                            friend_id,@"uid",
                                            friend_name, @"name", 
                                            friend_pic_square, @"pic_square", 
                                            friend_status, @"status",
                                            friend_sex, @"sex",
                                            friend_pic, @"pic",
                                            friend_pic_big, @"pic_big",
                                            friend_birthday, @"birthday",
                                            friend_relationship_status, @"relationship_status",
                                            friend_current_location, @"current_location",
                                            nil];

        // If the friend qualifies as a single of your gender, add to the friend cache
        if ( [AppHelpers friendQualifies:friend_info] == YES) {
            [[FriendCache sharedInstance] push:friend_info];
        }
    }
    [[FriendCache sharedInstance] writeToDisk];

}

My push method just wraps the NSMutableArray push:

- (void)push:(id)o {
    [cache addObject:o];
}

Can you think of any reason why the write would fail?

Thanks!


So as we already pointed out, it's because of the usage of the NSNull objects.

The best way to avoid this is to create an object Friend, with all of the needed properties. Then you can easily set nil values, something not possible with NSDictionary objects (well, you'd have to remove the key, which is not very good practice).

Then, by implementing the NSCoding protocol, you can easily archive (serialize) your custom object.

This is a much better way of handling your data, and it will become MUCH easier in the future. You'll be able to call messages on the Friend objects, something not possible with NSDictionary.


Use NSError-aware API for NSPropertyListSerialization to get the data and the NSData NSError aware write API so you get a meaningful error helping you understand what your problem might be.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜