Я создал экземпляр 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?