2014-11-07 2 views
24

У меня есть простой Person класса в Swift, который выглядит примерно так:Дополнительный массив против пустого массива в Swift

class Person { 
    var name = "John Doe" 
    var age = 18 
    var children = [Person]? 

    \\ init function goes here, but does not initialize children array 
} 

Вместо того, чтобы объявить children быть дополнительным массив, я мог бы просто объявить и инициализировать его как пустой массив:

var children = [Person]() 

Я пытаюсь решить, какой подход лучше. Объявление массива как необязательного массива означает, что он не будет занимать какую-либо память вообще, тогда как пустой массив имеет по крайней мере некоторую память, выделенную для него, правильно? Таким образом, использование необязательного массива означает, что будет по крайней мере некоторое сохранение памяти. Я предполагаю, что мой первый вопрос: действительно ли существует реальная экономия памяти, или мои предположения об этом неправильны?

С другой стороны, если он не является обязательным, то каждый раз, когда я пытаюсь его использовать, мне нужно будет проверить, есть ли оно nil или нет, перед добавлением или удалением из него объектов. Так что там будет некоторая потеря эффективности (но не так много, я думаю).

Я как бы факультативный подход. Не каждый Person будет иметь детей, так почему бы не позволить children быть nil до Person решает поселиться и поднять семью?

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

+0

У вас есть правильный вопрос, но я думаю, что аргументы за и против опасны - на основе преждевременной оптимизации, а не семантики. Гораздо лучше сосредоточиться на «доступности» кода - насколько он предлагает намерение (что бы это ни было для контекста). В Swift есть множество вещей, которые мне не нравятся, но для меня тип Optional - настоящий камень. Хотя для вашего вопроса нет «правильного» ответа, я широко использую его в таких контекстах, как ваш. Использование опционального для случая дополнительных детей кажется вполне разумным и минималистичным. –

+1

Я бы предположил, что количество элементов в массиве, равное нулю, означает, что есть нулевые дети. Массив nil предположил бы, что существует число детей, которые не могут быть равны нулю и не могут быть ненулевыми. Нет никакой логики в возвращении nil, поскольку в ней нет смысла. Чтобы сохранить код, написанный 20 лет назад, я могу сказать вам, что если вы предложите какое-то другое значение, вернув nil, кто-то его смутит, и задайтесь вопросом, что вы намеревались сделать с этим nil, что пустой массив не выполнить. производительность пустого массива вряд ли будет иметь значение. –

ответ

15

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

я бы выбрал:

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

Позвольте мне сделать некоторые примеры: заказ

  • Покупка с мастером и деталей (одна деталь для каждого продукта): заказ на покупку может иметь 0 детали, но это временный статус, потому что не имеет смысла иметь заказ на поставку с 0 продуктами
  • Человек с детьми: человек не может иметь детей на всю жизнь. Это не временный статус (хотя и не постоянный), но, используя необязательно, ясно, что у человека нет детей.

Обратите внимание, что мое мнение касается только того, чтобы сделать код более понятным и самообучающимся - я не думаю, что есть какие-либо существенные различия в производительности, использовании памяти и т. Д. Для выбора одного или другого варианта ,

+0

Количество элементов в массиве - это количество детей. Нулевые предметы - это нулевые дети. Использование nil для массива подразумевает подсчет, который не равен нулю и не равен нулю, что почти бессмысленно. Единственный случай, когда nil может иметь смысл, - это если вы хотите передать вызывающему абоненту, что номер не может быть вычислен (неизвестен), что является единственным возможным другим состоянием. Возвратите число детей, если число известно и вернет его, имея много элементов в массиве. –

+0

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

1

Swift предназначен для использования опционального и дополнительного разворачивания.

Вы могли также объявить массив, как ноль, так как это позволит сэкономить вам очень маленький (почти не заметные) объем памяти.

Я бы с дополнительным массивом вместо массива, который представляет нулевую ценность, чтобы сохранить Design Patterns Свифта счастливым :)

