Как преобразовать «Класс A» в его подкласс «Класс B» — Objective-C

StackOverflow https://stackoverflow.com/questions/1236434

Вопрос

Я использую структуру, которая определяет и использует «ClassA», подкласс NSObject.Я хотел бы добавить некоторые переменные и функциональные возможности, поэтому, естественно, я создал «ClassB», подкласс «ClassA».

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

Например, возьмем этот метод:

- (ClassA *)doSomethingCool:(int)howCool

Теперь в своем коде я пробую это:

ClassB * objB;
objB = (ClassB *)doSomethingCool(10); 

NSLog(@"objB className = %@", [objB className]);

Это работает нормально.Никаких ошибок компиляции или выполнения или чего-то еще.Но что для меня действительно странно, так это вывод:

>> "objB className = ClassA"

Кастинг явно провалился.Не знаю, что произошло в этот момент...objB имеет тип «ClassB», но его имя класса — «ClassA», и он не отвечает ни на какие методы «ClassB».

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

Я нашел похожее сообщение, которое прямо противоположно тому, что я спрашиваю. здесь

Это было полезно?

Решение

Приведение объектных переменных в Objective-C обычно является ошибкой (есть несколько случаев, когда это правильно, но никогда в подобных случаях).Обратите внимание, что вы не применяете объект — вы приводите указатель к объекту.Затем у вас есть указатель типа ClassB*, но он по-прежнему указывает на тот же экземпляр ClassA.То, на что указано, совсем не изменилось.

Если вы действительно хотите преобразовать экземпляры ClassA в ClassB, вам нужно будет написать метод конструктора ClassB, который сможет создать экземпляр ClassB из ClassA.Если вам действительно нужно добавить переменные экземпляра, это может быть вашим лучшим выбором.

Однако, как сказал Джейсон, зачастую полезно сначала попробовать какую-то категорию.

Другие советы

Вы не можете просто преобразовать суперкласс в его подкласс.На самом деле он не реализует ни одну из добавленных вами переменных/свойств или методов.Как только вы попытаетесь отправить сообщение с помощью метода, который вы определили в своем подклассе, вы получите исключение во время выполнения, и ваше приложение закроется.Вы можете безопасно забрасывать мяч только в одном направлении:от более конкретного к более общему.То есть вы можете безопасно преобразовать наш класс B в класс A, используя только методы и свойства класса A, но не наоборот.

Подумайте об этом так:у вас есть Car (родительский класс) и FourDoorSedan (подкласс).У каждой машины есть двигатель и две двери.Теперь предположим, что вы откуда-то получаете машину, и это все, что вы о ней знаете.Вы говорите оператору, что машина — четырехдверный седан, а на деле оказывается, что это не так.Итак, когда оператор делает что-то вроде:openBackPassengerDoor, что происходит?Дверей всего две!!Здесь то же самое.

Если вы просто хотите добавить немного функциональности в ClassA, ознакомьтесь с категориями Objective-C. Вероятно, они вам нужны, и приведение типов не потребуется.Однако внимательно прочитайте документацию, поскольку она не лишена оговорок.

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

Пример:

//"ClassA+doSomethingCool.h"
@interface ClassA (doSomethingCool)
- (ClassA *)doSomethingCool:(int)howCool;
@end


//"ClassA+doSomethingCool.m"
@implementation ClassA (doSomethingCool)
- (ClassA *)doSomethingCool:(int)howCool
{

}
@end

Приведение не преобразует один тип объекта в другой.Вы не можете заставить какую-либо библиотеку изменить тип объекта и создать другой тип объектов, если она не использует какой-либо фабричный шаблон.

Что происходит, когда вы вызываете один из методов подкласса для возвращаемого объекта?

ClassB * objB;
objB = (ClassB *)doSomethingCool(10);
[objB subClassMethod];

Obj-C довольно бесплатен и проигрывает в выборе типов, вам даже не нужно заранее знать тип, например.вы можете изменить все ссылки ClassB на id.Я знаю, что безопаснее знать, что у вас ожидаемый тип, но если ваш код правильный, это не имеет значения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top