2009-10-01 28 views
5

Tôi đang làm việc thông qua chương "Mã hóa giá trị khóa" trong "Lập trình cho Mac OS X". Tôi đã xây dựng một giao diện với một thanh trượt và một nhãn, cả hai ràng buộc với fido, một int. Nếu tôi đặt thuộc tính cho fido thành chỉ đọc, di chuyển thanh trượt vẫn khiến nhãn thay đổi giá trị của nó. Tôi đã giả định rằng tôi sẽ nhận được một số loại lỗi cho việc này. Nếu thuộc tính là chỉ đọc, cách thanh trượt vẫn có thể ghi vào thuộc tính? Tôi nghĩ rằng nó sẽ không có setters tạo ra, và KVC sẽ không làm việc. Cảm ơn.Tại sao thuộc tính chỉ đọc vẫn cho phép ghi bằng KVC

Dưới đây là đoạn code tôi đang sử dụng:

#import <Cocoa/Cocoa.h> 

@interface AppController : NSObject 
{ 
    int fido; 
} 

@property (readonly, assign) int fido; 

@end 

#import "AppController.h" 

@implementation AppController 

@synthesize fido; 

- (id)init 
{ 
    [super init]; 
    [self setValue:[NSNumber numberWithInt:5] forKey:@"fido"]; 
    NSNumber *n = [self valueForKey:@"fido"]; 
    NSLog(@"fido = %@", n); 
    return self; 
} 
@end 

alt text http://idisk.me.com/nevan/Public/Pictures/Skitch/Window-20091001-174352.png

Trả lời

16

AppController.h:

@interface AppController : NSObject 
{ 
     int fido; 
} 

@property (readonly, assign) int fido; 
@end 

nhập khẩu "AppController.h"

@implementation AppController 
@synthesize fido; 
... 
@end 

Tại thời điểm này, bạn đã khai báo rằng AppController có phương thức -fido và bạn đã tổng hợp phương thức đó. Không có phương thức -setFido:. Vì vậy, tại sao "công việc" sau đây?

- (id)init 
{ 
     if (self=[super init]) { 
      [self setValue:[NSNumber numberWithInt:5] forKey:@"fido"]; 
      NSNumber *n = [self valueForKey:@"fido"]; 
      NSLog(@"fido = %@", n); 
     } 
     return self; 
} 

(BTW: Tôi cố định init của bạn để thực hiện các mô hình chính xác)

này hoạt động vì KVC sau một Heuristic để thiết lập hoặc nhận được giá trị. Cuộc gọi đến -setValue:forKey: đầu tiên sẽ hiển thị -setFoo:. Nếu không tìm thấy, nó sẽ tìm biến cá thể foo và đặt nó trực tiếp.

Lưu ý rằng nếu bạn thay đổi các trường hợp biến fido để _fido, tập sẽ làm việc, nhưng valueForKey sẽ trở về 0 vì nó gọi phương thức tổng hợp (kể từ khi tôi đang trên 64 bit, các @synthesize tổng hợp một biến fido dụ Nhầm lẫn, tôi biết.).

Nếu bạn thay đổi tên của ivar thành bar và sau đó sử dụng @synthesize foo=bar;, mã sẽ thất bại khi chạy.

Bạn sẽ thấy:

2009-10-01 08:59:58.081 dfkjdfkjfjkfd[24099:903] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<AppController 0x20000e700> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key fido.' 
*** Call stack at first throw: 
(
    0 CoreFoundation      0x00007fff85b055a4 __exceptionPreprocess + 180 
    1 libobjc.A.dylib      0x00007fff85c5a0f3 objc_exception_throw + 45 
    2 CoreFoundation      0x00007fff85b5caf9 -[NSException raise] + 9 
    3 Foundation       0x00007fff814e14f5 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 434 
(
    0 CoreFoundation      0x00007fff85b055a4 __exceptionPreprocess + 180 
    1 libobjc.A.dylib      0x00007fff85c5a0f3 objc_exception_throw + 45 
    2 CoreFoundation      0x00007fff85b5caf9 -[NSException raise] + 9 
    3 Foundation       0x00007fff814e14f5 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 434 
    4 dfkjdfkjfjkfd      0x0000000100000d96 -[AppController init] + 130 
+9

Bạn cũng có thể sử dụng + (BOOL) accessInstanceVariablesDirectly {return NO; } để loại bỏ hành vi KVC này – sbooth

+0

Điểm tốt và thói quen tốt để tham gia. Cảm ơn! – bbum

+0

Câu trả lời hay, cảm ơn. Lý do tôi hỏi câu hỏi này là một trong những điểm chính của chương này là KVC sử dụng những người định cư và getters. Tôi cho rằng đó là cách duy nhất họ làm việc. Phong cách init là phong cách anh ta sử dụng trong cuốn sách. Anh ta nói rằng các lớp anh ta lớp con không bao giờ trở lại số không, vì vậy anh ta bỏ qua việc kiểm tra sự đơn giản. –

1

Có readonly tài sản có nghĩa là trình biên dịch sẽ không tạo bạn setter cho tài sản đó. Nó vẫn hợp pháp để viết cho nó thông qua KVO/KVC.

+1

Đó không phải là những gì đang xảy ra ở đây. – bbum

1

Chỉ thị của trình biên dịch @property@synthesize chỉ là cách viết tắt để tạo phương thức nhận và đặt biến được đề cập.

Phương thức setter được tạo có tên là setFido: và phương thức getter chỉ có tên fido.

Khi bạn chỉ định chỉ đọc, tôi tin rằng chỉ đơn giản là yêu cầu trình biên dịch không tạo phương thức setter, nhưng chỉ có trình thu thập dữ liệu. Nó không đặt bất kỳ loại rào cản nào trong cách thiết lập biến bằng các phương tiện khác.

(Hope Tôi đã có tất cả những gì đúng Chúc may mắn.!)

+0

Nhiều hoặc ít chính xác.Xem câu trả lời của tôi để biết chi tiết cụ thể. – bbum

Các vấn đề liên quan