I am building a model for a MVC and I am experiencing an anomaly where contrary to the Apple Documentation “Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value.”, the [[NSUserDefaults standardUserDefaults] objectForKey:@”key”] is returning a mutable array.
I created an empty application for iOS in Xcode 4D199 to re-create the condition and confirm that it isn’t accountable to other factors on my project.
I am setting the NSMutableArray as shown:
- (void)setupTest
{
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
[mutableArray addObject:@"one"];
[mutableArray addObject:@"two"];
[[NSUserDefaults standardUserDefaults] setObject:mutableArray forKey:@"mutableArray_01"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
and, I am getting the object as shown:
- (void)checkTest
{
NSMutableArray *mutableArrayInCheck = nil;
id whatIsThis = [[NSUserDefaults standardUserDefaults] objectForKey:@"mutableArray_01"];
if([whatIsThis isKindOfClass:[NSMutableArray class]])
{
NSLog(@"The array is mutable.");
mutableArrayInCheck = (NSMutableArray *)whatIsThis;
}
if([whatIsThis isKindOfClass:[NSArray class]])
{
NSLog(@"The array is immutable.");
}
if ([whatIsThis isMemberOfClass:[NSMutableArray class]])
{
NSLog(@"The array is a member of NSMutableArray class");
}
if (mutableArrayInCheck)
{
[mutableArrayInCheck addObject:@"three"];
NSLog([mutableArrayInCheck description]);
}
}
Now, according to the apple documentation, one would expect the console to only display the immutable line. But when I execute the code, the following lines are displayed in the console:
2012-01-05 18:47:33.328 Tester_01[78533:f803] The array is mutable.
2012-01-05 18:47:33.348 Tester_01[78533:f803] The array is immutable.
2012-01-05 18:47:33.349 Tester_01[78533:f803] (
one,
two,
three
)
So, I am wondering if there is something that I am missing here.
For additional information, the code that executes the tests is as shown:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL setupKey = NO;
if (setupKey)
{
[self setupTest];
}
BOOL checkKey = YES;
if (checkKey)
{
[self checkTest];
}
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Initially, I ran the project with setupKey set to YES. After the first run, I changed the setupKey to NO. The console log is an outcome whilst the setupKey was set to NO. Let me know what you think.
Strictly speaking you are right. The statement “Values returned are immutable” is confusing, because this makes it look like getting a mutable object should be impossible. However, the statement should be read as “Values returned cannot be guaranteed to be mutable”. So, even if you store a mutable array, when you read the value back, you will get a NSArray object (which might be an object of the mutable descendent class NSMutableArray, but this cannot be guaranteed and may vary between runs or depend on the array content).