Подтвердить что ты не робот

Как отличить класс "A" к его подклассу "Класс B" - Objective-C

Я использую фреймворк, который определяет и использует класс 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" .

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

Ответ 3

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

Пример:

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


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

}
@end

Ответ 4

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

Ответ 5

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

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

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