Инициализировать объект экземпляром суперкласса

Допустим, у меня есть Superclass и экземпляр этого класса superclassObject.
Я создаю производный ClassA.

Как создать (инициализировать) объект classAObject производного класса таким образом, чтобы все унаследованные поля были равны полям superclassObject?

Конечно, я могу просмотреть все поля и вручную скопировать значения, такие как classAObject.property = [superclassObject.property copy]. Но проблема с этим подходом в том, что я могу не знать (или не иметь доступа) ко всем ivars/свойствам суперкласса. Есть ли более простой (и более общий) способ?

Кажется, я упускаю что-то действительно элементарное...

Я пытаюсь сделать это, потому что получаю уже инициализированный UIView (с рамкой, цветом фона, маской автоматического изменения размера и т. д.) и хочу заменить его своим пользовательским представлением с теми же параметрами.

Обновление 1

Я нашел этот вопрос, и ответ там говорит, что это

обычно не поддерживается ни на одном языке OO

тем не мение

В Objective-C это возможно в некоторых случаях

Хорошо, если он не поддерживается, что мне делать? Если он поддерживается, как мне этого добиться?

Обновление 2

Кажется, я нашел решение для моего конкретного случая этой общей проблемы, которое я протестирую и сообщу об этом завтра.

Однако это привело меня к другой идее: что, если я использую NSCoder для кодирования superclassObject (если он, конечно, реализует <NSCoding>), а затем вызываю [[ClassA alloc] initWithCoder:coder] с кодером, который знает данные из закодированного superclassObject? Отказ от ответственности: Ну, я не очень хорошо разбираюсь в концепциях кодирования (или даже совсем не разбираюсь), так что последнее предложение может быть чепухой.


person adubr    schedule 17.05.2011    source источник
comment
Вы инициализируете его любым обычным объектом. Проблемы, с которыми вы сталкиваетесь, вероятно, связаны с разрешениями суперкласса и функцией инициализации суперкласса (конструктором).   -  person Radu    schedule 17.05.2011
comment
@Раду, ты не понял моего вопроса. Ивары экземпляра суперкласса уже установлены, но не на значения по умолчанию. Мне нужно их скопировать.   -  person adubr    schedule 17.05.2011
comment
Добавляет ли ваш подкласс собственные переменные экземпляра или поля такие же, как и в суперклассе? То есть вы только создаете новые методы?   -  person jscs    schedule 18.05.2011
comment
@ Джош, да, это так. Если нет, то не будет ли достаточно просто привести указатель к типу classAObject = (ClassA *)superclassObject? В любом случае, не могли бы вы объяснить оба случая или разницу между ними?   -  person adubr    schedule 18.05.2011
comment
Нет, актерский состав не работает. Я только что опубликовал ответ, основанный на предположении, что вы не добавляли ивары; теперь неактуально. Я обновлю, чтобы объяснить; тем временем вы можете прочитать сообщение в блоге, на которое я ссылался, поскольку я в основном имею в виду это.   -  person jscs    schedule 18.05.2011
comment
Мне будет очень интересно посмотреть, что вы придумали! Идея NSCoding меня вдохновила, но я еще недостаточно обдумал ее, чтобы понять, будет ли она работать. Удачи!   -  person jscs    schedule 18.05.2011


Ответы (3)


Если я правильно понимаю вопрос, у вас есть установленное представление, которое вы хотите изменить на другой класс. Предположительно по причине изменения его функциональности.

Клонирование свойств класса между классами и обмен экземплярами — единственный способ сделать это в таких языках, как Java.

Но... в Objective C у нас есть категории. Если все, что вы пытаетесь сделать, это изменить поведение, возможно, решением может быть создание категории для UIView, которая выполняет дополнительные или переопределенные функции, которые вам нужны.

Вторая мысль - выяснить, почему вы не создаете правильный класс, и, следовательно, избежать всей этой проблемы.

person drekka    schedule 17.05.2011
comment
+1 за обход; Тем не менее, расширения категорий/классов вовсе не являются хорошей идеей для переопределения методов фреймворка, а только для добавления. Добавление хранилища в класс фреймворка, хотя и законно, тоже может быть не очень хорошим. - person jscs; 18.05.2011
comment
@ Джош, да, согласен. Моим личным предпочтением было бы выяснить, почему в первую очередь был создан экземпляр неправильного класса. лучше поймать лошадь, пока она не убежала ;-) - person drekka; 18.05.2011

