Подтвердить что ты не робот

Цель C: как проверить, является ли переменная NSArray или NSMutableArray

Как проверить, является ли переменная NSArray или NSMutableArray?

4b9b3361

Ответ 1

* Обратите внимание, что реализация массива NS {, Mutable} изменилась с момента написания этого ответа. В результате теперь работает isKindOfClass:. На каких платформах, где и когда, я не знаю.

Пока это не задокументировано как безопасное, я бы настоятельно рекомендую НЕ писать код, который пытается определить, является ли коллекция изменчивой или неизменяемой. Даже если бы это было безопасно, такой шаблон проектирования почти всегда свидетельствует о серьезном недостатке дизайна.

(для тех, у кого есть доступ) Filed rdar://10355515 с просьбой уточнить.


Рассмотрим:

int main (int argc, const char * argv[]) {
    NSArray *array = [NSArray arrayWithObjects: [NSObject new], nil];
    NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects: [NSObject new], nil];

    NSLog(@"array class: %@", NSStringFromClass([array class]));
    NSLog(@"mutableArray class: %@", NSStringFromClass([mutableArray class]));

    NSLog(@"array responds to addObject: %@", 
          [array respondsToSelector: @selector(addObject:)] ? @"YES" : @"NO");

    return 0;
}

(Я использую непустые массивы, потому что пустой NSArray достаточно распространен, что Cocoa предлагает один общий экземпляр в качестве оптимизации.)

array class: NSCFArray
mutableArray class: NSCFArray
array responds to addObject: YES

т.е. ни -isKindOfClass:, ни проверка реализации addObject: не будут работать.

Короче говоря, вы не можете отличить NSArray от NSMutableArray. Это по дизайну и очень предполагаемому поведению. Он также справедлив для NSString, NSDictionary и NSSet (все из которых имеют изменяемый подкласс).

Это может стать неожиданностью. Однако реальность заключается в том, что шаблоны проектирования, требующие проверки на изменчивость, сбивают с толку и несут значительные накладные расходы.

Например, если test-for-mutability были общим шаблоном, чем все методы в Cocoa, которые возвращают NSArray экземпляры должны были бы фактически возвращать экземпляры NSArray и никогда не возвращать ссылку на внутренний NSMutableArray которые могут использоваться.

Ответ 2

Плохие, но технически точные советы...

Единственный способ сделать это - вызвать [unknownArray addObject:someObject] внутри блока @try/@catch и уловить NSInternalInconsistencyException, который будет вызываться, если unknownArray является неизменным (фактическое исключение может быть методом, а не реализовано или класс является неизменным исключением).

Хороший совет...

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

Невозможно выявить причину, связанную с изменчивостью неизменяемых объектов, - поддерживать методы классов, которые работают следующим образом:

- (NSArray *)internalObjects
{
    return myInternalObjects;
}

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

Если у вас есть класс друзей, который нуждается в изменяемом доступе к переменной myInternalObjects, объявите специальную категорию адаптера, которую импортирует только класс friend с помощью метода типа

- (NSMutableArray *)mutableInternalObjectsArray;

Это позволит другу (который вы предполагаете, достаточно умен, чтобы не нарушать специальные правила), чтобы иметь доступ, который ему нужен, но не подвергая изменчивость в более широком смысле.

Ответ 3

Я бы сделал следующее -

if([unkownArray isKindOfClass:[NSMutableArray class]]){
  // This is a nsmutable array
}
else if ([unkownArray isKindOfClass:[NSArray class]]){
 // This is a nsarray
}

Ответ 4

Если вы хотите изменить массив, сделайте это сами:

NSArray *someArray = /* obtain from somewhere, could be mutable, could be immutable */
NSMutableArray *mutableVersion = [someArray mutableCopy]; // definitely mutable

// later

[mutableVersion release];

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

Ответ 5

См. Метод NSObject -class:

NSLog(@"myUnknownArray is of type: %@", [myUnknownArray class]);

Вы также можете напрямую проверить метод +class:

BOOL isMutableArray = [myUnknownArray isKindOfClass:[NSMutableArray class]];

Ответ 6

Использовать...

[Array isKindOfClass: [NSMutableArray class]]

[Array isKindOfClass: [класс NSArray]]

Это будет нормально работать.

Ответ 7

Вы должны использовать:

[yourArray isKindOf: [NSArray class]]

поскольку простая сопоставление классов может потерпеть неудачу, потому что ваш массив, вероятно, не NSArray, а какой-то другой тип низкого уровня. Вы также можете проверить, отвечает ли ваш массив методам, которые вам нужны.

[yourArray respondsToSelector: @selector(addObject:)]