Похоже, вы получили большинство свои вопросы в комментариях, но я думал, что писать ответ на, чтобы заполнить любые недостающие пробелы.
NSArray принимает идентификатор, и вы можете пройти в любом подклассе NSObject, который вы хотите, и он позволит ему выполнить его. Это НЕ РЕКОМЕНДУЕТСЯ, но может быть сделано.
NSArray* animals = [NSArray arrayWithObjects:
[[Dog alloc] init],
[[Cat alloc] init],
@"This is a string",
@(42),
nil];
Даже кулер - это то, что когда вы вытаскиваете предметы из массива, они выходят как id. Это становится отличным от любых переменных, которые вы используете.
Dog *dog = animals[0];
Cat *cat = animals[1];
Компилятор не будет волноваться, если вы сделаете это.
NSString *aString = animals[0];
NSLog(@"%@", aString);
NSLog(@"%@", [aString lowercaseString]);
Это то, что вы получите в журнале ...
2015-06-07 08:55:53.715 DogsAndCats2[5717:4029814] <Dog: 0x7fe790c71b80>
2015-06-07 08:55:53.715 DogsAndCats2[5717:4029814] -[Dog lowercaseString]: unrecognized selector sent to instance 0x7fe790c71b80
Вы бросаете идентификатор к NSString, который позволил, однако, вы пытаетесь вызвать метод, который не существует на Собака и рухнет на второй NSLog. Обратите внимание, что первый журнал говорит, что он по-прежнему является Собакой, хотя он заносится как NSString.
Теперь, если мы добавим свойство к вашему Dog.h, мы можем увидеть некоторые опрятные вещи в цикле for.
Dog.h
#import <UIKit/UIKit.h>
@interface Dog : NSObject
@property (nonatomic, strong)NSString *dogName;
-(void)bark;
@end
Теперь, когда мы цикл рассмотрим следующее.
for (id thing in animals)
{
if ([thing respondsToSelector:@selector(bark)])
{
//You are allowed to send messages to id
[thing bark];
[thing setDogName:@"Lassie"];
//compiler error because it doesn't know it is a Dog class
//thing.dogName = @"Lassie";
}
if ([thing isKindOfClass:[Dog class]])
{
[thing bark];
//this is safe because we checked the class first and now we can cast it as so
Dog *dog = (Dog *)thing;
dog.dogName = @"Lassie";
}
}
Надеюсь, это ответит на ваши вопросы и не слишком смущает.
Итератор массива возвращает объекты типа 'id', которые могут быть назначены на все (' Dog') в вашем случае. – rmaddy
@rmaddy, ладно, спасибо. Далее, почему я могу реализовать метод bark() в классе Cat, а затем сделать это: 'Dog * myDog = [[Cat alloc] init]; [myDog bark]; 'По той же причине? init() в NSObject возвращает тип id? Да: '- (instancetype) init'. Как отправить комментарий в качестве ответа? – 7stud
Назначение объекта 'Cat' переменной' Dog' не должно компилироваться (или, по крайней мере, давать предупреждение, которое не следует игнорировать). Но, несмотря на то, что 'myDog' объявлен как переменная' Dog', он фактически указывает на объект 'Cat' во время выполнения, поэтому вы можете вызывать любой метод« Cat »без проблем. – rmaddy