Я также думаю, что

if let children = children { 

} 

выглядит лучше, чем:

if(children != nil){ 

} 
14

Я собираюсь сделать противоположный случай из Йорди - пустой массив точно так же ясно говорит, что «у этого Человека нет детей», и сэкономит вам массу хлопот. children.isEmpty - это простая проверка на существование детей, и вам никогда не придется разворачивать или беспокоиться о неожиданном nil.

Кроме того, в качестве примечания, объявление чего-либо как необязательного не означает, что оно занимает нулевое пространство - это .None случай Optional<Array<Person>>.

+0

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

+0

Я задаюсь вопросом о проблемах с производительностью, если у меня есть тяжелый класс, будет ли массив такого типа иметь большие накладные расходы по сравнению с .None? Или есть ли оптимизация в Swift, чтобы не выделять пространство для изначально пустых массивов? – Bretsko

9

Интересно, что у нас недавно было мало дискуссий по этому самому вопросу на работе.

Некоторые считают, что существуют тонкие смысловые различия. Например. nil означает, что у человека нет детей вообще, но тогда что означает 0? Означает ли это, что "имеет детей, всего 0 из них"? Как я уже сказал, чистая семантика «имеет 0 детей» и «не имеет детей» не имеет значения при работе с этой моделью в коде. В таком случае, почему бы не выбрать более прямолинейные и менее осторожные меры?

Некоторые считают, что при сохранении nil может появиться указание, что, например, при извлечении модели из бэкэнда что-то пошло не так, и мы получили ошибку вместо детей. Но я думаю, что модель не должна пытаться использовать этот тип семантики, а nil не следует использовать как указание на некоторую ошибку в прошлом.

Я лично считаю, что модель должна быть настолько тупой, насколько это возможно, и dumbest опция в этом случае пустой массив.

Имея дополнительный сделаешь перетаскивание, что ? до конца дней и не использовать guard let, if let или ?? снова и снова.

Вы должны иметь дополнительную логику разворачивания для NSCoding реализации, вам придется сделать person.children?.count ?? 0 вместо простого person.children.count, когда вы показываете эту модель в любом контроллере представления.

Конечной целью всех этих манипуляций является отображение чего-либо в пользовательском интерфейсе. Вы бы сказали:

«У этого человека нет детей» и «У этого человека есть 0 детей» для nil и пустой массив соответственно?Я надеюсь, что вы не :)

Последняя Стро

Наконец, и это действительно самый сильный аргумент у меня есть

В модели Cocoa есть такие примеры: UIViewController::childViewControllers и другие.

Даже из чистого мира Swift: Dictionary::keys, хотя это может быть немного надуманным.

Почему у человека нет nil детей, но не для SKNode? Для меня аналогия идеальна. Эй, имя метода даже SKNode «s является children :)

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

Последняя Последняя Стро

Наконец, некоторые ссылки на очень хорошие статьи, каждый из этих

В пост Наташи, вы найдете link to NSHipster's blog post и в Swiftification параграф вы можете прочитать:

Например, вместо маркировки возвращаемых значений NSArray, как Nullable многих интерфейсов были изменены, чтобы вернуть пустой массив-семантически они имеют одинаковое значение (то есть, ничего), а не опциональный массив гораздо проще для работы с

+2

«nil» для меня - это нуль в базе данных (то же, что и значения java и C#). Это означает, что мы не знаем, есть ли у ребенка дети или нет. Значение 0 означает, что мы знаем, что у человека нет детей. – chrisl08

0

Иногда существует разница между чем-то не существующим и пустым.

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

Когда мы не можем различать пустое свойство или не существующий пустой, это путь. Если бы Person потеряли своего единственного ребенка, мы должны просто удалить этого ребенка и иметь пустой массив, а не проверять, является ли count равным 1, а затем установить весь массив на nil.

0

Я всегда использую пустые массивы.

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

Смежные вопросы