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に示すように、変更後、参照を検索して取得した後でも削除されませんsurname1
。removeObject
なぜこれが起こっているのですか?可変コンテナーに可変オブジェクトを含めることはできませんか?
含まれているオブジェクトのハッシュをキャッシュするこの投稿を読みましたが、それが問題になる可能性があります。NSSet
もしそうなら、それをきれいにする方法はありますか?代替ソリューションはありますか?
好奇心のために、例 1が機能する理由を教えてください。
アップデート:
Apple の Collection Programming Topicsから:
変更可能なオブジェクトがセットに格納されている場合、オブジェクトのハッシュ メソッドが変更可能なオブジェクトの内部状態に依存してはならず、変更可能なオブジェクトがセット内にある間は変更されるべきではありません。たとえば、変更可能な辞書をセットに入れることができますが、そこにある間は変更してはなりません。(特定のオブジェクトがコレクション内にあるかどうかを知るのは難しい場合があることに注意してください)。
更新 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 )}