見出し画像

【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

ご覧の通り、ポインタのアドレスが同一です。


この記事が気に入ったらサポートをしてみませんか?