2011-07-18 13 views
3

私はコンパイルしないで書き込んだコアデータ検証メソッドを持っています。メソッドをコンパイルしてコンパイルできるようにすることはできますが、実行時エラーが発生します。このメソッドの2つのバージョンは次のとおりです(2番目のバージョンでは「*」が見つからないことに注意してください)。このバージョンは、(以下警告およびエラーを参照)コンパイラの警告やエラーを与える(id *)変数または(id *)引数を使用してメッセージを送信する正しい方法

- (BOOL)validateInitialValue:(id *)value error:(NSError **)error { 
    if (*value == nil) { 
     return YES; 
    } 
    if ([*value doubleValue] < 0.0) { 
     return NO; 
    } 
    return YES; 
} 

- (BOOL)validateInitialValue:(id *)value error:(NSError **)error { 
    if (value == nil) { 
     return YES; 
    } 
    if ([value doubleValue] < 0.0) { 
     return NO; 
    } 
    return YES; 
} 
「:認識されないセレクタークラス0x7fff70a448e8に送ら+ [NSCFNumberのdoubleValue]」このバージョンは、ランタイムエラーがコンパイルしかし与えます

コンパイラのエラーと警告:私は最終的に問題は呼び出し元のコードであってもよいことを考え出し

warning: Semantic Issue: Receiver type 'id *' is not 'id' or interface pointer, consider casting it to 'id' 
warning: Semantic Issue: Method '-doubleValue' not found (return type defaults to 'id') 
error: Semantic Issue: Invalid operands to binary expression ('id' and 'double') 

- (void)setInitialValue:(NSNumber *)initialValue { 
    [self willChangeValueForKey:@"initialValue"]; 
    [self validateValue:initialValue forKey:@"initialValue" error:nil]; 
    [self setPrimitiveInitialValue:initialValue]; 
    [self didChangeValueForKey:@"initialValue"]; 
} 

initialValueの前に '&'を使用するように呼び出し元を変更し、メソッドの最初のバージョンを使用し、すべてが機能しました。だから、新しい呼び出し元のコードは、1つの行は、このように変更されました:

[self validateValue:&initialValue forKey:@"initialValue" error:nil]; 

しかし、それは「&」を持っている必要が本当にあります? setPrimitiveInitialValueは '&'を使用しません。私はObjective-Cの理解がまだ十分に進んでいないように感じています。あなたが知っているすべての人は、非常に単純な答えでこれを些細な疑問に思うでしょう。

+1

その他'id *'の意味を説明しました。 Objective-Cオブジェクトの最初のフィールドがそのクラスオブジェクトへのポインタであるということを、ランタイムエラーが発生した理由を追加したいと思います。だから '(id *)value'として' initialValue'を渡し、 '[* value doubleValue]'を呼び出すと '[* initialValue doubleValue]'となり、あるオブジェクト/構造体へのポインタはポインタと同じですその最初のフィールドに渡すので、実際には*クラスのdoubleValueを呼び出しています* NSCFNumber - クラスメソッドを示す実行時エラーの+記号に注目してください。 –

答えて

4

あなたは問題が呼び出し元のコードであることをおっしゃるとおり

チャンスは、これはあなたが探しているものである、あります。 id *のポインタからidの値を示します。オブジェクト変数自体はidなので、&で取得する変数にポインタが必要です。あなたの検証方法は、それが有効にするために値を変更する方法を知っているならば、それはYESを返すことができ、また、(変数を設定することにより)、有効なオブジェクトを返す、ようにあなたがポインタを渡す

理由があります。

- (BOOL)validateInitialValue:(id *)value error:(NSError **)error { 
    if (*value == nil) { 
     return YES; 
    } 
    if ([*value doubleValue] < 0.0) { 
     return NO; 
    } 
    if ([*value doubleValue] > 0.0 && [*value doubleValue] < 1.0) { 
     *value = [NSNumber numberWithInt:0]; 
    } 
    return YES; 
} 

setPrimitiveValue:

は、呼び出し元のコンテキストで変数を設定する必要はありませんので、それだけで idを取る:1より小さい数が0にクランプする必要があるのであれば、たとえば、あなたが行う可能性があります。 ( validateValue:forKey:error:のように動作するメソッドはほとんどありません。変更したかどうかを示すために BOOLを返したい場合は、一般的にそれを行いますが、変更された値も返す必要があります)

5

id自体がポインタを表します。したがって、id *を使用すると、実際にポインタへのポインタを参照しています。 this優れたチュートリアルの最初の部分は、この概念を説明しています。

- (BOOL)validateInitialValue:(id)value error:(NSError **)error { 
    if (value == nil) { 
     return YES; 
    } 
    if ([value doubleValue] < 0.0) { 
     return NO; 
    } 
    return YES; 
} 
+1

具体的には、 'id'は一般的なObjective-Objectへのポインタのために[objc.h](http://opensource.apple.com/source/objc4/objc4-437.3/runtime/objc.h)の' typedef'です。 Cオブジェクト: 'typedef struct objc_object { クラスisa; } * id; '([ランタイムリファレンス](http://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html#//apple_ref/doc/uidも参照してください)/TP40001418-CH3g-BAJFBCCJ)) –

+2

このメソッドは、コアデータ検証システムの一部です。引数の正しい型は確かに 'id *'です。 – Chuck

+0

答えがありがとう、それは助けますが、チャックは正しいです、私は引数の種類を選択することはできませんでした。私はスーパークラスのメソッドをオーバーライドしています。チャックの答えはこれを説明しています。それは私の質問にすべて答えるので、彼のgetはこの質問の「チェック」です。みんなありがとう! – Jason

関連する問題