Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSUserDefaults is returning a mutable array

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.

like image 306
Jin Avatar asked Jan 06 '12 03:01

Jin


2 Answers

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).

like image 131
marcelnijman Avatar answered Oct 22 '22 14:10

marcelnijman


isKindOfClass the method is not appropriate for the class cluster

the next paragraph is in the documentation

Be careful when using this method on objects represented by a class cluster. Because of the nature of class clusters, the object you get back may not always be the type you expected. If you call a method that returns a class cluster, the exact type returned by the method is the best indicator of what you can do with that object. For example, if a method returns a pointer to an NSArray object, you should not use this method to see if the array is mutable, as shown in the following code:

 // DO NOT DO THIS!
 //if ([myArray isKindOfClass:[NSMutableArray class]])
 //{
 // Modify the object
 //}
like image 22
RockLee Avatar answered Oct 22 '22 15:10

RockLee