IFF ваш подкласс добавляет только методы, а не какие-либо хранилища (т. е. ivars) в суперкласс, тогда вы можете использовать технику получерной магии*, называемую "isa-swizzling ". Роб Нэпьер упоминает это и ссылается на запись в блоге, которая все объясняет.

Каждый экземпляр Objective-C имеет часть памяти для своих переменных экземпляра, но реализация методов хранится в другом месте, в хранилище для объекта класса. Среда выполнения использует указатель экземпляра isa для доступа к объекту класса.

Таким образом, как показано в связанном сообщении в блоге, можно преобразовать экземпляр одного класса в другой, при условии, что они имеют точно такие же поля. Как предупреждает Роб, вы не можете добавлять ивары, только изменять методы.

Приведение (MyDerivedClass *)instanceOfSuperclass имеет эффект только во время компиляции. Все, что он делает, это делает компилятор довольным, когда он сравнивает типы: это не влияет на поиск методов во время выполнения, поэтому ваш instanceOfSuperclass будет по-прежнему действовать как Superclass.

РЕДАКТИРОВАТЬ: В качестве последней мысли, поскольку мы уже говорим об опасных методах, возможно, вы могли бы создать вспомогательный класс, который будет содержать ивары, которые вы хотите добавить в подкласс. Ого, теперь я реально сошли с ума!

Я никогда не делал этого сам; Я только сообщаю о методе, который может быть полезен для вас. Пожалуйста, обратите внимание на все предупреждения, которые вы видите, когда это обсуждается.


*Используется для KVO, интересно.

person jscs    schedule 17.05.2011
comment
Этот метод, вероятно, относится к вопросу, который вы связали. - person jscs; 18.05.2011

Это определенно возможно с использованием среды выполнения ObjC, но это будет немного сложно... Это ссылка на документы Apple: Среда выполнения Objective-C и пример ее использования: Программирование среды выполнения на Objective-C.

Вы должны перебрать все свойства, проверить их атрибуты, чтобы узнать, какие из них вы можете установить (т.е. опустить свойства только для чтения), получить их метод получения в суперклассе, прочитать значение и установить с помощью метода установки в подклассе.

В конкретном случае UIView это может сработать — вы будете настраивать, пока не заработает. Как правило, это может быть сложно: как насчет иваров, которые не выставляются как свойства? Вы хотите скопировать их все? Затем вам нужно будет проверить свойства, определенные в классе, и все протоколы, которые реализует класс. И я не уверен, что не нужно будет перебирать все суперклассы вашего суперкласса, чтобы получить все определенные свойства и ivars.

Но, тем не менее, это возможно.

ОБНОВЛЕНИЕ

Если бы вы копировали переменные экземпляра, то, вероятно, вы, вероятно, были бы установлены, даже не касаясь свойств - я предполагаю, что в конечном итоге все состояние сохраняется в ivars. Таким образом, в этом случае также нет необходимости трогать определенные протоколом свойства.

Но другое решение, которое может работать достаточно хорошо, состоит в том, чтобы просто придерживаться общедоступного интерфейса (точнее, его части: только то, что кажется данными, а не функциональностью): читать данные через свойства суперкласса и устанавливать, используя свойства производного класса. , опять же предполагая, что классы будут правильно обращаться с данными. В этом случае свойства протокола одинаково важны, поскольку они также являются частью общедоступного интерфейса, и их реализация может сохранять состояние в переменных экземпляра.

Опять же, я бы не стал пробовать этот подход в качестве общего решения для копирования любого класса, но в случае дублирования данных одного конкретного класса это может работать достаточно хорошо, и вы можете легко и тщательно проверить свой случай.

person Tomasz Stanczak    schedule 17.05.2011
comment
В общем случае, я полагаю, хотелось бы, чтобы все данные были скопированы, включая частные ивары. Но зачем заботиться о свойствах протоколов? Насколько я знаю, они не обеспечены иварами, поэтому у них нет данных для копирования. Или я что-то упускаю? Ну, во всяком случае, я согласен, что это сложно. Хотя я сделал одно дикое предположение по этому поводу - пожалуйста, проверьте обновленный вопрос. - person adubr; 18.05.2011
comment
См. обновление: свойства протокола также являются методами, вы можете реализовать их, делая все, что вам нравится, включая сохранение состояния в ivars. - person Tomasz Stanczak; 18.05.2011