在iOS类扩展中定义属性

ala*_*aro 12 objective-c automatic-ref-counting ios5.1

我想在类扩展中向UITableView添加一个属性:

@interface UITableViewController ()

@property NSString *entityString;

@end
Run Code Online (Sandbox Code Playgroud)

然后我导入扩展,然后在UITableViewController的子类中使用entityString属性:

@implementation CustomerTableViewController

- (void)viewDidLoad {
    self.entityString = @"Customer";
    ...
    [super viewDidLoad];
}
...
Run Code Online (Sandbox Code Playgroud)

Apple文档说:

编译器将自动合成主类实现中的相关访问器方法(...).

但是当我尝试执行它时,我收到此错误:

- [CustomerTableViewController setEntityString:]:无法识别的选择器发送到实例0x737b670

我究竟做错了什么?也许子类无法访问该属性?

pra*_*ant 14

请尝试使用具有关联引用的类别.它更干净,适用于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
Run Code Online (Sandbox Code Playgroud)

//示例用法

#import "UIButton+Property.h"


UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button1.property = @"HELLO";
NSLog(@"Property %@", button1.property);
button1.property = nil;
NSLog(@"Property %@", button1.property);
Run Code Online (Sandbox Code Playgroud)

  • 它们更干净,因为它们起作用(类扩展不是因为在编译类的@implementation时扩展名不存在),但这并不能使它们干净.将状态添加到现有框架类是设计糟糕和高度脆弱的标志.虽然prashant的答案有效,但这样做通常表明您应该重新考虑您的架构. (4认同)

bbu*_*bum 6

类扩展来声明额外的接口-方法和属性-其实现合同将类的主要内得到满足@implementaiton.

这正是您无法通过类扩展添加存储 - 添加ivars的原因.类扩展是一个接口,不多也不少. @synthesize是什么创造了存储@property的声明,而是@synthesize一个@property只能出现在@implementation类的(无论是明示或因为编译器的默认行为).

由于无法重新编译框架类,因此无法向其添加ivars.

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

更好地重新审视您的设计,理解为什么您当前需要将状态附加到不能直接包含它的对象,并重构该要求.

  • 您可以在类扩展中声明ivars和属性,但除非在编译类的@implementation之前编译器看到扩展,否则不会创建此类存储. (4认同)

Chr*_*hey 5

文档说明:

类扩展类似于匿名类,除了它们声明的方法必须在相应类的主@implementation块中实现.

使用时@property,它大致相当于声明访问器方法.所以这意味着如果你也是@implementation类的"主" 块的作者,你只能做这样的事情,用UITableViewController,你不是.

这里唯一的选择是类别,它不能添加实例变量.

文档链接,并注意该页面的最后一行:

setValue:方法的实现必须出现在类的主@implementation块中(您无法在类别中实现它).如果不是这种情况,编译器会发出警告,指出它无法找到setValue的方法定义:.

  • `@ property`**是**ivar加访问者. (4认同)