使用超类'实例初始化对象

时间:2022-06-20 21:28:45

Let's say a have a Superclass and an instance of this class superclassObject.
I create a derived ClassA.

假设有一个Superclass和这个类superclassObject的一个实例。我创建了一个派生的ClassA。

How can I instantiate (initialize) an object classAObject of the derived class in a such way, that all the inherited fields are equal to ones of superclassObject?

如何以这种方式实例化(初始化)派生类的对象classAObject,所有继承的字段都等于superclassObject的字段?

Of course I can cycle through all the fields and manually copy the values like classAObject.property = [superclassObject.property copy]. But the problem with this approach is that I may not know (or have access to) all the ivars/properties of the superclass. Is there an easier (and more general) way?

当然,我可以遍历所有字段并手动复制像classAObject.property = [superclassObject.property copy]这样的值。但是这种方法的问题在于我可能不知道(或无法访问)超类的所有ivars /属性。有更简单(更通用)的方式吗?

It seems that I'm missing something really basic...

似乎我错过了一些非常基本的东西......

I'm trying to do this because I get an already initialized UIView (with frame, background color, autoresizing mask, etc.) and I want to replace it with my custom view with same parameters.

我正在尝试这样做,因为我得到了一个已经初始化的UIView(带框架,背景颜色,自动调整遮罩等),我想用我的自定义视图替换它具有相同的参数。

Update 1

I've found this question, and the answer there says that it

我发现了这个问题,那里的答案就是这么说的

generally isn't supported in any OO language

通常不支持任何OO语言

however

然而

In Objective-C it is possible in some cases

在Objective-C中,在某些情况下是可能的

Ok, if it's not supported, what should I do? If it is supported, how can I achieve this?

好的,如果它不受支持,我该怎么办?如果支持,我该如何实现?

Update 2

It seems I've found a solution to my particular case of this general problem, which I'll test and report that tomorrow.

我似乎找到了解决这个一般问题的特殊情况的解决方案,我将在明天测试并报告。

However, this lead me to another idea: What if I use a NSCoder to encode the superclassObject (if it implements <NSCoding> of course), and then call [[ClassA alloc] initWithCoder:coder] with a coder that knows data from the encoded superclassObject? Disclaimer: Well, I'm not that familiar with coding concepts (or even not at all), so may be the last sentence is nonsense.

然而,这引出了另一个想法:如果我使用NSCoder对超类对象进行编码(如果它当然实现了 ),然后使用知道数据的编码器调用[[ClassA alloc] initWithCoder:coder],该怎么办?编码的超类对象?免责声明:嗯,我不熟悉编码概念(甚至根本不熟悉),所以可能最后一句话是胡说八道。

3 个解决方案

#1


2  

If I understand the question correctly, you have an established view which you want to change to a different class. Presumably for the reason of changing it's functionality.

如果我正确理解了这个问题,那么您有一个已建立的视图,您希望将其更改为其他类。大概是因为改变了它的功能。

Cloning class properties between classes and swapping instances is the only way to do this sort of thing in languages like Java.

克隆类和交换实例之间的类属性是在Java等语言中执行此类操作的唯一方法。

But ... in Objective C we have Categories. If all you are trying to do is change behaviour then perhaps a solution might be to create a Category for UIView that performs the additional or overridden functionality you require.

但是......在目标C中我们有类别。如果您要做的只是更改行为,那么可能解决方案可能是为UIView创建一个类别,以执行您需要的附加或重写功能。

Second thought is to look into why you are not creating the correct class in the first place and therefore avoid this whole problem.

第二个想法是调查为什么你不是首先创建正确的类,因此避免这整个问题。

#2


0  

IFF your subclass adds only methods and not any storage (i.e., ivars) to the superclass, then you can use a semi-black-magic technique* called "isa-swizzling". Rob Napier mentions it, and links to a blog post that explains it all.

IFF您的子类只向超类添加方法而不是任何存储(即ivars),然后您可以使用称为“isa-swizzling”的半黑魔法技术*。 Rob Napier提到了它,并链接到一篇解释这一切的博客文章。

Each Objective-C instance has a chunk of storage in memory for its instance variables, but the implementation of the methods is all kept in another place, in the storage for the class object. The runtime uses an instance's isa pointer to get at the class object.

每个Objective-C实例在内存中都有一块存储空间用于其实例变量,但是这些方法的实现都保存在另一个地方,即类对象的存储空间中。运行时使用实例的isa指针来获取类对象。

It is therefore possible, as demonstrated in the linked blog post, to transform an instance of one class into another provided they have exactly the same fields. As Rob warns, you cannot add ivars, only change the methods.

因此,如链接博客文章所示,可以将一个类的实例转换为另一个类,只要它们具有完全相同的字段即可。正如Rob警告的那样,你不能添加ivars,只能改变方法。

