23

TableViewclassの作成中に間違いを犯し、誤って定義したままにしました@propertycopy

@property (copy, nonatomic) NSMutableArray *words; 

配列を「正しく」初期化しました: (これは 3 回目の試行です。mutableCopy や他のより良い方法を使用していないという事実は無視してください)

NSArray *fixedWords = @[@"Eeny", @"Meeny", @"Miny", @"Moe", @"Catch", @"A", @"Tiger", @"By", @"His", @"Toe"];
NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords];
self.words = mutWords;

しかし、後で配列を並べ替えようとすると、removeObjectAtIndex 行でクラッシュしました。

id object = [self.words objectAtIndex:fromIndexPath.row];
NSUInteger from = fromIndexPath.row;
NSUInteger to = toIndexPath.row;
[self.words removeObjectAtIndex:from];

エラーメッセージで

unrecognized selector sent to instance

これは、コピーが NSMutableArray を割り当てると、標準の (変更不可能な) NSArray が作成されることを意味するためであることを理解するために、多くの調査が必要でした。これが正しい動作である理由を誰かが説明できますか?

4

2 に答える 2

36

-copyは、可変のCocoaクラスによって実装されているため、常に不変の対応するクラスを返します。したがって、NSMutableArrayが-copyで送信されると、同じオブジェクトを含むNSArrayが返されます。

wordsにはメモリ修飾子があるためcopy、次の行は次のようになります。

NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords];
self.words = mutWords;

次のように拡張されます。

NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords];
self.words = [mutWords copy];

NSMutableArrayがNSArrayのサブクラスであるとすると、コンパイラは文句を言わず、NSArrayはその可変サブクラスのメソッドを認識しないため(内容を変更できないため)、時限爆弾が手元にあります。

于 2013-02-13T15:19:47.900 に答える
8

プロパティは魔法ではなく、単なる速記です。オブジェクトでaを宣言する@propertyと、コンパイラにバッキングインスタンス変数とそのアクセサメソッドを作成するように指示されます。実際に生成されるコードは、プロパティに設定した属性によって異なります。

ドット構文を使用してプロパティを設定することも省略形であることを覚えておくことが重要です。電話をかけると…</p>

self.words = mutWords;

…実際には、次のように、生成されたアクセサメソッドをバックグラウンドで呼び出しています。

[self setWords:mutWords];

プロパティに属性を指定したので、次のようなコードでアクセサメソッドcopyを生成するようにコンパイラに指示しました。-setWords:

- (void)setWords:(NSMutableArray *)words
{
    _words = [words copy];
}

それをすべて知っていると、何が起こっているかを確認できます。生成されたセッターメソッドは-copy入力引数を呼び出し、その結果をバッキングインスタンス変数に割り当てます。-copyメソッドは常に不変オブジェクトを返すように実装されているため(実行[aMutableString copy]するとNSStringが返されるなど)、そのプロパティは常に不変コピーを格納します。

于 2013-02-13T15:28:25.453 に答える