15

私はJavaのバックグラウンドから来て、Objective Cを学んでいます。文字列配列と配列を変更するメンバー関数を持つクラスを作成しようとしています。私のコードは次のようになりました:

@implementation TAWChapter

@synthesize mSubject;

@synthesize mItems;

- (id) init{
    self.mItems = [[NSMutableArray alloc] init];
    return self; 
}

- (void) setSubject:(NSString *)subject{
    self.mSubject = subject; 
}

- (void) addItem:(NSString *)item{
    [self.mItems addObject:@"asdf"]; 
}

@end

うまくいきませんでした。私は"[__NSArrayI addObject:]: unrecognized selector sent to instance "と を手に入れました"NSInvalidArgumentException"。インターネットで検索した後、コンストラクターの単一行を次のように変更しました。

self.mItems = [self.mItems init];

うまくいきましたが、なぜですか?Java 開発者の観点からは、最初のものは 2 番目のものよりも理にかなっています。そして、最初の行と同じ別の行がありますが、機能しています(コンストラクターではありません)。誰かが私にこれを説明してもらえますか?

4

4 に答える 4

31
  1. まず、Objective-C のコーディング規約に従う必要があります。Objective-C では、クラスにはコンストラクターがなく、初期化子があります。Objective-C では、イニシャライザはスーパークラスのイニシャライザを呼び出すため、次のようになります。

    - init
    {
        self = [super init];
        if (!self) return nil;
    
        // set up other stuff here 
    
        return self;
    }
    
  2. 次に、ARC を使用していない場合、メモリ リークが発生する可能性があります。初期化子の最初の行は、所有しているオブジェクトを、所有権も取得する可能性が高いプロパティに割り当てます。次のいずれかを使用する必要があります。

    // property takes care of ownership
    self.mItems = [NSMutableArray array];
    

    また:

    // assign to instance variable directly with owned object
    mItems = [[NSMutableArray alloc] init];
    

    Apple は、KVO などをいじることができるため、初期化子でのアクセサー メソッドの使用を思いとどまらせることがありますが、アクセサー メソッドを一貫して使用することで、適切なオブジェクトの所有権とメモリ管理が保証されます。

  3. イニシャライザの行を次のように変更します。

    self.mItems = [self.mItems init];
    

    何もしませ。初期化メソッドが呼び出されると (通常は割り当てられた直後)、すべてのインスタンス変数が自動的に nil に設定されます。したがって、あなたがしていることは次のとおりです。

    self.mItems = [nil init];
    

    これはちょうどです:

    self.mItems = nil;
    

    initまた、最初にインスタンスを割り当てずに使用しないでください。また、一度しか使用しないでくださいinit

  4. スーパークラス自体を初期化しない場合、他の領域で問題が発生する可能性があります。Build & Analyzeを実行し、アナライザーによって指摘された問題を修正したことを確認します。

于 2012-05-06T23:20:00.213 に答える
7

object-c は c のスーパーセットであるため、基本的には c に "OO" 構文シュガーが含まれています。オブジェクトを作成 (または使用) する前に、ヒープ内にそのオブジェクト用のスペースを割り当てる必要があります。でこれを行い[Class alloc]ます。次のステップは、そのスペースの初期化です。alloc は、 init で初期化するヒープ内のそのスペースへのポインターを返します;)

だからあなたは電話しますClass *myObjc = [[Class alloc] init];

継承を使用する場合 (NSOBject から継承するため)、スーパークラスがすべてを適切に初期化していることを確認する必要があります。これが super の呼び出しです。実行時エラーが発生しないようにするには、if(self) を使用して暗黙的に実行する self != nil を確認します。

self.mItems = [self.mItems init]; // doesn't do anything, since you call the getter for mItems with self.mItems and try to init. then you try to set mItmes to itself. 

このコードを使用してください:

@implementation TAWChapter

@synthesize mSubject, mItems;

- (id)init
{
    self = [super init];
    if (self) {
        mItems = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void) setSubject:(NSString *)subject{
    mSubject = subject; 
}

- (void) addItem:(NSString *)item{
    [mItems addObject:item]; 
}

@end
于 2012-05-06T23:05:34.923 に答える
4

メソッドで呼び出しsuperて、その結果を割り当てる必要がありselfます。init

- (id)init
{
    self = [super init];
    if (self) {
        self.mItems = [[NSMutableArray alloc] init];
    }
    return self;
}
于 2012-05-06T23:02:07.897 に答える
2

もう 1 つの方法は、NSArray から NSMutableArray を作成することです。

NSMutableArray *myMutableArray = [NSMutableArray arrayWithArray:myArray];
于 2015-04-15T23:30:25.923 に答える