概要
使用する元データは同一のものを使用するが、後続処理によって値を分ける必要がある場合にアドレス参照を意識する。
ゴール
データA, B, Cを元データ格納用変数に格納し、配列A、配列Bでは元データを利用する。処理の分岐先で配列Aと配列Bを処理によって異なるデータにしたい。
ハマった内容
配列(ここではNSMutableArrayを例にとる)を代入コピーする場合、参照されているポインタが渡される。
そのため、変数A、変数Bどちらかに新しくオブジェクトを追加した場合、変数Aと変数Bのポインタが同一のものとなってしまう。
サンプル
※修正前
Before.m
NSMutableArray *useDataArray = @[].mutableCopy;
[useDataArray addObject: @"http://www.testA.jp"];
[useDataArray addObject: @"http://www.testB.jp"];
[useDataArray addObject: @"http://www.testC.jp"];
NSMutableArray *sampleA = @[].mutableCopy;
NSMutableArray *sampleB = @[].mutableCopy;
sampleA = useDataArray;
// 参照が渡される
// 同一のデータが複製されるが、相互の参照先アドレスが紐付いている状態
sampleB = sampleA;
[sampleA addObject: @"http://www.testD.jp"];
// A or Bどちらかにオブジェクトを追加すると参照されるポインタが更新される
NSLog(@"sampleA:%@", sampleA);
NSLog(@"sampleB:%@", sampleB);
Before.log
sampleA:(
"http://www.testA.jp",
"http://www.testB.jp",
"http://www.testC.jp",
"http://www.testD.jp"
sampleB:(
"http://www.testA.jp",
"http://www.testB.jp",
"http://www.testC.jp",
"http://www.testD.jp"
)
// 同一のアドレスを参照している
※修正後
After.m
NSMutableArray *useDataArray = @[].mutableCopy;
[useDataArray addObject: @"http://www.testA.jp"];
[useDataArray addObject: @"http://www.testB.jp"];
[useDataArray addObject: @"http://www.testC.jp"];
NSMutableArray *sampleA = @[].mutableCopy;
NSMutableArray *sampleB = @[].mutableCopy;
sampleA = useDataArray;
// 変更可能(mutable)プロパティを加える
sampleB = sampleA.mutableCopy;
[sampleA addObject: @"http://www.testD.jp"];
NSLog(@"sampleA:%@", sampleA);
NSLog(@"sampleB:%@", sampleB);
After.log
sampleA:(
"http://www.testA.jp",
"http://www.testB.jp",
"http://www.testC.jp",
"http://www.testD.jp"
)
sampleB:(
"http://www.testA.jp",
"http://www.testB.jp",
"http://www.testC.jp"
)
// 異なるデータが格納される
まとめ
アドレス参照型のものを複製する場合、代入演算子でコピーすると相互の変数に対するアドレスが紐づくため、mutable属性を与えて代入をするとよい。
※ご指摘ありがとうございます。内容を修正しました。