2012-06-06 17 views
7

Xét đoạn mã sau:Objective-C đối tượng typedef sản lượng @encode lạ và phá vỡ 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"]); 
} 

Đây là kết quả:

$ 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ác câu hỏi tôi có ở đây là là những gì nó về Mục tiêu -C gây ra các typedef NSString MyString để có hiệu quả tạo ra một cấu trúc có chứa một biến loại Class và sau đó sử dụng mà tôi sử dụng MyString. ví dụ. các cấu trúc trông như thế này (sau khi trao đổi this):

struct NSString { 
    Class a; 
}; 

Nó loại có ý nghĩa nhưng làm cho valueForKey: thất bại, có lẽ bởi vì nó là một cấu trúc hiện nay, vì vậy nó không thể trở về mà trong cùng một cách như các đối tượng . Hoặc chính xác hơn, nó rơi vào phần "ném ngoại lệ" của đơn đặt hàng tìm kiếm described in the docs.

Tôi chỉ muốn hiểu những gì về ngôn ngữ gây ra điều này xảy ra và tại sao nó không thể xử lý 2 typedef của tôi theo cùng một cách.

+0

Mặc dù bạn tổng hợp các thuộc tính, bạn dường như không có một thanh công cụ thực sự sao lưu chúng. –

+4

Các phiên bản gần đây của trình biên dịch tạo ra các mã vạch cho các đặc tính tổng hợp tự động. –

+0

Nói chung, chuỗi @encode không hữu ích lắm. Họ nhanh chóng trở nên quá phức tạp khi giao dịch với các loại C++, ví dụ. – bbum

Trả lời

3

tôi nhận được câu trả lời cho điều này tại WWDC 2012. Nó chỉ ra rằng hành vi này được dự kiến ​​như là để tương thích nhị phân với GCC.

Có vẻ kỳ quặc với tôi rằng họ sẽ giới thiệu một cách hiệu quả những gì tôi xem là lỗi tương thích nhị phân với GCC cũ. Tôi hy vọng rằng loại điều này cuối cùng sẽ được loại bỏ theo ưu tiên của một trình biên dịch chính xác.

+0

Tôi nghĩ rằng tôi thấy điều này với clang 4.2, FWIW. Phù hợp với nó được dự định là hành vi sai trái. – nmr

+0

Thật vậy. Đó là những gì Apple nói. – mattjgalloway

1

Tôi có thể tạo lại điều này, nhưng chỉ với gcc. Với clang, tôi nhận được:

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

Vì vậy, có vẻ như các nhà phát triển tiếng lóng đồng ý với bạn về cách thức hoạt động.

(Tôi cũng đã cố gắng của Apple kêu vang phiên bản 3.0. Kết quả tốt Same.)

+0

Thú vị, vì tôi cũng đang sử dụng tiếng kêu. Bạn có bật ARC trong đó không? – mattjgalloway

+0

Đã thêm phiên bản tiếng lóng của tôi và dòng lệnh tôi đã sử dụng để xây dựng cho câu hỏi của mình. – mattjgalloway

+0

Không sử dụng ARC. 'clang -std = gnu99 foo.m -framework Foundation' Tôi cần gnu99 vì khai báo' i' trong vòng lặp 'for'. –