Я создал экземпляр NSArray, тогда как чей класс не NSArray, а __NSArrayI?

У меня есть следующий код:

id anArray = [NSArray arrayWithObjects:@1, @2, nil];
NSLog(@"anArrayClass - %@", [anArray class]);
NSLog(@"NSArrayClass - %@", [NSArray class]);

И я ожидаю, что оба выхода NSArray, однако, результат оказывается:

2016-08-18 21:08:53.628 TestUse[9279:939745] anArrayClass - __NSArrayI
2016-08-18 21:08:53.629 TestUse[9279:939745] NSArrayClass - NSArray

Затем я создаю тестовый класс под названием CAJTestClass и создайте экземпляр этого класса:

id testInstance = [CAJTestClass new];
NSLog(@"testInstanceClass - %@", [testInstance class]);
NSLog(@"cajTestClass - %@", [CAJTestClass class]);

На этот раз вывод становится:

2016-08-18 21:08:53.629 TestUse[9279:939745] testInstanceClass - CAJTestClass
2016-08-18 21:08:53.629 TestUse[9279:939745] cajTestClass - CAJTestClass

На этот раз результат - то, что я ожидал. Но почему бы [anArray class] быть __NSArrayI?
Объяснение из "Эффективной цели-C" заключается в том, что NSArray является частью "кластера классов"(который, я думаю, представляет собой серию классов, которые имеют наследуемые отношения). Но CAJTestClass также подкласс NSObject, Я ошибся?

РЕДАКТИРОВАТЬ: Спасибо за все ваши ответы. Но мой вопрос состоит именно в том, почему я получаю разные результаты в этих двух случаях, если это должно способствовать делу "кластера классов"?

6 ответов

Решение

РЕДАКТИРОВАТЬ: Спасибо за все ваши ответы. Но мой вопрос состоит именно в том, почему я получаю разные результаты в этих двух случаях, если это должно способствовать делу "кластера классов"?

Потому что тестовый код совершенно другой. Вы звоните NSArray метод, который возвращает подкласс NSArray, но ты звонишь [CAJTestClass new], который возвращает CAJTestClass сам. Если вы сделаете их одинаковыми, то получите те же результаты:

@interface CAJTestClass : NSObject
+ (instancetype)testClassWithMagic;
@end

@interface __MagicTestSubclass : CAJTestClass
@end

@implementation CAJTestClass

+ (instancetype)testClassWithMagic {
    return [__MagicTestSubclass new];
}
@end

@implementation __MagicTestSubclass
@end

Теперь используя ваш тестовый код:

    id testInstance = [CAJTestClass testClassWithMagic];
    NSLog(@"testInstanceClass - %@", [testInstance class]);
    NSLog(@"cajTestClass - %@", [CAJTestClass class]);

2016-08-18 09:57:15.126 test[72004:47882338] testInstanceClass - __MagicTestSubclass
2016-08-18 09:57:15.127 test[72004:47882338] cajTestClass - CAJTestClass

rmaddy повышает вероятность того, что у вас есть другой вопрос, и он может быть прав, поэтому я отвечу и на этот вопрос.

[anArray class] является результатом прохождения -class сообщение экземпляру anArray, Обычная вещь для экземпляра, чтобы сделать, когда он получает -class сообщение должно вернуть определенный класс, в котором он был инициализирован (его конкретный подкласс). Это не универсально (классы KVO преднамеренно нарушают это правило, и даже можно менять классы во время выполнения), но это общий подход. Это isa указатель в структуре, который сообщает диспетчеру, какой набор методов использовать. Таким образом, вы получаете фактический объект класса как экземпляр (__NSArrayI).

[NSArray class] является результатом прохождения +class сообщение объекту класса NSArray, Обычно для объекта класса возвращается self (Я не знаю классов, которые нарушают это правило; нарушать это правило может быть не законно). Таким образом, вы получите класс, которому вы передали сообщение (NSArray).

При разработке программного обеспечения единственные классы, о которых вы беспокоитесь, это NSArray и NSMutableArray. За кулисами, есть много разных классов. Например, одноэлементный класс для пустых массивов. Класс для массивов с одним элементом массива. Все сохраняет память, потому что люди используют тонны и тонны тривиальных массивов.

__NSArrayI - это кодовое слово для неизменяемого массива, то есть "обычный" NSArray, который вы не можете изменить.

__NSArrayM - это кодовое слово для изменяемого массива, то есть NSMutableArray. В NSMutableArray вы можете добавлять и удалять элементы.

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

+ arrayWithObjects: возвращает __NSArrayI с этим ничего не поделаешь, так как это частный API, который нельзя использовать для распространения в магазине приложений.

Если вы хотите проверить, что ваш объект NSArray ты можешь использовать

if ([anArray isKindOfClass:[NSArray class]]){
     //blablabla
}

__NSArrayI ссылается на неизменяемую версию массива, которую нельзя изменить после инициализации.

__NSArrayI означает неизменную форму NSArray. И есть также __NSArrayM, который является изменяемой формой. Неизменность означает, что вы не можете изменить его, объекты внутри этого массива не могут быть изменены. А для изменчивых можно поменять элементы. Вы можете проверить этот пост также. Я думаю, что это также отвечает на ваш вопрос. Что такое __NSArrayI и __NSArrayM? Как конфертировать в NSArray?

Другие вопросы по тегам