Objective c 如何从其超类的实例分配NSObject子类实例?

Objective c 如何从其超类的实例分配NSObject子类实例?,objective-c,cocoa,inheritance,subclass,nsobject,Objective C,Cocoa,Inheritance,Subclass,Nsobject,给定一个类结构,例如 @interface SuperClassView : NSView @end @interface SubClassedView : SuperClassView @property int aProp; @end 如何从超类视图的实例实例化子类视图 假设一个方法返回超类SuperView的实例 但我想得到SubClassedView子类的一个实例?这是不可能简单地投下它 SubClassedView *subC

给定一个类结构,例如

@interface SuperClassView : NSView                              @end
@interface SubClassedView : SuperClassView @property int aProp; @end
如何从超类视图的实例实例化子类视图

假设一个方法返回超类SuperView的实例

但我想得到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];
或者在运行时将子类的附加属性方法setAProp:和aProp添加到超类实例中,并将其向上强制转换

SubClassedView *subClsInstance = (SubClassedView*)[ViewFactory makeSuperClassView];
[subClsInstance addSwizzleMethod:@selector(setAProp:) viaSomeMagic:....];
[subClsInstance addSwizzleMethod:@selector(aProp)     viaSomeMagic:....];
希望这是一个简单的运行时技巧,我只是不知道。。。这并不是一个可悲的迹象,我正试图通过一些令人尴尬的反模式欺骗ObjC实现多重继承。不管怎样,你有什么想法

编辑:Pending@BryanChen将其评论作为答案发布,这可以通过其建议的运行时函数轻松实现,或者作为NSObjectála上的一个类别


你想做的是非常不习惯的。。。感觉就像你在尝试做一些基于原型的OOP。有几个要点:

不要做恶作剧。你不能切换到一个实例上,而是切换到类定义上,因此如果你这样做了,你就不会将子类方法添加到超类的实例上,而是将它们添加到超类的所有实例上。 是的,如果您想这样做,您只需要将您想要的属性从super复制到子类的新实例中。 您可以在超类中有一个返回子类的工厂方法,并在其中封装所有复制,因此,[SuperClassView MakeSublassView]返回SubassedView*。这实际上是比较常见的,并且是实现了多少类集群,尽管它们返回符合超类实现的私有子类 可能是也可能不是您正在寻找的运行时技巧。它会在运行时更改实例的类。但是,它确实有许多限制,例如新类不能有额外的IVAR。您可以查看更多详细信息

我认为更好的方法是,与其使用[ViewFactory makeSuperClassView]创建视图,不如使用[SuperClassView alloc]initWithSomething]创建视图。然后你可以做[[subclass-view-alloc]initwith-something]

或者如果你真的想使用ViewFactory,那么就让它成为[ViewFactory makeViewOfClass:

对象\u setClass不是你要找的droid

是的,它将更改实例的类。但是,它不会改变它的大小。因此,如果您的子类视图声明了未在超级类视图上声明的额外属性或实例变量,那么您尝试在这个弗兰肯斯坦实例上访问这些属性或实例变量,充其量会导致缓冲区溢出,可能会导致数据损坏,最坏的情况是导致应用程序崩溃

听起来你真的只是想在工厂里使用self方法:

+ (instancetype)makeView {
    return [[self alloc] init];
}
然后,如果调用[SuperClassView makeView],将返回一个SuperClassView实例。如果调用[SubClassView makeView],将返回SubClassView的实例

但是,您会说,如果视图是子类视图,如何自定义其属性

就像处理其他任何事情一样:重写子类视图上的方法:


你想干什么?更改实例的类?你能用一句话说出你想达到的目的吗?你想复制一个原型吗?@BryanChen是的,这正是我想要的。。。将其作为答案发布。。。这里有一个例子。。。SuperClassView*x=SuperClassView.new;对象_setClassx,[子类视图类];子类视图*z=x;z、 aProp=2;耶!只需在超类中创建子类并返回它。它确实需要一个小舞蹈与转发指针,等等,但它可以做到。请记住,当子类init方法调用super方法时,super init方法集的所有项都将在您的子类中设置。这是唯一的代码。@BryanChen:你可以在一个类的单个实例上使用方法吗?你会怎么做呢?创建一个私有子类,切换私有子类,将实例的类设置为私有子类。这就是允许您在特定实例上动态重写指定方法的方式。它是子类化的超级方便的替代方法,或者如果您希望根据运行时条件有几个稍微不同的实现..问题是NSObject没有initWithSomething:method。您应该在SuperClassView中定义它。您不应该使用object_setClass。查看我的答案了解原因。Dave这都是真的,但要求工厂方法是视图类st的函数
结构。。。我的意思是暗示一些不太知情的外部工厂-对于超类视图的子类结构可能一无所知。此外,我认为你对大小的观察也是真实的,但在我给出的@BryanChen的例子中。。。我可以在重新分类的超级对象上设置并获得新的或应该说继承的属性。这仅仅是一个幸运的例子,还是运行时以某种方式补偿了大小差异?@alexgray这完全是幸运的。object_setClass在内存插槽上执行OSAtomicCompareAndSwap。我认为您可以通过使用ObjC的相关对象存储API和绕过自动合成来解决ivar/属性问题。不漂亮,但这可能是一个可行的解决办法。
@implementation NSObject (SettingClass)
- (void)setClass:(Class)kls { if (kls) object_setClass(self, kls); } @end
+ (instancetype)makeView {
    return [[self alloc] init];
}
@implementation SubClassView

+ (instancetype)makeView {
    SubClassView *v = [super makeView];
    v.answer = 42;
    return v;
}

@end