2012-06-06 9 views
7

を壊し、次のコードを考えてみましょう:Objective-CのオブジェクトとKVC

#import <Foundation/Foundation.h> 
#import <objc/runtime.h> 

typedef NSString* MyStringRef; 
typedef NSString MyString; 

@interface ClassA : NSObject 
@property (nonatomic, copy) MyStringRef stringA; 
@property (nonatomic, copy) MyString *stringB; 
@end 

@implementation ClassA 
@synthesize stringA = _stringA; 
@synthesize stringB = _stringB; 
@end 

int main() { 
    unsigned int count = 0; 
    Ivar *ivars = class_copyIvarList([ClassA class], &count); 
    for (unsigned int i = 0; i < count; i++) { 
     Ivar thisIvar = ivars[i]; 
     NSLog(@"thisIvar = %s, %s", ivar_getName(thisIvar), ivar_getTypeEncoding(thisIvar)); 
    } 

    ClassA *a = [[ClassA alloc] init]; 
    NSLog(@"Out: %@", [a valueForKey:@"stringA"]); 
    NSLog(@"Out: %@", [a valueForKey:@"stringB"]); 
} 

これが出力されます。

$ clang --version 
Apple clang version 3.1 (tags/Apple/clang-318.0.58) (based on LLVM 3.1svn) 
Target: x86_64-apple-darwin11.4.0 
Thread model: posix 

$ clang -o typedef -fobjc-arc -framework Foundation typedef.m && ./typedef 
2012-06-06 20:14:15.881 typedef[37282:707] thisIvar = _stringA, @"NSString" 
2012-06-06 20:14:15.884 typedef[37282:707] thisIvar = _stringB, ^{NSString=#} 
2012-06-06 20:14:15.885 typedef[37282:707] Out: (null) 
2012-06-06 20:14:15.888 typedef[37282:707] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<ClassA 0x7fabe0501480> valueForUndefinedKey:]: this class is not key value coding-compliant for the key stringB.' 
*** First throw call stack: 
(
    0 CoreFoundation      0x00007fff835fef56 __exceptionPreprocess + 198 
    1 libobjc.A.dylib      0x00007fff878e5d5e objc_exception_throw + 43 
    2 CoreFoundation      0x00007fff836891b9 -[NSException raise] + 9 
    3 Foundation       0x00007fff83e77703 -[NSObject(NSKeyValueCoding) valueForUndefinedKey:] + 240 
    4 Foundation       0x00007fff83dae38e _NSGetUsingKeyValueGetter + 108 
    5 Foundation       0x00007fff83dae315 -[NSObject(NSKeyValueCoding) valueForKey:] + 392 
    6 typedef        0x000000010e84bc6d main + 317 
    7 typedef        0x000000010e84b9c4 start + 52 
) 

私がここに持っている問題は、それが客観的に約あるものです-Cは、がClass型の1つの変数を含む構造体を効果的に作成してから、MyStringを使用する場所を使用します。例えば構造体は、(thisに相談した後に)次のようになります。

struct NSString { 
    Class a; 
}; 

それは一種の理にかなっているが、それはオブジェクトと同じようにそれを返すことができませんので、それは、今の構造体だと思われるので、失敗するvalueForKey:を引き起こし。または、より正確には、検索順序described in the docsの「スロー例外」部分に該当します。

私は、これが起こる原因となる理由と、同じように2つのtypedefを扱うことができない理由について理解したいと思います。

+0

プロパティを合成することはできますが、実際のivarをバッキングしているようには見えません。 –

+4

コンパイラの最近のバージョンでは合成されたプロパティのivarsが自動的に作成されます。 –

+0

一般に、@encode文字列はあまり有効ではありません。例えば、C++型を扱う場合、それらは素早く複雑になります。 – bbum

答えて

3

私はそれはGCCとのバイナリ互換性のためであるとして、この動作が期待されていることが判明したWWDC 2012で、これに対する答えを得ました。

私はバグが古いGCCとバイナリ互換性があると考えると効果的だと私には奇妙に思えます。私はこの種のことが最終的には正しいコンパイラのために段階的に廃止されることを願っています。

+0

私はclang 4.2、FWIWでこれを見ていると思います。それは意図的な誤動作と一致しています。 – nmr

+0

確かに。それはAppleが言ったことだ。 – mattjgalloway

1

私はこれを再現できますが、gccのみで再現できます。 clangを使って、私は得る:

$ clang --version 
Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn) 
Target: x86_64-apple-darwin10 
Thread model: posix 
$ ./a.out 
2012-06-06 15:16:37.947 a.out[61063:903] thisIvar = _stringA, @"NSString" 
2012-06-06 15:16:37.949 a.out[61063:903] thisIvar = _stringB, @"NSString" 
2012-06-06 15:16:37.949 a.out[61063:903] Out: (null) 
2012-06-06 15:16:37.950 a.out[61063:903] Out: (null) 

それで、clangの開発者はあなたがどのように動作すべきかについてあなたに同意すると思われる。

(私はまた、Appleの打ち鳴らすのバージョン3.0を試してみました。同じ良い結果。)

+0

興味深いです、私もclangを使っているからです。 ARCを有効にしていますか? – mattjgalloway

+0

質問にビルドするために使用したclangのバージョンとコマンドラインを追加しました。 – mattjgalloway

+0

ARCを使用していません。 'clang -std = gnu99 foo.m -framework Foundation'' for'ループ内に 'i'が宣言されているため、gnu99が必要でした。興味深いもの: –

関連する問題