Почему вместо этого следует использовать перечисления

Ain’t Got No Strings ...

«Волшебные» струны не такие уж и волшебные в Swift

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

Я знаю, что в тот или иной момент мы все время думали: «Как снова назывался этот идентификатор?» … Затем вы возвращаетесь к поиску, и к тому времени, когда вы его находите и копируете, вы в первую очередь забываете, для чего он вам нужен. Ваш мыслительный процесс временно замедляется, потому что вам пришлось остановиться и подумать о чем-то, что вам никогда не нужно было останавливать и думать!

Хуже того, вы запомнили это и неправильно написали! Ну что ж ... вот и окрестности. Теперь ваше приложение дает сбой, потому что "PreformDetailSegue" не является допустимым идентификатором.

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

В этой истории мы рассмотрим простой способ избежать магических ниточек.

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

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

У нас уже есть усталость от принятия решений (термин, исследованный Роем Ф. Баумейстером), умственная усталость, мозговой туман, трехчасовой спад и многое другое, о чем нужно беспокоиться. Итак, давайте узнаем, как избавиться от одного из этих переживаний - помогает каждая мелочь!

Допустим, мы создаем словарь, содержащий наши ID (accountNumber) firstName, lastName, latitude и longitude. Поскольку ключи словаря должны быть хешируемыми, а строки должны быть хешируемыми ... но наши значения в этом случае могут быть либо String, либо Double, нам понадобится Dictionary типа [String: Any].

Мы могли бы создать этот словарь, используя простые строки для ключей, но тогда мы оставим себя открытыми для опечаток и значений nil в дальнейшем. Вместо этого мы могли бы довольно быстро построить одно или два перечисления и использовать эти значения вместо строк. Таким образом, мы избегаем ошибок, вызванных опечатками (вы не избежите опечаток, но, по крайней мере, вы будете последовательны и получите НАМНОГО проще рефакторинг времени!)

Во-первых, традиционный способ создания словаря [String: Any] в Swift:

Я сделал орфографическую ошибку в приведенном выше словаре. Если вы не заметили, это клавиша широты или latitiude. Я сделал ошибку намеренно, чтобы выделить точку, но при разработке этого простого примера на самом деле сделал ошибку, которая вызвала у меня головную боль на минуту, заставив меня вернуться и изучить свои строки.

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

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

Давайте организовываться

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

Начнем с нашего первого перечисления NameKey.

В нем мы будем хранить наши accountNumber, firstName и lastName. Если подумать, его можно было бы более уместно назвать как-нибудь вроде UserIdentifierKey. Может показаться странным, что я использовал единственное число для перечисления, поскольку оно содержит ключ s, а не единственный ключ, но я следую стандартному соглашению об именах Swift.

Ключевое слово enum идентифицирует это как перечисление так же, как class идентифицирует класс. Затем идет имя, опять же, как при идентификации класса (class SomeViewController: UIViewController). Следующая часть немного другая. Обычно мы называем это типом, но с помощью перечисления мы называем это исходным значением.

Необработанное значение дает нашим кейсам перечисления связанный тип. Обычно, когда мы объявляем перечисление с необработанным значением, мы должны затем дать каждому случаю связанное необработанное значение. Однако перечисления с rawValue типа String поставляются со свободным связанным значением имени случая. Таким образом, rawValue accountNumber равно «accountNumber». Если бы мы хотели, чтобы он был связан с другим значением, мы могли бы легко это сделать ... но давайте не будем усложнять и перейдем к нашему перечислению Location.

Перечисление LocationKey

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

Теперь у нас есть дом для всех строковых значений нашего словаря. Давайте создадим наш словарь. Нам потребуется доступ к rawValue каждого случая, чтобы добраться до String. Если вы забыли .rawValue и явно набрали в словаре [String: Any], компилятор на мгновение прервет ваш день с ошибкой, сообщив вам, что он не может преобразовать ваш тип LocationKey в ожидаемый тип: String.

Вместо этого вы хотите использовать LocationKey.currentLocation.rawValue. Это обращается к rawValue дела и помещает наше String значение туда, где мы хотим - и мы никогда не вводили одинарные (или двойные 🤓) кавычки.

Вы можете использовать .capitalized после .rawValue, если хотите, чтобы первая буква была заглавной, или нарушите соглашение об именах и назовите свой регистр одной. В этом примере currentLocation написано в нижнем регистре, хотя в нашем примере String оно было в верхнем регистре.

Теперь позже, когда мы хотим извлечь значение, мы просто используем наши перечисления для ключей словаря, и мы почти гарантированно получим значение обратно!

В заключение

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

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

Избегайте магических строк и избегайте магических чисел, когда это возможно. Другие разработчики, которые работают над вашей кодовой базой и над вашим будущим, будут вам благодарны. Перечисления - отличный способ избежать и того, и другого!