Casting (MyDerivedClass *)instanceOfSuperclass only has an effect at compile-time. All it does is make the compiler happy when it is comparing types: it doesn't affect the runtime lookup of methods, so your instanceOfSuperclass will still act like a Superclass.

Casting(MyDerivedClass *)instanceOfSuperclass仅在编译时有效。它所做的就是让编译器在比较类型时感到高兴:它不会影响方法的运行时查找,因此你的instanceOfSuperclass仍然会像超类一样运行。

EDIT: Just as a final thought, since we're already talking about dangerous techniques, perhaps you could create a helper class that would hold the ivars that you want to add to the subclass. Whew, now I've really gone mad!

编辑:最后的想法,因为我们已经在谈论危险的技术,也许你可以创建一个帮助类来保存你想要添加到子类的ivars。哇,现在我真的疯了!

I have never done this myself; I am only reporting a technique that may be useful to you. Please pay attention to all the warnings you see when this is discussed.

我自己从未这样做过;我只报告一种可能对您有用的技术。请注意讨论时看到的所有警告。


*Used for KVO, interestingly.

*有趣的是用于KVO。

#3


0  

It is definitely possible using ObjC runtime, but it will be a bit hairy... This is a link to Apple's docs: Objective-C Runtime and an example of its usage: Objective-C Runtime Programming.

绝对有可能使用ObjC运行时,但它会有点毛茸茸...这是Apple的文档链接:Objective-C运行时及其用法示例:Objective-C运行时编程。

You would iterate over all properties, check their attributes to find out those you can set (i.e. omitting readonly properties), get their getter method on the superclass, read value and set using setter method on the subclass.

您将迭代所有属性,检查它们的属性以找出您可以设置的属性(即省略只读属性),在超类上获取它们的getter方法,读取值并使用子类上的setter方法进行设置。

In the specific case of UIView this may work - you will tweak until it works. Generally it may be difficult: what about ivars that are not exposed as properties? Do you want to copy them all? Then you would need to check properties defined in the class and all protocols the class implements. And I'm not sure if won't be necessary to iterate over all the superclasses of your superclass to get all defined properties and ivars.

在UIView的特定情况下,这可能有用 - 你会调整直到它工作。通常情况下可能很困难:那些没有作为属性暴露的ivars怎么办?你想复制它们吗?然后,您需要检查类中定义的属性以及该类实现的所有协议。而且我不确定是否有必要迭代你的超类的所有超类以获得所有已定义的属性和ivars。

But, still, it is possible.

但是,仍然有可能。

UPDATE

UPDATE

If you would copy instance variables then probably you would be probably set without even touching properties - I assume that all state is saved in ivars eventually. So in this case also no need to touch protocol defined properties.

如果你要复制实例变量那么可能你甚至可能没有触及属性就设置了 - 我假设所有状态最终都保存在ivars中。所以在这种情况下也不需要触摸协议定义的属性。

But the other solution that may work well enough is to just stick to the public interface (well actually part of it: just what appears to be data and not functionality): read data through properties of the superclass and set using properties of the derived class, again assuming that the classes will do the right thing with the data. In this case the protocol properties are equally important because the are also part of the public interface and their implementation can save state into instance variables.

但另一个可能运行良好的解决方案就是坚持公共接口(实际上是它的一部分:看似数据而不是功能):通过超类的属性读取数据并使用派生类的属性进行设置,再次假设类将对数据做正确的事情。在这种情况下,协议属性同样重要,因为它们也是公共接口的一部分,它们的实现可以将状态保存到实例变量中。

Again, I wouldn't try this approach as a general solution to copy any class but in a case of duplicating the data of one specific class that might work well enough and you can easily and thorough test your case.

同样,我不会尝试这种方法作为复制任何类的一般解决方案,但在复制一个特定类的数据的情况下可能会运行得很好,并且您可以轻松彻底地测试您的案例。

#1


2  

If I understand the question correctly, you have an established view which you want to change to a different class. Presumably for the reason of changing it's functionality.

如果我正确理解了这个问题,那么您有一个已建立的视图,您希望将其更改为其他类。大概是因为改变了它的功能。

Cloning class properties between classes and swapping instances is the only way to do this sort of thing in languages like Java.

克隆类和交换实例之间的类属性是在Java等语言中执行此类操作的唯一方法。

But ... in Objective C we have Categories. If all you are trying to do is change behaviour then perhaps a solution might be to create a Category for UIView that performs the additional or overridden functionality you require.

但是......在目标C中我们有类别。如果您要做的只是更改行为,那么可能解决方案可能是为UIView创建一个类别,以执行您需要的附加或重写功能。

Second thought is to look into why you are not creating the correct class in the first place and therefore avoid this whole problem.

第二个想法是调查为什么你不是首先创建正确的类,因此避免这整个问题。

#2


0  

IFF your subclass adds only methods and not any storage (i.e., ivars) to the superclass, then you can use a semi-black-magic technique* called "isa-swizzling". Rob Napier mentions it, and links to a blog post that explains it all.

