NSCachedURLResponse / NSKeyedUnarchiver pain

Wed, 27. Jan 2010

Categories: en development Tags: cache Cocoa iPhone NSCachedURLResponse NSKeyedArchiver NSKeyedUnarchiver NSURLCache Objective C

as the iPhone SDK comes with a rather dysfunctional NSURLCache — Apple suggests to implement it from scratch yourself in the code examples about caching — I went for just this.

Until I came across the [NSKeyedUnarchiver unarchiveObjectWithData:...] not restoring userInfo, storagePolicy and data of NSCachedURLResponse.

Couldn’t believe it and spent almost the whole day verifying that the error is not within my code but really the unarchiver treats those fields transient.

See yourself:

-(void)testiPhoneSDK312NSKeyedArchiver
{
//  prepare a NSCachedURLResponse
    NSCachedURLResponse *src = nil;
    {
        NSURL *i_url = [NSURL URLWithString:@"http://www.url.example/path/file.html"];
        NSString *i_mime = @"text/html";
        NSInteger expectedContentLength = 112;
        NSString *i_encoding = @"iso-8859-2";

        NSURLResponse *i_response = [[NSURLResponse alloc] initWithURL:i_url
            MIMEType:i_mime
            expectedContentLength:expectedContentLength
            textEncodingName:i_encoding];
        NSData *i_data = [@"Hello, world!" dataUsingEncoding:NSISOLatin2StringEncoding];
        NSURLCacheStoragePolicy i_storage =  NSURLCacheStorageAllowed;
        NSDictionary *i_userInfo = [NSDictionary dictionaryWithObject:
        [NSDate dateWithTimeIntervalSince1970:13] forKey:@"era"];

        NSCachedURLResponse *src = [[NSCachedURLResponse alloc] initWithResponse:i_response
            data:i_data
            userInfo:i_userInfo
            storagePolicy:i_storage];

//      ensure it's all in place:
        STAssertEqualObjects(i_url, src.response.URL, @"");
        STAssertEqualObjects(i_mime, src.response.MIMEType, @"");
        STAssertEquals((int)expectedContentLength, (int)src.response.expectedContentLength, @"");
        STAssertEqualObjects(@"file.html", src.response.suggestedFilename, @"");
        STAssertEqualObjects(i_encoding, src.response.textEncodingName, @"");

        STAssertEqualObjects(i_data, src.data, @"");
        STAssertEqualObjects(i_userInfo, src.userInfo, @"");
        STAssertEquals( 0u, src.storagePolicy, @"");
    }

//  archive + unarchive:
    NSCachedURLResponse *dst = [NSKeyedUnarchiver unarchiveObjectWithData:
      [NSKeyedArchiver archivedDataWithRootObject:src]];

//  check whether src == dst
    STAssertEqualObjects(src.response.URL, dst.response.URL, @"");
    STAssertEqualObjects(src.response.MIMEType, dst.response.MIMEType, @"");
    STAssertEquals(src.response.expectedContentLength, dst.response.expectedContentLength, @"");
    STAssertEqualObjects(src.response.suggestedFilename, dst.response.suggestedFilename, @"");
    STAssertEqualObjects(src.response.textEncodingName, dst.response.textEncodingName, @"");

//  !!!!!!!!!!
//  sad information loss after unarchiving:
    STAssertNil( dst.data, @"" );
    STAssertNil( dst.userInfo, @"" );
    STAssertEquals( 2u , dst.storagePolicy, @"" );
}

When my NSURLCache replacement is ready I think about publishing it a github — interested anyone?