Какао: Тестирование, чтобы найти, является ли NSString неизменным или изменчивым? - PullRequest
7 голосов
/ 19 января 2010

Это создает неизменный строковый объект:

NSString* myStringA = @"A";  //CORRECTED FROM: NSMutableString* myStringA = @"A";

Это создает изменяемый строковый объект:

NSMutableString* myStringB = [NSMutableString stringWithString:@"B"];

Но оба объекта отображаются как объект одного типа, "NSCFString":

NSLog(@"myStringA is type: %@, myStringB is type: %@", 
[myStringA class], [myStringB class]);

Итак, что же отличает эти объекты внутри, и как мне проверить это, чтобы я мог легко определить, является ли переменная-загадочная строка неизменной или изменчивой, прежде чем совершить что-то плохое для нее?

Ответы [ 3 ]

13 голосов
/ 19 января 2010

Документы содержат довольно длинное объяснение того, почему Apple не хочет, чтобы вы это делали, и почему они явно не поддерживают это в Получение изменяемых объектов .Сводка такова:

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

Я считаю их пример NSView наиболее простым для понимания, иэто иллюстрирует основную проблему Какао.У вас есть NSMutableArray с именем «elements», который вы хотите представить в виде массива, но не хотите, чтобы вызывающие абоненты связывались с ним.У вас есть несколько вариантов:

  1. Предоставить NSMutableArray как NSArray.
  2. Всегда делать неизменяемую копию при запросе
  3. Сохранять элементы как NSArray и создаватьновый массив каждый раз, когда он мутирует.

Я делал все это в разных точках.№ 1, безусловно, самое простое и быстрое решение.Это также опасно, так как массив может видоизменяться за спиной вызывающего.Но Apple указывает, что это то, что они делают в некоторых случаях (обратите внимание на предупреждение для -подвидов в NSView).Я могу подтвердить, что, хотя № 2 и № 3 намного безопаснее, они могут создавать серьезные проблемы с производительностью, поэтому, вероятно, именно поэтому Apple решила не использовать их на часто используемых членах, таких как -subviews.

Результатвсе это в том, что если вы используете # 1, то самоанализ будет вводить вас в заблуждение.У вас есть NSMutableArray, приведенный как NSArray, и самоанализ покажет, что он изменчив (самоанализ не может знать иначе).Но вы не должны мутировать его.Только проверка типа во время компиляции может сказать вам об этом, и поэтому это единственное, чему вы можете доверять.

Исправление для этого - это некая быстрая неизменяемая версия структуры изменяемых данных с копированием при записи.,Таким образом, # 2 может быть сделано с достойной производительностью.Я могу представить изменения в кластере NSArray, которые позволили бы это, но в настоящее время его нет в Какао (и может повлиять на производительность NSArray в обычном случае, сделав его не стартером).Даже если бы у нас было это, вероятно, существует слишком много кода, который полагается на текущее поведение, чтобы когда-либо позволять доверять интроспекции изменчивости.

4 голосов
/ 19 января 2010

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

BOOL isMutable(id object)
{
   id copy = [object copy];
   BOOL copyIsADifferentObject = (copy != object);
   [copy release];
   return copyIsADifferentObject;
}

Отказ от ответственности: конечно, нет гарантии, что копия эквивалентна сохранению для неизменяемых типов.Вы можете быть уверены, что если isMutable вернет NO, то он не будет изменяемым, поэтому функция должна быть названа canBeMutable.Однако в реальном мире вполне безопасно предположить, что неизменяемые типы (NSString, NSArray) будут реализовывать эту оптимизацию.Существует много кода, включая базовые вещи, такие как NSDictionary, который ожидает быстрое копирование из неизменяемых типов.

4 голосов
/ 19 января 2010

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

Можно ожидать, что сработает одно из следующих, но ни одно из них не сработает:

[[s class] isKindOfClass:[NSMutableString class]]; // always returns false
[s isMemberOfClass:[NSMutableString class]]; // always returns false
[s respondsToSelector:@selector(appendString)]; // always returns true

Больше информации здесь, хотя это не поможет вам с проблемой:

http://www.cocoabuilder.com/archive/cocoa/111173-mutability.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...