IFF您的子类只向超类添加方法而不是任何存储(即ivars),然后您可以使用称为“isa-swizzling”的半黑魔法技术*。 Rob Napier提到了它,并链接到一篇解释这一切的博客文章。

Each Objective-C instance has a chunk of storage in memory for its instance variables, but the implementation of the methods is all kept in another place, in the storage for the class object. The runtime uses an instance's isa pointer to get at the class object.

每个Objective-C实例在内存中都有一块存储空间用于其实例变量,但是这些方法的实现都保存在另一个地方,即类对象的存储空间中。运行时使用实例的isa指针来获取类对象。

It is therefore possible, as demonstrated in the linked blog post, to transform an instance of one class into another provided they have exactly the same fields. As Rob warns, you cannot add ivars, only change the methods.

因此,如链接博客文章所示,可以将一个类的实例转换为另一个类,只要它们具有完全相同的字段即可。正如Rob警告的那样,你不能添加ivars,只能改变方法。

Casting (MyDerivedClass *)instanceOfSuperclass only has an effect at compile-time. All it does is make the compiler happy when it is comparing types: it doesn't affect the runtime lookup of methods, so your instanceOfSuperclass will still act like a Superclass.

Casting(MyDerivedClass *)instanceOfSuperclass仅在编译时有效。它所做的就是让编译器在比较类型时感到高兴:它不会影响方法的运行时查找,因此你的instanceOfSuperclass仍然会像超类一样运行。

EDIT: Just as a final thought, since we're already talking about dangerous techniques, perhaps you could create a helper class that would hold the ivars that you want to add to the subclass. Whew, now I've really gone mad!

编辑:最后的想法,因为我们已经在谈论危险的技术,也许你可以创建一个帮助类来保存你想要添加到子类的ivars。哇,现在我真的疯了!

I have never done this myself; I am only reporting a technique that may be useful to you. Please pay attention to all the warnings you see when this is discussed.

我自己从未这样做过;我只报告一种可能对您有用的技术。请注意讨论时看到的所有警告。


*Used for KVO, interestingly.

*有趣的是用于KVO。

#3


0  

It is definitely possible using ObjC runtime, but it will be a bit hairy... This is a link to Apple's docs: Objective-C Runtime and an example of its usage: Objective-C Runtime Programming.

绝对有可能使用ObjC运行时,但它会有点毛茸茸...这是Apple的文档链接:Objective-C运行时及其用法示例:Objective-C运行时编程。

You would iterate over all properties, check their attributes to find out those you can set (i.e. omitting readonly properties), get their getter method on the superclass, read value and set using setter method on the subclass.

您将迭代所有属性,检查它们的属性以找出您可以设置的属性(即省略只读属性),在超类上获取它们的getter方法,读取值并使用子类上的setter方法进行设置。

In the specific case of UIView this may work - you will tweak until it works. Generally it may be difficult: what about ivars that are not exposed as properties? Do you want to copy them all? Then you would need to check properties defined in the class and all protocols the class implements. And I'm not sure if won't be necessary to iterate over all the superclasses of your superclass to get all defined properties and ivars.

在UIView的特定情况下,这可能有用 - 你会调整直到它工作。通常情况下可能很困难:那些没有作为属性暴露的ivars怎么办?你想复制它们吗?然后,您需要检查类中定义的属性以及该类实现的所有协议。而且我不确定是否有必要迭代你的超类的所有超类以获得所有已定义的属性和ivars。

But, still, it is possible.

但是,仍然有可能。

UPDATE

UPDATE

If you would copy instance variables then probably you would be probably set without even touching properties - I assume that all state is saved in ivars eventually. So in this case also no need to touch protocol defined properties.

如果你要复制实例变量那么可能你甚至可能没有触及属性就设置了 - 我假设所有状态最终都保存在ivars中。所以在这种情况下也不需要触摸协议定义的属性。

But the other solution that may work well enough is to just stick to the public interface (well actually part of it: just what appears to be data and not functionality): read data through properties of the superclass and set using properties of the derived class, again assuming that the classes will do the right thing with the data. In this case the protocol properties are equally important because the are also part of the public interface and their implementation can save state into instance variables.

但另一个可能运行良好的解决方案就是坚持公共接口(实际上是它的一部分:看似数据而不是功能):通过超类的属性读取数据并使用派生类的属性进行设置,再次假设类将对数据做正确的事情。在这种情况下,协议属性同样重要,因为它们也是公共接口的一部分,它们的实现可以将状态保存到实例变量中。

Again, I wouldn't try this approach as a general solution to copy any class but in a case of duplicating the data of one specific class that might work well enough and you can easily and thorough test your case.

同样,我不会尝试这种方法作为复制任何类的一般解决方案,但在复制一个特定类的数据的情况下可能会运行得很好,并且您可以轻松彻底地测试您的案例。