【Objective-C】NSMutableArrayでmutableCopyをすればコピー元の配列の変更状況が常に反映される!?そうではないって話。【Xcode10.1対応】
こういう人に向けて発信しています。
・NSMutableArrayの取扱いや理解が浅い人
・mutableCopyについて理解が浅い人
・Objective-C初心者
そもそもmutableCopyとは?
NSMutableArray *copyArray = [[NSMutableArray alloc] init];
[copyArray addObject:@"A"];
[copyArray addObject:@"B"];
NSMutableArray *mutableArray = copyArray.mutableCopy;
よく「ミュータブルな配列に戻す」という表現がなされます。
NSMutableArray *mutableArray = @[@"A",@"B"].mutableCopy;
配列リテラルをそのまま代入できないので、
レシーバに指定したNSArrayオブジェクトを、
NSMutableArrayオブジェクトに変換して戻しているのが、
mutableCopyになります。
ざっくり説明すると、
NSArrayを可変(mutable)オブジェクトにしているメソッドになります。
コピー先MutableArrayはコピー元の変更を反映するのか?
タイトルでも否定しているように、一切しません。
下記コードで実際にログを見てみてください。
-(void)testLog{
NSMutableArray *copyArray = [[NSMutableArray alloc] init];
NSLog(@"(1)ログ:copyArray %@",copyArray);
[copyArray addObject:@"A"];
[copyArray addObject:@"B"];
[copyArray addObject:@"C"];
[copyArray addObject:@"D"];
[copyArray addObject:@"E"];
NSLog(@"(2)ログ:copyArray %@",copyArray);
NSMutableArray *mutableArray = copyArray.mutableCopy;
NSLog(@"mutableCopy直後の各配列の内容を確認してみる");
NSLog(@"(3)ログ:copyArray %@",copyArray);
NSLog(@"(4)ログ:mutableArray %@",mutableArray);
//copyArrayの中身を全て削除する。
[copyArray removeAllObjects];
NSLog(@"(5)ログ:copyArray %@",copyArray);
NSLog(@"(6)ログ:mutableArray %@",mutableArray);
}
要約すると、
*copyArrayをコピーした後、copyArrayの中身を全削除しています。
(5),(6)ログにて同一の内容が反映されていないとおかしいですよね。
ログをとってみた。
(1)ログ:copyArray ()
(2)ログ:copyArray (
A,B,C,D,E
)
mutableCopy直後の各配列の内容を確認してみる
(3)ログ:copyArray (
A,B,C,D,E
)
(4)ログ:mutableArray (
A,B,C,D,E
)
(5)ログ:copyArray (
※空の配列となっている。
)
(6)ログ:mutableArray (
A,B,C,D,E
)
やはり、mutableCopyはコピー元の配列を反映するメソッドではないです。
コピー元を反映する方法について
こちらの記事がとても参考になりました。
https://qiita.com/yu_okb/items/3de1606501bd9bd07fdb
下記のようなコードであれば、参照先のアドレスが紐付いているので、
同一の内容が帰ってきます(同一のアドレスを参照して配列を操作しているため)
-(void)testLog{
NSMutableArray *copyArray = [[NSMutableArray alloc] init];
[copyArray addObject:@"A"];
[copyArray addObject:@"B"];
[copyArray addObject:@"C"];
[copyArray addObject:@"D"];
[copyArray addObject:@"E"];
NSMutableArray *mutableArray = copyArray;
上記のコードでログを取ってみました。
copyArrayを削除した場合、mutableArrayも同様に反映されるはずです。
rootProject[4658:478689] (1)ログ:copyArray (
)
rootProject[4658:478689] (2)ログ:copyArray (
A,B,C,D,E
)
rootProject[4658:478689] mutableCopy直後の各配列の内容を確認してみる
rootProject[4658:478689] (3)ログ:copyArray (
A,B,C,D,E
)
rootProject[4658:478689] (4)ログ:mutableArray (
A,B,C,D,E
)
rootProject[4658:478689] (5)ログ:copyArray (
)
rootProject[4658:478689] (6)ログ:mutableArray (
)
今度はポイントのアドレスについて注目してみる
-(void)testLog{
NSMutableArray *copyArray = [[NSMutableArray alloc] init];
NSLog(@"copyArrayのポインタのアドレス:%p", copyArray);
[copyArray addObject:@"A"];
[copyArray addObject:@"B"];
NSMutableArray *mutableArray = copyArray.mutableCopy;
NSLog(@"mutableArrayのポインタのアドレス:%p", mutableArray);
}
//出力
rootProject[4664:480580] copyArrayのポインタのアドレス:0x2818a5f80
rootProject[4664:480580] mutableArrayのポインタのアドレス:0x2818a6070
ご覧の通り、
copyArrayとmutableArrayのポインタのアドレスが異なる事がわかります。
copyArray = mutableArrayの時のログ
-(void)testLog{
NSMutableArray *copyArray = [[NSMutableArray alloc] init];
NSLog(@"copyArrayのポインタのアドレス:%p", copyArray);
[copyArray addObject:@"A"];
[copyArray addObject:@"B"];
NSMutableArray *mutableArray = copyArray;
NSLog(@"mutableArrayのポインタのアドレス:%p", mutableArray);
}
//出力
rootProject[4667:481329] copyArrayのポインタのアドレス:0x280dd4bd0
rootProject[4667:481329] mutableArrayのポインタのアドレス:0x280dd4bd0
ご覧の通り、ポインタのアドレスが同一です。