使用类扩展将ivar和属性添加到类

问题描述:

我试图将实例变量和属性添加到现有类。我想要这样做来扩展开源库的基类,而不修改源代码(为了更容易的代码管理)。使用类扩展将ivar和属性添加到类

documentation

不同于常规类,一类扩展可以添加自己的 属性和实例变量的类。如果您在类扩展中声明 属性,编译器将自动合成 合成主类实现内的相关访问器方法以及实例 变量。

我试图在测试应用程序中做到这一点。我有一个空类ClassA

ClassA.h

#import <Foundation/Foundation.h> 
@interface ClassA : NSObject 
@end 

ClassA.m

#import "ClassA.h"  
@implementation ClassA 
@end 


然后,我添加的扩展:

ClassA的+ Ext.h

#import "ClassA.h" 
@interface ClassA() 

@property (nonatomic) NSString *name;  // <-- this is my new property 

@end 


最后,在我的AppDelegate我只是一个初始化和ClassA尝试设置,然后再登录该name

#import "AppDelegate.h" 
#import "ClassA.h" 
#import "ClassA+Ext.h" 

@implementation AppDelegate 

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{ 
    ClassA *a = [[ClassA alloc] init]; 
    a.name = @"test"; 
    NSLog(@"Name: %@", a.name); 
} 

@end 

这编译和运行,但我得到了控制台上的错误:

2013-05-10 00:58:08.598 Test[53161:303] -[ClassA setName:]: unrecognized selector 
sent to instance 0x108a1a630 
2013-05-10 00:58:08.600 Test[53161:303] -[ClassA setName:]: unrecognized selector 
sent to instance 0x108a1a630 

名称没有登录。如果我设置了一个断点并检查ClassA实例,它没有name伊娃。我究竟做错了什么?这实际上不可能做到吗?

+0

这个错误与一个ivar在那里或没有没有关系。问题在于该属性的setter方法无法识别。注释掉'a.name = ...'这一行并查看在日志语句中是否存在与“getter”有关的问题。 – rmaddy 2013-05-09 23:04:35

+0

如果我这样做,我得到的错误为getter [[ClassA name]] – DrummerB 2013-05-09 23:07:44

+1

正如删除的答案所述,添加到类扩展中的属性对于类是私有的。这就是为什么另一个类无法看到private属性'name'的setter或getter。 – rmaddy 2013-05-09 23:11:12

你的理解是不正确的。您通过类​​扩展添加了一个属性。这个属性应该只能在你的类中使用。它不应该被用作你的类的一个真正的“属性”,你可以通过外部实例化来改变它。把它看作一个伪私有实例变量。

我相信你想要做的就是简单地继承你的A类什么

提出的另一种可行的解决方案是:

“你可以写一个类别,它包装成 - [setAssociatedObject:forKey:]”当使用objc_setAssociatedObject - > by @Artur

+0

我不能继承子类,因为这是库中的基类和库中的其他类的子类。我必须改变很多才能在层次结构中插入额外的类,这使得代码非常繁琐。 – DrummerB 2013-05-09 23:15:06

+0

然后对需要变量的类进行子类化,不必在根目录下执行它。 – 2013-05-09 23:16:23

+0

不幸的是他们都需要它。这就像图书馆的创建者忘了将通常的'userData'或'userInfo' ivar添加到API中。 – DrummerB 2013-05-09 23:18:47

我认为类扩展应该放在class.m文件中,通常放在类的@implementation之上。