我正在使用一个NSMutableSet
包含可变对象的对象。我NSMutableSet
在尝试删除已变异的对象时发现不一致。
为了隔离问题,我编写了一个快速测试来说明问题(如果有的话):
示例 1:按预期工作
NSMutableSet *colors = [[NSMutableSet alloc] init];
NSMutableString *color1 = [[NSMutableString alloc] initWithString:@"Blue"];
NSMutableString *color2 = [[NSMutableString alloc] initWithString:@"Green"];
[colors addObject:color1];
[colors addObject:color2];
NSLog(@"%@",[colors description]); // {( Green, Blue )}
[color1 insertString:@"Cobalt " atIndex:0];
NSLog(@"%@",[colors description]); // {( Green, "Cobalt Blue" )}
[colors removeObject:color1];
NSLog(@"%@",[colors description]); {( Green )}
示例 2:未按预期工作
NSMutableSet *surnames = [[NSMutableSet alloc] init];
NSMutableString *surname1 = [[NSMutableString alloc] initWithString:@"Brown"];
NSMutableString *surname2 = [[NSMutableString alloc] initWithString:@"Homes"];
[surnames addObject:surname1];
[surnames addObject:surname2];
NSLog(@"%@",[surnames description]); // {( Homes, Brown )}
[surname1 appendString:@"ie"];
NSLog(@"%@",[surnames description]); // {( Homes, Brownie )}
[surnames removeObject:surname1];
NSLog(@"%@",[surnames description]); // {( Homes, Brownie )}
NSString *surnameToRemove = nil;
for (NSString *surname in surnames) {
if ([surname isEqualToString:@"Brownie"]) {
surnameToRemove = surname;
break;
}
}
[surnames removeObject:surnameToRemove];
NSLog(@"%@",[surnames description]); // {( Homes, Brownie )}
如示例 2所示,在 mutating 之后,即使在通过搜索获取引用之后surname1
,removeObject
也不会将其删除。为什么会这样?可变容器不能包含可变对象吗?
我在这篇文章中读过NSSet
缓存包含对象的哈希值,这可能是问题所在。如果是这样,有没有办法清理它?任何替代解决方案?
只是出于好奇,为什么示例 1有效?
更新:
如果可变对象存储在集合中,则对象的哈希方法不应该依赖于可变对象的内部状态,或者当可变对象在集合中时不应该修改它们。例如,一个可变字典可以放在一个集合中,但是当它在那里时你不能改变它。(请注意,很难知道给定对象是否在集合中)。
更新 2:
重要的是,如果您在 Mac 或 iOS 应用程序上运行,示例 2将返回不同的日志输出:
登录 Mac 应用程序(按预期工作):
{( Green, Blue )}
{( Green, "Cobalt Blue" )}
{( Green )}
{( Brown, Homes )}
{( Brownie, Homes )}
{( Homes )}
-[__NSSetM removeObject:]: object cannot be nil
登录一个 iOS 应用程序(没有像我预期的那样工作):
{( Green, Blue )}
{( Green, "Cobalt Blue" )}
{( Green )}
{( Homes, Brown )}
{( Homes, Brownie )}
{( Homes, Brownie )}
{( Homes, Brownie )}
更新 3:
与示例 2中的代码相同,但NSMutableArray
似乎可以工作......所以猜测如何NSMutableSet
使用哈希。我相信正如上面链接线程中所评论的那样,它正在缓存它们:
NSMutableArray *surnames = [[NSMutableArray alloc] init];
NSMutableString *surname1 = [[NSMutableString alloc] initWithString:@"Brown"];
NSMutableString *surname2 = [[NSMutableString alloc] initWithString:@"Homes"];
[surnames addObject:surname1];
[surnames addObject:surname2];
NSLog(@"%@",[surnames description]); // {( Homes, Brown )}
[surname1 appendString:@"ie"];
NSLog(@"%@",[surnames description]); // {( Homes, Brownie )}
[surnames removeObject:surname1];
NSLog(@"%@",[surnames description]); // {( Homes )}