Могу ли я определить тип объекта в Object-C?

У меня есть массив arry1, который содержит два типа объектов obj1 и obj2. obj2 является подклассом obj1. Я написал метод для суммирования value всех вхождений obj1, который включает:

    int total = 0;
    for (obj1 *t in arry1){
        total += t.value;
    }

Проблема в том, что он содержит как obj1, так и obj2 элементов. То же самое произойдет, если я изменю цикл for на obj2 *t. Итак, у меня есть два вопроса:

  1. Есть ли способ определить фактический класс текущего экземпляра внутри цикла for?

  2. Есть ли способ различать два экземпляра объекта в объявлении for?


person John Morrison    schedule 02.01.2014    source источник
comment
Возможно, isKindOfClass: это проверка, которая может вам помочь   -  person iOS Dev    schedule 03.01.2014


Ответы (4)


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

int total = 0;
for (obj1 *t in arry1) {
    if ([t class] == [obj1 class])
        total += t.value;
}

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

person Nikolai Ruhe    schedule 02.01.2014
comment
это будет работать для большинства случаев, но это похоже на запрос isMemberOfClass, так как не будет работать для кластеров/подклассов - person Grady Player; 03.01.2014
comment
Истинный. Тем не менее вопрос, кажется, подразумевает, что классы хорошо известны. Также особо запрашивается сумма объектов класса obj1. Если кластер классов молча добавляет неизвестные классы, можно возразить, что их не следует добавлять. - person Nikolai Ruhe; 03.01.2014
comment
Спасибо. Я проверил это, и это работает как для основного класса, так и для подкласса. - person John Morrison; 03.01.2014

Там есть

[obj1 isMemberOfClass: [whateverObj1Is class]];

Но это, вероятно, верно для obj2, так как это подкласс

Хорошим решением было бы иметь функцию-член с именем value или что-то, что класс 2 переопределял бы, возвращая 0 или что-то в этом роде.

person 0xFADE    schedule 02.01.2014
comment
isMemberOfClass:, вероятно, является здесь правильным решением, потому что он проверяет принадлежность к определенному классу, а не наследуется ли объект от данного класса. Другими словами, ваш пример не будет верным для obj2. - person NSAdam; 03.01.2014

Вы можете попробовать что-то вроде этого:

int total = 0;
for (Obj1 *t in arry1){
    if([t isMemberOfClass:[Obj1 class]]) total += t.value;
}

Все объекты реализуют протокол NSObject. Этот код использует два метода в этом протоколе. isMemberOfClass: проверяет, принадлежит ли объект тому классу, который передается в качестве аргумента. Метод класса возвращает объект класса для класса получателя.

Источник/дополнительная информация

Кроме того, если вы хотите проверить наличие объектов класса Obj1 или любого из его подклассов, вы можете вместо этого использовать isKindOfClass:.

person Connor    schedule 02.01.2014
comment
Нет смысла объявлять переменную цикла NSObject вместо obj1. - person Nikolai Ruhe; 03.01.2014
comment
Я решил использовать NSObject, потому что его массив содержит объекты obj1 и obj2. В этом примере кода это не имеет особого значения, потому что он заботится только об объектах obj1, но если он хочет делать разные вещи с объектами в зависимости от того, являются ли они obj1 или obj2 в цикле, для меня было бы более разумно объявите переменную цикла как NSObject. - person Connor; 03.01.2014
comment
Объекты в массиве либо obj1, либо obj2, которые являются подклассом obj1. Всегда лучше использовать наиболее конкретный доступный тип, чтобы получить преимущества статической типизации. В этом случае отпадает необходимость в уродливом гипсе. - person Nikolai Ruhe; 03.01.2014
comment
Я пропустил эту часть. Ты прав, я изменю это. - person Connor; 03.01.2014

Вы можете использовать самоанализ, чтобы определить, к какому классу принадлежит каждый из объектов в массиве. Есть два полезных метода для определения класса объекта. isKindOfClass: и isMemberOfClass:. isKindOfClass: возвращает логическое значение, указывающее, является ли получатель экземпляром данного класса или экземпляром любого класса, наследуемого от этого класса. Принимая во внимание, что isMemberOfClass: возвращает логическое значение, указывающее, является ли объект членом этого конкретного класса.

Поэтому вы можете сделать это:

int total = 0;
obj1 *myObj1;
for (NSObject *object in arry1)
{
    if([object isMemberOfClass:[obj1 class]])
    { 
        myObj1 = (obj1 *)object;
        total += myObj1.value;
    }
}
person Tyler Cloutier    schedule 02.01.2014
comment
object.value работает только тогда, когда вы объявляете переменную цикла obj1 object. - person Nikolai Ruhe; 03.01.2014
comment
Ах да, извините за это, я обновлю. - person Tyler Cloutier; 03.01.2014
comment
Нет смысла объявлять переменную цикла NSObject вместо obj1. (obj1 кажется, это название класса. Вы называете его Obj1ClassName). Затем вы можете удалить вторичную переменную. - person Nikolai Ruhe; 03.01.2014
comment
Есть смысл, если вы хотите делать другие вещи с другими объектами в массиве в зависимости от их класса. Хотя я полагаю, что в данном случае это было необязательно. Все еще хорошая практика ИМХО. Кроме того, вы правы, позвольте мне исправить это тоже. - person Tyler Cloutier; 03.01.2014
comment
Я не вижу проблемы с сохранением вторичной переменной, если она проясняет код. Это также позволит вам получить доступ к другим свойствам этого объекта без приведения типов каждого из них. - person Tyler Cloutier; 03.01.2014