2012-09-03 16 views
10

Tôi muốn thêm một tài sản để UITableView trong một Extension Class:Xác định một tài sản trong công tác khuyến lớp iOS

@interface UITableViewController() 

@property NSString *entityString; 

@end 

Sau đó, tôi nhập phần mở rộng và sau đó tôi sử dụng tài sản entityString trong một lớp con của UITableViewController:

@implementation CustomerTableViewController 

- (void)viewDidLoad { 
    self.entityString = @"Customer"; 
    ... 
    [super viewDidLoad]; 
} 
... 

Apple documentation nói:

the compiler will automatically synthesize the relevant accessor methods (...) inside the primary class implementation.

Nhưng khi tôi cố gắng cũ ecute it Tôi nhận được lỗi này:

-[CustomerTableViewController setEntityString:]: unrecognized selector sent to instance 0x737b670

Tôi đang làm gì sai? có thể thuộc tính không thể được truy cập bởi các lớp con?

Trả lời

5

Một lớp mở rộng được sử dụng để khai báo thêm giao diện - phương pháp và bất động sản - có hợp đồng thực hiện sẽ được đáp ứng trong vòng chính @implementaiton của lớp.

Đó chính xác là lý do tại sao bạn không thể thêm bộ nhớ - thêm ivars - thông qua tiện ích mở rộng lớp học. Một phần mở rộng lớp là một giao diện, không còn nữa, không kém. @synthesize là nội dung tạo bộ nhớ cho các khai báo @property, nhưng @synthesize của @property chỉ có thể xuất hiện trong lớp @implementation của lớp (cho dù rõ ràng hoặc là hành vi mặc định của trình biên dịch).

Vì bạn không thể biên dịch lại lớp khung công tác, bạn không thể thêm ivars vào nó.

Câu trả lời của @ prashat là một cách để thêm bộ nhớ vào lớp hiện có. Tuy nhiên, đi tuyến đường đó thường không mong muốn; treo nhà nước của các lớp khung willy-nilly là một dấu hiệu của thiết kế kém và sẽ làm cho ứng dụng của bạn đáng kể khó khăn hơn để duy trì theo thời gian.

Tốt hơn hết là truy cập lại thiết kế của bạn, hiểu lý do tại sao bạn hiện yêu cầu đính kèm trạng thái vào đối tượng không thể chứa trực tiếp và tái cấu trúc yêu cầu đó.

+0

Không thể thêm ivars vào phần mở rộng của lớp học hoặc điều này phụ thuộc vào trình biên dịch được sử dụng? – tiguero

+3

Bạn có thể khai báo ivars và các thuộc tính trong các phần mở rộng của lớp, nhưng lưu trữ cho nó sẽ không được tạo trừ khi phần mở rộng được trình biên dịch nhìn thấy trước khi biên dịch @implementation của lớp đó. – bbum

+0

Cảm ơn bạn đã làm rõ - tôi đã không nhận thấy alazaro đang sử dụng một lớp mở rộng cho một lớp khung thực sự – tiguero

4

Các tài liệu nhà nước:

Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main @implementation block for the corresponding class.

Khi bạn sử dụng @property, nó tương đương với tuyên bố phương pháp accessor. Vì vậy, điều này có nghĩa là bạn chỉ có thể làm một điều như vậy nếu bạn cũng là tác giả của khối "chính" @implementation của lớp, mà với UITableViewController, bạn thì không.

Tùy chọn duy nhất của bạn ở đây là Danh mục, không thể thêm biến mẫu.

The docs link, và lưu ý dòng cuối cùng của trang đó:

The implementation of the setValue: method must appear within the main @implementation block for the class (you cannot implement it in a category). If this is not the case, the compiler emits a warning that it cannot find a method definition for setValue:.

+0

Tôi nghĩ rằng đó không phải là trường hợp của tôi, tôi không sử dụng ivar + accessors. Tuy nhiên, trình biên dịch không phàn nàn về mã của tôi. Lỗi là trong thời gian chạy. – alazaro

+3

thuộc tính '@' ** là một ivar cộng với người truy cập. –

+0

Vâng, tôi biết, nhưng trình biên dịch thực hiện công việc cho bạn. Tôi nghĩ rằng nó có thể thêm accessors trong lớp chính quá, không có vấn đề nếu nó thuộc về tôi hay không. – alazaro

12

Hãy thử sử dụng một loại với Associative Tài liệu tham khảo để thay thế. Nó sạch sẽ hơn và sẽ hoạt động trên tất cả các phiên bản của UIButton.

UIButton+Property.h 

#import <Foundation/Foundation.h> 

@interface UIButton(Property) 

@property (nonatomic, retain) NSObject *property; 

@end 


UIButton+Property.m 

#import "UIButton+Property.h" 
#import <objc/runtime.h> 

@implementation UIButton(Property) 

static char UIB_PROPERTY_KEY; 

@dynamic property; 

-(void)setProperty:(NSObject *)property 
{ 
    objc_setAssociatedObject(self, &UIB_PROPERTY_KEY, property, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 

-(NSObject*)property 
{ 
    return (NSObject*)objc_getAssociatedObject(self, &UIB_PROPERTY_KEY); 
} 

@end 

// Ví dụ sử dụng

#import "UIButton+Property.h" 


UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
button1.property = @"HELLO"; 
NSLog(@"Property %@", button1.property); 
button1.property = nil; 
NSLog(@"Property %@", button1.property); 
+0

Tham chiếu liên kết sạch hơn tiện ích mở rộng lớp học như thế nào? – vikingosegundo

+4

Chúng sạch hơn vì chúng hoạt động (phần mở rộng của lớp không phải vì phần mở rộng không có sẵn khi @implementation cho lớp được biên dịch), nhưng điều đó không làm cho chúng sạch sẽ. Việc thêm trạng thái vào các lớp khung công tác hiện có là một dấu hiệu của thiết kế xấu và sự mong manh cao. Trong khi câu trả lời của prashant hoạt động, làm như vậy thường là một dấu hiệu cho thấy bạn nên xem xét lại kiến ​​trúc của bạn. – bbum

+0

Không cần sử dụng '@ dynamic' trong mã đó, btw. – bbum

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