Как привести «Класс A» к его подклассу «Класс B» - Objective-C - PullRequest
26 голосов
/ 06 августа 2009

Я использую фреймворк, который определяет и использует 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', но его className - это 'ClassA', и он не будет отвечать ни на какие методы 'ClassB'.

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

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

Ответы [ 5 ]

26 голосов
/ 06 августа 2009

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

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

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

19 голосов
/ 06 августа 2009

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

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

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

5 голосов
/ 06 августа 2009

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

Пример:

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


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

}
@end
2 голосов
/ 30 октября 2010

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

0 голосов
/ 06 августа 2009

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

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

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

...