Mutable Objects in Collections

寵の児 提交于 2019-12-06 05:16:04

I will show you an example.

Let's define our own mutable key for a dictionary, note it can be copied, it defines an implementation of hash and of equality.

@interface MyKey : NSObject <NSCopying>

@property (nonatomic, copy, readwrite) NSString *keyData;

@end

@implementation MyKey

- (id)initWithData:(NSString *)data {
    self = [super init];

    self.keyData = data;

    return self;
}

- (id)copyWithZone:(NSZone *)zone {
    MyKey *key = (MyKey *) [[[self class] alloc] init];
    key.keyData = self.keyData;

    return key;
}

- (NSUInteger)hash {
    return self.keyData.length;
}

- (BOOL)isEqual:(id)object {
    if (![object isMemberOfClass:[self class]]) {
        return NO;
    }

    MyKey *key = object;

    return [self.keyData isEqualToString:key.keyData];
}

@end

Now let's have a simple test case:

Let's define some keys

MyKey *key1 = [[MyKey alloc] initWithData:@"key1"];
MyKey *key2 = [[MyKey alloc] initWithData:@"key2"];
MyKey *keyX = [[MyKey alloc] initWithData:@"XXX"];

And a simple dictionary

NSDictionary *dictionary = @{key1: @"value1", key2: @"value2"};

Let's see what's inside

NSLog(@"%lu", (unsigned long) dictionary.count);
NSLog(@"%@", dictionary);
NSLog(@"%@", [dictionary objectForKey:key1]);
NSLog(@"%@", [dictionary objectForKey:key2]);
NSLog(@"%@", [dictionary objectForKey:keyX]);

gives (expected)

2
{
    "<MyKey: 0x10010a8d0>" = value1;
    "<MyKey: 0x100108e40>" = value2;
}
value1
value2
(null)

Let's now change the value of a key

[(MyKey *)[[dictionary allKeys] objectAtIndex:0] setKeyData:@"XXX"];

Let's see what's inside again

NSLog(@"%lu", (unsigned long) dictionary.count);
NSLog(@"%@", dictionary);
NSLog(@"%@", [dictionary objectForKey:key1]);
NSLog(@"%@", [dictionary objectForKey:key2]);
NSLog(@"%@", [dictionary objectForKey:keyX]);

Gives

2   //expected
{
    "<MyKey: 0x10010a8d0>" = (null);  //huh, null value?
    "<MyKey: 0x100108e40>" = value2;
}
(null) //huh?
value2
(null) //huh?

What went wrong?

The internal structures of a dictionary are implemented using a hash table. The hash of they key is used to search a value. Once we change the data in the key, the hash value will also change. As a result, the dictionary won't be able to find the value stored for the given key.

The code is safe. NSDictionary does not care about mutability of values in the key-value pairs. What it does care is about mutability of keys which in your case are of NSString (immutable) type.

Also do not expect that if problem with mutability really exists it will manifest itself with exception or crash. It may pass unnoticed just giving incorrect results when querying collection, so the test you did does not help much.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!