2012-09-03 53 views
10

我想一个属性在类扩展添加的UITableView:定义iOS中类扩展属性

@interface UITableViewController() 

@property NSString *entityString; 

@end 

于是我进口的扩展名,然后我用entityString财产的UITableViewController的子类:

@implementation CustomerTableViewController 

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

Apple documentation说:

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

但是,当我尝试前执行它我得到这个错误:

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

我做错了什么?也许属性不能被子类访问?

回答

5

类扩展用于声明附加的接口 - 的方法和属性 - 其执行合同将类的初级@implementaiton内满足。

这正是您无法添加存储的原因 - 通过类扩展添加ivars。类扩展是一个接口,不多也不少。 @synthesize是为@property声明创建存储,但的@synthesize只能出现在该类的@implementation中(无论是显式还是作为编译器的默认行为)。

由于您无法重新编译框架类,因此无法将ivars添加到它。

@prashat的答案是将存储添加到现有类的一种方法。但是,走这条路通常是不可取的;挂在框架类的状态是一个糟糕的设计的标志,并且会使您的应用程序在一段时间内难以维护。

好得多重新审视你的设计,明白你为什么目前需要连接状态的对象不能直接包含它,重构这一要求了。

+0

无法将ivars添加到类扩展中,或者这取决于所使用的编译器? – tiguero

+3

您可以在类扩展中声明ivars和属性,但是除非在编译该类的@implementation之前编译器才能看到该扩展,否则不会创建这样的存储。 – bbum

+0

感谢澄清 - 我没有注意到alazaro实际上是使用类扩展来实现框架类 – tiguero

4

的文档状态:

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

当您使用@property,它大致相当于声明访问方法。所以这意味着如果你也是类的“主”@implementation块的作者,那么你只能做这样的事情,而你使用的是UITableViewController。

您的唯一选择是分类,它不能添加实例变量。

The docs link,并注意页面的最后一行:

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

我认为这不是我的情况,我没有使用ivar + accessors。但是,编译器不会抱怨我的代码。错误在运行时。 – alazaro

+3

@ @ property **是** ivar加accessors。 –

+0

是的,我知道,但编译器会为您完成这项工作。我认为它可能会在主类中添加访问器,无论它是否属于我。 – alazaro

12

尝试使用与关联引用,而不是一个类别。它更清洁,并将在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 

//例使用

#import "UIButton+Property.h" 


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

联合引用如何比类扩展更干净? – vikingosegundo

+4

它们更干净是因为它们的工作原因(类扩展并不是因为当类的@implementation被编译时扩展不存在),但是这并不能使它们变得干净。将状态添加到现有的框架类是一个糟糕的设计和高度脆弱的迹象。虽然prashant的答案有效,但这样做通常表明您应该重新考虑您的架构。 – bbum

+0

没有必要在该代码中使用'@ dynamic',顺便说一句。 – bbum