Цель c isKindOfClass missunderstanding?

У меня есть следующая структура объектов:

Животное, собака и кошка. Как вы ожидаете, собака и кошка наследуются от животных.

И у меня есть класс фермы:

 @implementation AnimalFarm

-(Animal*) createAnimal:(AnimalType)type{

  switch (type) {

    case CAT:
      return [Cat new];

    case DOG:
      return [Dog new];

    default:
      return [Animal new];
  }

}

@end

и я попытался unit test:

  AnimalFarm *farm = [AnimalFarm new];

  Animal *dog = [farm createAnimal:DOG];
  Animal *cat = [farm createAnimal:CAT];

  STAssertTrue([cat isMemberOfClass:[Cat class]],@"cat is not a cat!");
  STAssertTrue([dog isMemberOfClass:[Dog class]],@"Dog is not a dog!");

  STAssertTrue([cat isKindOfClass:[Animal class]],@"Cat is not an animal!");
  STAssertTrue([dog isKindOfClass:[Animal class]],@"Cat is not an animal!");

Выполнение классов:

@interface Cat : Animal {

}


@end

@implementation Cat

  -(NSString*) say{
    return @"miau";
}

@end

Реализация собаки похожа.

но ни один isKindOfClass или isMemberOfClass не работал, как я ожидал....

Я что-то пропустил?


Когда я использую IFs вместо переключателя, тогда все идет хорошо... но в чем разница?

Реализация createAnimal, которая работает:

-(Animal *) createAnimal:(AnimalType)type {

  if (type == DOG) {
    return [Dog new]; 
  } else if (type == CAT) {
    return [Cat new]; 
  } else {
    return [Animal new];
  }

Ответ 1

isMemberOfClass: будет возвращать только YES, если класс экземпляра точно такой же, однако isKindOfClass: вернет YES, если класс экземпляра тот же или подкласс данного класса.

Например, это выведет No!:

BOOL result = [[NSMutableArray array] isMemberOfClass:[NSArray class]];
NSLog (@"%@", result? @"Yes!" : @"No!");

Но это выведет Yes!:

BOOL result = [[NSMutableArray array] isKindOfClass:[NSArray class]];
NSLog (@"%@", result? @"Yes!" : @"No!");

Это связано с тем, что NSMutableArray является своего рода NSArray, но он не является членом класса NSArray (иначе он не был бы NSMutableArray).

Внутри Foundation и Cocoa существует ряд "кластеров классов". Подробнее об этом можно узнать в документации на веб-сайте Apple developer. Из-за природы кластеров классов, если вы создаете, возможно, объект NSString, это может привести к ошибке isMemberOfClass:[NSString class].

Если ни isKindOfClass:, либо isMemberOfClass: не вернет правильное значение, посмотрите, какой класс имеет фактический объект с

NSLog(@"cat class = %@, dog class = %@", [cat className], [dog className]);

Если они возвращают что-либо иное, чем то, что они предполагают, тогда возникает проблема с вашим классом фермы.

Ответ 2

Ваша проблема кроется в другом месте.

Я создал ваши классы Animal, Dog и Cat, а четыре случая, которые вы прошли выше, прошли. Для справки, вот мой код: http://pastie.org/774468

Он выводит:

2010-01-11 19:45:10.259 EmptyFoundation[83698:a0f] [cat isMemberOfClass:[Cat class]] PASSED
2010-01-11 19:45:10.265 EmptyFoundation[83698:a0f] [dog isMemberOfClass:[Dog class]] PASSED
2010-01-11 19:45:10.265 EmptyFoundation[83698:a0f] [cat isKindOfClass:[Animal class]] PASSED
2010-01-11 19:45:10.273 EmptyFoundation[83698:a0f] [dog isKindOfClass:[Animal class]] PASSED

EDIT:

Я предполагаю, что была небольшая вероятность того, что ваш объект AnimalFarm был источником ошибки, но я просто попытался создать объекты животных таким образом и получил те же результаты (код: http://pastie.org/774480):

2010-01-11 19:51:35.144 EmptyFoundation[83741:a0f] [cat isMemberOfClass:[Cat class]] PASSED
2010-01-11 19:51:35.156 EmptyFoundation[83741:a0f] [dog isMemberOfClass:[Dog class]] PASSED
2010-01-11 19:51:35.157 EmptyFoundation[83741:a0f] ![ant isMemberOfClass:[Cat class]] PASSED
2010-01-11 19:51:35.157 EmptyFoundation[83741:a0f] [cat isKindOfClass:[Animal class]] PASSED
2010-01-11 19:51:35.157 EmptyFoundation[83741:a0f] [dog isKindOfClass:[Animal class]] PASSED
2010-01-11 19:51:35.158 EmptyFoundation[83741:a0f] [ant isKindOfClass:[Animal class]] PASSED

ИЗМЕНИТЬ № 2:

Основываясь на вашем наблюдении, что оператор if else else if работает, но оператор switch не делает этого, я изменил код, который я разместил выше, чтобы использовать оператор switch.... и он работал нормально. Итак, мой комментарий/вопрос: В ваших операторах if/switch вы используете эти константы Dog и Cat. Где определены эти?

Ответ 3

Вам не хватает перерывов, поэтому ваш коммутатор не работает. Это должно выглядеть так.

switch (type) {

 case CAT:
   return [Cat new];
 break;
 case DOG:
   return [Dog new];
 break;
 default:
   return [Animal new];
 break;
}