Должен ли я проверять объекты внутри контейнеров Foundation API? - PullRequest
2 голосов
/ 06 августа 2010

В таких языках, как C++ и C# при создании содержимого, такого как std::vector или C# list, вы явно объявляете тип контейнера при его создании:

C ++:

std::vector<MyObject>

C #:

List<MyObject> list = new List<MyObject>();

Глядя на код выше, я сразу знаю, что эти контейнеры могут содержать только объекты типа MyObject, и компилятор будет жаловаться, если я попытаюсь добавить объект, который не относится к этому типу.

Поскольку Objective-C является динамическим языком, у нас нет привилегии компилятора, предупреждающего нас об этом (потому что это совершенно допустимая, но потенциально опасная вещь):

Objective-C:

NSDictionary *dict = [[NSDictionary alloc]init];
[dict setValue:[[SomeClass alloc]init] forKey:@"someClass"];
[dict setValue:[[NSMutableString alloc]init] forKey:@"mutableString"];
BOOL classIsSomeClass = [[dict objectForKey:@"someClass"] isKindOfClass:[SomeClass class]];

Вместо этого что-то вроде NSDictionary или NSArray будет хранить и принимать объекты любого типа, которые наследуются от NSObject. Я нахожу это само по себе очень гибким, но на самом деле я не могу быть уверенным в типе объекта в контейнере, который я могу знать только по runtime, тогда как по c++ или c# я знаю это по compile time и просто глядя код.

Должен ли я проверять содержимое контейнеров при добавлении, использовании и удалении объектов для классов контейнеров (NSArray, NSSet, NSDictionary и т. Д.) Из Apple Foundation Framework ? Или это нормально при любых обстоятельствах, и проверка сильно ухудшит производительность?

NSDictionary *dict = [[NSDictionary alloc]init];
[dict objectForKey:@"someKey"];    // return nil?

Ответы [ 3 ]

5 голосов
/ 06 августа 2010

Динамический обмен сообщениями в Objective-C во многом похож на динамические языки, такие как Python или Ruby. В этих языках стандартная парадигма часто известна как «типирование утки». Другими словами, если экземпляр объекта крякает как утка (то есть отвечает на сообщение, которое вы отправляете), это утка. В Objective-C методы могут быть добавлены во время выполнения с помощью ряда механизмов вне иерархии наследования объектов. Поэтому гораздо чаще спрашивать, реагирует ли экземпляр на определенный селектор:

if([obj respondsToSelector:@selector(myMethod)]) {
  [obj myMethod];
}

, чем спросить, принадлежит ли obj к определенной иерархии классов.

По большей части разработчики Objective-C не выполняют эту проверку, если они не получают экземпляры объектов из «неизвестных» модулей. Вместо этого мы в значительной степени полагаемся на предупреждения компилятора (компилятор Objective C предупредит об отправке сообщения типу, который не уверен, что может получить это сообщение) и модульном тестировании. В этом случае модульное тестирование, чтобы подтвердить, что в коллекцию попадают правильные объекты и что вы получаете ожидаемые типы из коллекции, вероятно, поможет развеять ваши страхи.

2 голосов
/ 06 августа 2010

Похоже, что это «путь Objective-C», позволяющий избежать проверки типов объектов, взятых из коллекции. Это, конечно, спорно ли это хорошо, но я думаю, что это часть общей темы предпочитает думать о сообщениях объект отвечает, а не сам объект.

Примером этого являются различные ...Value (например, stringValue, intValue и т. Д.) Сообщения, на которые отвечают многие объекты. Стоит также отметить тот факт, что тип id автоматически подавляет любые предупреждения о том, что такой-то может не отвечать на такие-то сообщения разновидность.

0 голосов
/ 06 августа 2010

Я бы сказал, что шаблон в Objective-C - хранить только объекты одного типа в контейнере - и почти всегда вы уверены в том, что входит в контейнер.Вот почему очень немногие люди на практике тратят время, чтобы проверить содержимое коллекции.Когда я хочу что-то проверить, я обычно использую isKindOfClass: и правильно типизированный объект для хранения элемента из коллекции.

Если вы по какой-то причине действительно беспокоитесь о наборе текста, было бы довольно легко создатьКласс-обертка, который реализовал типизированные версии objectAtIndex: и других распространенных методов NSArray. Обратите внимание, что я не говорю о подклассе NSArray или любой другой коллекции, просто об объекте, который имеет похожие имена сообщений.Подобные вещи могут быть полезны для многих целей, и вы всегда можете добавить метод сброса, чтобы получить доступ к резервной коллекции.Но я думаю, что это больше проблем, чем стоит, и отходит от овладения языком.

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

Теперь для метода, который принимает аргумент typeID, я с большей вероятностью проверю тип перед использованием - потому что эти методы имеют тенденцию принимать гораздо более широкий диапазон объектов.

...