Инициализировать объект с помощью экземпляра суперкласса
Скажем, a имеет 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
? Отказ от ответственности: Ну, я не знаком с концепциями кодирования (или даже совсем не с ними), поэтому последнее предложение может быть абсурдным.
Ответы
Ответ 1
Если я правильно понял вопрос, у вас есть установленное представление, которое вы хотите изменить на другой класс. Предположительно по причине изменения его функциональности.
Свойства класса клонирования между классами и экземплярами подкачки - единственный способ сделать такие вещи на таких языках, как Java.
Но... в Objective C мы имеем категории. Если все, что вы пытаетесь сделать, это изменить поведение, то, возможно, решение может заключаться в создании категории для UIView, которая выполняет дополнительные или переопределенные функции, которые вам нужны.
Вторая мысль - посмотреть, почему вы не создаете правильный класс и, следовательно, избегаете всей этой проблемы.
Ответ 2
Это определенно возможно с использованием среды выполнения ObjC, но она будет немного волосатой... Это ссылка на документы Apple: Objective-C Время выполнения и пример его использования: Objective-C Программирование времени выполнения.
Вы будете перебирать все свойства, проверять их атрибуты, чтобы узнать те, которые вы можете установить (т.е. опускать свойства readonly), получить их метод getter на суперклассе, прочитать значение и установить с помощью метода setter в подклассе.
В конкретном случае UIView это может сработать - вы будете настраивать до тех пор, пока он не будет работать. Как правило, это может быть трудно: как насчет иваров, которые не подвергаются воздействию свойств? Вы хотите скопировать их все? Затем вам нужно будет проверить свойства, определенные в классе и во всех протоколах, реализуемых классом. И я не уверен, если не будет необходимости перебирать все суперклассы вашего суперкласса, чтобы получить все определенные свойства и ivars.
Но, все же, это возможно.
UPDATE
Если бы вы скопировали переменные экземпляра, то, вероятно, вы, вероятно, были бы настроены, даже не касаясь свойств - я предполагаю, что все состояние сохраняется в ivars в конце концов. Поэтому в этом случае также не нужно касаться определенных протоколом свойств.
Но другое решение, которое может работать достаточно хорошо, - это просто придерживаться общедоступного интерфейса (ну, собственно, его часть: именно то, что представляется как данные, а не функциональность): чтение данных через свойства суперкласса и установка с использованием свойств производный класс, снова полагая, что классы будут делать правильные вещи с данными. В этом случае свойства протокола одинаково важны, поскольку они также являются частью открытого интерфейса, и их реализация может сохранять состояние в переменных экземпляра.
Опять же, я бы не пробовал этот подход как общее решение для копирования любого класса, а в случае дублирования данных одного определенного класса, который мог бы работать достаточно хорошо, и вы можете легко и тщательно протестировать ваш случай.
Ответ 3
IFF ваш подкласс добавляет к суперклассу только методы, а не какое-либо хранилище (т.е. ivars), тогда вы можете использовать метод получерчной магии *, называемый "isa-swizzling". Роб Напир упоминает об этом, и ссылки на сообщение в блоге, которое объясняет все это.
Каждый экземпляр Objective-C имеет кусок памяти в памяти для своих переменных экземпляра, но реализация методов хранится в другом месте в хранилище для объекта класса. В среде выполнения используется указатель экземпляра isa
для доступа к объекту класса.
Таким образом, как показано в связанном сообщении в блоге, можно преобразовать экземпляр одного класса в другой , если они имеют точно такие же поля. Как предупреждает Роб, вы не можете добавить ivars, только измените методы.
Литье (MyDerivedClass *)instanceOfSuperclass
влияет только на время компиляции. Все это делает компилятор счастливым, когда он сравнивает типы: он не влияет на поиск методов во время выполнения, поэтому ваш instanceOfSuperclass
будет по-прежнему действовать как Superclass
.
EDIT: как последняя мысль, так как мы уже говорим об опасных методах, возможно, вы можете создать вспомогательный класс, который будет содержать ивары, которые вы хотите добавить в подкласс. Whew, теперь я действительно сошел с ума!
Я никогда не делал этого сам; Я только сообщаю вам технику, которая может быть вам полезна. Пожалуйста, обратите внимание на все предупреждения, которые вы видите, когда это обсуждается.
* Интересно, что для KVO.