2012-06-06 26 views
7

考慮下面的代碼:Objective-C的對象的typedef產量奇怪@encode並打破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導致typedef NSString MyString有效地創建一個結構,該結構包含一個類型爲Class的變量,然後在使用MyString時使用該變量。例如該結構是這樣的(諮詢this後):

struct NSString { 
    Class a; 
}; 

它的排序是有道理的,但促使valueForKey:失敗,大概是因爲它是一個結構現在,所以不能返回以同樣的方式作爲對象。或者更確切地說,它落入搜索順序described in the docs的「拋出異常」部分。

我只是想了解它是什麼引起這種情況發生,爲什麼它不能以同樣的方式對待我的2 typedefs。

+0

雖然你綜合了這些屬性,但你似乎沒有真正的伊娃支持他們。 – 2012-06-06 19:38:51

+4

最近版本的編譯器自動爲合成屬性創建ivars。 –

+0

一般來說,@encode字符串並不是非常有用。例如,在處理C++類型時,它們很快變得過於複雜。 – bbum

回答

3

我在WWDC 2012的答案,這個事實證明,這種行爲是預期的那樣是與GCC二進制兼容性。

對我來說似乎很奇怪,他們會有效地引入我認爲與舊GCC二進制兼容的錯誤。我希望這種事情最終將被逐步淘汰,轉而使用正確的編譯器。

+0

我覺得我看到這與鐺4.2,FWIW。與它意圖不當行爲一致。 – nmr

+0

確實。這就是蘋果所說的。 – mattjgalloway

1

我可以重現這一點,但只能用gcc。隨着鐺,我得到:

$ 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) 

所以,似乎鏗鏘聲開發者同意你應該如何工作。

(我也試過蘋果鐺3.0版。同樣不錯的結果。)

+0

有趣,因爲我也使用鏗鏘。你有ARC嗎? – mattjgalloway

+0

添加了我用於構建我的問題的clang版本和命令行。 – mattjgalloway

+0

不使用ARC。 'clang -std = gnu99 foo.m -framework Foundation'我需要gnu99,因爲在'for'循環中聲明瞭'i'。 –