给定一个类结构,如......
@interface SuperClassView : NSView @end
@interface SubClassedView : SuperClassView @property int aProp; @end
如何从SubClassedView
的实例实例化SuperClassView
?
假设一个方法返回超类SuperView
的实例....
SuperClassView *superInstance = [ViewFactory makeSuperClassView];
但我希望获取 子类 SubClassedView
的实例?不可能简单地“施放”它......
SubClassedView *subClsInstance = (SubClassedView*)[ViewFactory makeSuperClassView];
并且没有像
这样的NSObject
方法的内置(或容易想象的实现)
self = [super initWithInstance:[superInstance copy]];`
是将超类实例的所需属性复制到新实例化的子类对象的唯一方法,例如......
SubClassedView *subClsInstance = SubClassedView.new;
for (NSString* someKey in @["frame",@"color",@"someOtherProperty])
[subClsInstance setValue:[superInstance valueForKey:someKey] forKey:someKey];
或者将(“em> swizzle at runtime ”)子类'“其他属性方法”(在本例中为setAProp:
和aProp
)添加到超类实例(并且还将其强制转换)向上)...
SubClassedView *subClsInstance = (SubClassedView*)[ViewFactory makeSuperClassView];
[subClsInstance addSwizzleMethod:@selector(setAProp:) viaSomeMagic:....];
[subClsInstance addSwizzleMethod:@selector(aProp) viaSomeMagic:....];
希望这是一个简单的运行时技巧,我根本就不知道......不是一个悲伤的迹象,我不幸地试图通过一些<{1}}欺骗ObjC
进行多重继承em>令人尴尬的反模式。无论哪种方式,想法?
编辑:等待@BryanChen发表评论作为答案,这可以通过他建议的运行时功能轻松实现,或者作为NSObject
上的类别实现...
@implementation NSObject (SettingClass)
- (void)setClass:(Class)kls { if (kls) object_setClass(self, kls); } @end
答案 0 :(得分:6)
你要做的事情非常非惯用......感觉你正在尝试做一些像基于原型的OOP。几点快点:
-[SuperClassView makeSubclassView]
返回SubClassedView *
。这实际上相对常见,是如何实现了许多类集群(尽管它们返回符合超类实现的私有子类)答案 1 :(得分:1)
object_setClass
不是您正在寻找的机器人。
是的,它会更改实例的类。但是,它不会更改它的大小。因此,如果您的SubClassView
声明了未在SuperClassView
上声明的额外属性或实例变量,那么您在此frankenstein实例上访问它们的尝试将导致(最多)缓冲区溢出,(可能)损坏的数据,(最糟糕的是)你的应用程序崩溃。
听起来你真的只想在工厂方法中使用self
:
+ (instancetype)makeView {
return [[self alloc] init];
}
然后,如果您致电[SuperClassView makeView]
,则会返回SuperClassView
的实例。如果您致电[SubClassView makeView]
,则会返回SubClassView
的实例。
“但是,”你说,“如果它是SubClassView
,我如何自定义视图的属性?”
就像你对其他任何东西一样:你覆盖SubClassView
上的方法:
@implementation SubClassView
+ (instancetype)makeView {
SubClassView *v = [super makeView];
v.answer = 42;
return v;
}
@end
答案 2 :(得分:0)
object_setClass
可能是也可能不是您正在寻找的“运行时技巧”。它确实是一个在运行时更改实例类的混合体。然而,它确实有许多约束,例如新类不能有额外的ivars。您可以查看this question了解详情。
我认为更好的方法是,不要使用[ViewFactory makeSuperClassView]
制作视图,而是将其设为[[SuperClassView alloc] initWithSomething]
。然后你可以[[SubClassView alloc] initWithSomething]
或者如果您真的想使用ViewFactory
,请将其设为[ViewFactory makeViewOfClass:]