7

私はobjective-cが初めてで、iPhone用の小さなアプリを作成しようとしています。
ここで、この小さなエラーを除いて、ほぼ完了です。実際、適切な解決策を見つけるためにGoogleで何時間も検索しましたが、残念ながら機能する解決策を見つけることができません.
ここでこのチュートリアルを使用して UITableView を構築しています: UITableView チュートリアル 完全なエラー メッセージは次のようになります。

* キャッチされない例外 'NSInternalInconsistencyException' が原因でアプリを終了します。理由: '* -[NSCFArray insertObject:atIndex:]: 変更メソッドが不変オブジェクトに送信されました'

これはデータ コントローラー ヘッダーです: MyLinksDataController.h

@interface MyLinksDataController : NSObject {

NSMutableArray *tableList; //<---important part

}

- (unsigned)countOfList;
- (id)objectInListAtIndex:(unsigned)theIndex;
- (void)addData:(NSString *)data; //<---important part
- (void)removeDataAtIndex:(unsigned)theIndex;

@property (nonatomic, copy, readwrite) NSMutableArray *tableList; //<---important part

.....

データ コントローラー メソッド: MyLinksDataController.m

#import "MyLinksDataController.h"

@implementation MyLinksDataController

@synthesize tableList;

- (id)init {

    if (self = [super init]) {

        NSLog(@"Initilizing DataController");
        //Instantiate list
        NSMutableArray *localList = [[NSMutableArray alloc] init];
        self.tableList = [localList copy];
        [localList release];

        //Add initial Data
        [self addData:@"AAAAAAAAAAAAAA"];
        [self addData:@"BBBBBBBBBBBBBB"];

    }

    return self;

}

-------------------------------ソースコードの後半で-------------- --------------------

- (void)addData:(NSString*)data; {

    [tableList addObject:data]; //<---- here the app crashes

}

どんな助けでも大歓迎です。

よろしくお願いいたします。

ダニエル

4

5 に答える 5

27

次のinitステートメントのように、コピーメッセージを NSMutableArray に送信すると、不変のコピーが返されます。

self.tableList = [localList copy];

Cocoa のドキュメントでは、不変という言葉を使用して、読み取り専用で初期化後に変更できないオブジェクトを指しています。したがって、addObject:への後続の呼び出しは失敗し、エラー メッセージが表示されます。

上記の割り当てステートメントがコンパイラの警告をトリガーしないことに注意してください。copyは、コンパイラに関する限り、NSMutableArray* tableList に快適に収まるidを返します。メッセージが渡されないため、ここでも実行時エラーは発生しません。NSArray ポインターは、NSMutableArray ポインター変数に配置されるだけです。

変更可能なコピーを取得するには、代わりにmutableCopyを使用してください。

copymutableCopyの両方が新しい配列を作成し、元の内容をそれにコピーすることに注意してください。コピーの変更はオリジナルには反映されません。元の配列への別の参照が必要な場合は、代わりに保持を使用してください。

詳細については、copyWithZone リファレンスの説明セクションとNSMutableCopying プロトコル リファレンスを参照してください。

于 2009-08-03T22:40:04.203 に答える
5

基本的に、Cocoa のメモリ管理ルール (具体的には、これらの詳細) に遭遇しています。不変バージョンと可変バージョンを持つオブジェクトがある場合、オブジェクトに送信-copyすると不変オブジェクトが返されます。

関連する部分を見ていきましょう。

NSMutableArray *localList = [[NSMutableArray alloc] init];

これにより、所有する新しい空の可変配列が作成されます。罰金。

self.tableList = [localList copy];

これにより、空の配列の不変のコピーが作成されます。さらに、あなたはこの新しく作成されたコピーを所有しています。それはあなたが現在所有している 2 つのオブジェクトです。

これにより、コピーしたオブジェクトもプロパティに割り当てられますtableList。プロパティ宣言を見てみましょう。

@property (nonatomic, copy, readwrite) NSMutableArray *tableList;

このプロパティはcopy属性で宣言されているため、新しい値が割り当てられるたびに別の-copyメソッドが送信されます。ただし、この 3 番目のコピーはあなたが所有するのではなく、オブジェクトが所有します。

[localList release];

これにより、元の空の可変配列が解放されます。わかりましたが、まだ 2 行目で作成した未リリースのものが浮かんでいます。それはメモリリークです。

何かの変更可能なコピーが実際に必要な場合は、-mutableCopyメソッドが必要です。(これらのメソッドのドキュメントは、 および にNSCopyingあります。) ただし、割り当てられたものに送信さNSMutableCopyingれるため、変更可能なバージョンの何かを属性を持つプロパティに取得することは決してありません。プロパティは属性の代わりに属性を使用する必要があり、それを初期化するコードは次のようになります。copy-copyretaincopy

NSMutableArray *localList = [[NSMutableArray alloc] init];
self.tableList = localList;
[localList release];

または、短いバージョン:

self.tableList = [NSMutableArray array];

この状況では何もコピーする必要はありません。新しいオブジェクトを作成するだけです。

于 2009-08-03T23:55:24.910 に答える
0

これにより、問題が解決されます。

NSMutableArray *localList = [[NSMutableArray alloc] init];
self.localList = [[NSMutableArray alloc]initWithArray:localList];
于 2014-11-18T08:14:23.193 に答える