ios - 集合中的可变对象

标签 ios mutable

From the docs , 在集合对象中存储可变对象可能会导致问题。如果某些集合包含的对象发生变异,它们可能会变得无效甚至损坏,因为通过变异,这些对象可能会影响它们在集合中的放置方式。首先,作为散列集合中的键的对象的属性(例如 NSDictionary 对象或 NSSet 对象)如果发生更改,如果更改的属性影响对象的散列或 isEqual: 方法的结果,则会破坏集合。 (如果集合中对象的哈希方法不依赖于其内部状态,则损坏的可能性较小。)其次,如果有序集合(例如排序数组)中的对象的属性发生更改,这可能会影响该对象的方式与数组中的其他对象进行比较,从而使排序无效。

但是当我记录结果时,该对象已完美添加到集合中。实际上这样做并不安全?

-(void)mutableObjectsinCollections{
 NSMutableArray *arr1 = [[NSMutableArray alloc]init];
 NSMutableArray *arr2 = [[NSMutableArray alloc]init];
 NSMutableArray *arr3 = [[NSMutableArray alloc]init];
 NSMutableArray *arr4 = [[NSMutableArray alloc]init];


 [self addObjectsToArrayBefore:arr1];
 [self addObjectsToArrayBefore:arr2];
 [self addObjectsToArrayBefore:arr3];
 [self addObjectsToArrayBefore:arr4];

 NSDictionary *dict = @{@"arr1": arr1,@"arr2": arr2,@"arr3": arr3,@"arr4": arr4,@"arr5": arr5};
 NSLog(@"%@",dict);

 [self addObjectsToArrayAfter:arr1];
 [self addObjectsToArrayAfter:arr2];
 [self addObjectsToArrayAfter:arr3];
 [self addObjectsToArrayAfter:arr4];

 NSLog(@"%@",dict);
}

-(void)addObjectsToArrayBefore:(NSMutableArray *)arr{

for (int i = 1; i<10; i++) {
      [arr addObject:[NSNumber numberWithInteger:i]];
}
}

-(void)addObjectsToArrayAfter:(NSMutableArray *)arr{

for (int i = 10; i<20; i++) {
    [arr addObject:[NSNumber numberWithInteger:i]];
  }
}

最佳答案

我将向您展示一个示例。

让我们为字典定义我们自己的可变键,注意它可以被复制,它定义了哈希和相等的实现。

@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

现在让我们来看一个简单的测试用例:

让我们定义一些键

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

还有一个简单的字典

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

看看里面有什么

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

给出(预期)

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

现在让我们更改键的值

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

让我们再看看里面有什么

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

给予

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

出了什么问题?

字典的内部结构是使用哈希表实现的。它们的键的哈希用于搜索值。一旦我们改变了key中的数据,哈希值也会改变。因此,字典将无法找到为给定键存储的值。

关于ios - 集合中的可变对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20368173/

相关文章:

ios - 如何解决 CALayer 异常?

c++ - 为什么可变说明符被分类为存储类说明符,而不是限定符?

python - 使用外部函数更新内部 python 类参数

C++ 可变在这种情况下合适吗?

ios - 从 NSXMLElement 中获取值

ios - 防止转义 URL 中的括号

ios - 从 XIB 加载 UITabBarController 不包含来自 XIB 的任何内容

javascript - 如何在我的 iPhone 模拟器中查看嵌入式 Web 应用程序的启动日志

string - 如何传递 &mut str 并更改原始 mut str 而不返回?

python - 为什么在 Python 中不推荐使用 MutableString?