отладка кода в XCode SwiftUI

Глава 2. Отладка кода

Отладка кода

Оглавление

Введение

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

В компьютерном мире ошибки обычно называют – баги(bugs). Это название появилось еще в те времена, когда компьютеры были большими и для их работы и программирования применялись физические переключатели. В один день компьютер перестал работать и когда техник открыл его, он нашел мотылька, который застрял в переключателе и мешал нормальной работе компьютера. Именно с этого момента ошибки стали называть багами, а поиск и исправление ошибог стали называть дебаггингом(debugging).

Ошибки можно разделить на 3 группы:

  • синтаксические ошибки. Имеет место ошибка синтаксиса, опечатки в синтаксисе, именах переменных, именах функций, именах классов или напечатаны некорректные символы(например при  конкатенции слов используется знак * вместо +)
  • логические ошибки. Имеют место когда код корректен с точки зрения синтаксиса, но логика Вашего кода нарушена. Например при нажатии на кнопку воспроизведения трека, происходит переход к экрану настроек.
  • ошибки исполнения. Встречаются когда в работе программы происходят непредвиденные ситуации, например пользователь вводит некорректные данные или другое приложение мешает работе Вашего приложения.

Синтаксические ошибки самые легкие в плане поиска и исправления. Потому что обычная опечатка в имени переменной, или Swift команды видна редактором XCode. Например если мы введем в редакторе ключевое слово var или let, XCode подсветит ключевое слово розовым цветом.(или тем цветом, который вы дополнительно укажете в настройках XCode).

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

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

XCode pop up hint

Синтаксические ошибки не позволяют выполнить сборку и запуск проекта. В этом плане они считаются самыми простыми к исправлению и поиску. Среда XCode при попытке запуска или сборки проекта обязательно высветит список имеющихся ошибок и их расположение в коде.

xcode mistake code

xcode build failed

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

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

И в заключении, самые сложные ошибки для поиска и отладки – это ошибки исполнения. Или их еще называют ошибки времени исполнения. Их отличие от логических ошибок заключается в следующем. Логические ошибки предсказуемы. Например если пользователь вводит правильный логин и пароль, а приложение не открывает главный экран, значит в коде присутствует логическая ошибка. То есть она происходит КАЖДЫЙ РАЗ при выполнении именно этого действия.

Ошибки времени исполнения более коварны. Потому что они не всегда предсказуемы. Например Ваше приложение стабильно работает на всех моделях Iphone, но при запуске на IPad ваше приложение терпит крах. В данном случае ошибка может быть в ошибке поддержки разных экранов Вашим приложением. Или например напоминание в Вашем приложении не срабатывает после того, как пользователь сменит часовой пояс или после перевода часов на весеннее время. Такая ошибка очень сложна в отслеживании и отладке.

Типичные проблемы ошибок времени исполнения: нехватка памяти, запуск приложения на разных размерах экранов или разрешениях, запуск в разных версиях ОС. Так как ошибки времени исполнения возникают случайно или при изменении конфигурации устройства, они более раздражающие и сложны в поиске и исправлении. Также проблема может быть в попытке выполнить сохранение файла при отсутствии разрешения на это действие. или при отсутствии свободной памяти, или при попытке отправить данные не через мобильную сеть, а через Wi Fi соединение.

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

В разработке программ применяют очень интересный метод Утенка. Если какая то часть кода не работает так, как Вы это задумали, Вы ставите игрушечного утенка на стол рядом с ноутбуком и объясняете ему как это код работает строчка за строчкой. В процессе объяснения вы выполняете типичную задачу по Code Review.  В большинстве случаев этот метод срабатывает и Вы находите ошибку в коде.

Простая отладка

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

Если Вы предполагаете, какая именно часть кода вызывает проблемы, у Вас есть 2 грубых решения. Первое решение заключается в том, что Вы удаляете подозрительный участок кода, перенеся его например в тестовый редактор Atom. Если после этого проблема исчезает, Вы можете вернуть код обратно и приступать к поиску ошибки. Если же проблема не исчезла, Вам придется все также брать следующие участки кода и удалять уже их. Это весьма кропотливая работа с низким КПД.

Второе решение заключается в комментировании кода. Для этого есть 3 решения:

– Добавить символы // перед строкой кода, которую вы хотите закомментировать

– Окружить подозрительный участок кода символами /* */

– Выбрать интересующие нас строки и комбинацией клавиш Cmd + / закомментировать этот код. Среда XCode автоматически добавит в начало всех выделенных строк символы комментариев //. Также это действие можно выбрать вручную выбрав Editor – Structure – Comment Selection

comment code in Xcode

Цвет закомментированных строк всегда можно изменить в настройках среды XCode.

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

Посмотрим как это делается. Создадим простой проект. Он будет называться Chapter 2. Все примеры из этой главы далее будут отрабатываться именно в этом проекте. Вы можете его скачать здесь.

import SwiftUI

struct ContentView: View {
    @State var message = "Velocity in meters per second "
    let velocity : Float = 20.0
    var body: some View {
        VStack {
            Text(message+"\(velocity)")
            Text("Velocity in kilometer per hour: \(velocityToKilometerPerHour(velocityMpS: velocity))")
        }
        .padding()
    }
    
    func velocityToKilometerPerHour(velocityMpS: Float) -> Float {
        var velocityKpH: Float
        velocityKpH = velocityMpS * 3.6
        return velocityKpH
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

 

В этом коде нет ничего сверхъестественного. Мы переводим скорость из единицы измерения метры в секунду в километр в час. Если этот код вызывает у Вас непонимание, в частности что такое аннотация @State, ключевые слова let и var, Вам необходимо ознакомиться с нашей большой работой – Основы языка Swift. Теперь обратим внимание, что же мы видим на панели Canvas:

Velocity in meters per second 20.0

Velocity in kilometer per hour: 72.00000

Это не совсем то, что мы хотим видеть. Несмотря на то, что вычисления произведены правильно, форма вывода оставляет желать лучшего. Как нам убрать лишние нули в выводе? Давайте для начала добавим в код функцию print и отследим вывод переменной velocityMpS:

Отладка кода в XCode

Мы видим в консоли, что входной параметр содержит всего 1 знак после запятой, следовательно проблема не в нем. Тогда просто изменим возвращаемый параметр нашей функции c типа Float на String, тем более в задаче вывода не стоит требуемая точность и оставим количество знаков после запятой равным 2:

    func velocityToKilometerPerHour(velocityMpS: Float) -> String {
        print(velocityMpS)
        var velocityKpH: Float
        velocityKpH = velocityMpS * 3.6
        return String(format: "%.2f", velocityKpH)
//        return velocityKpH
    }

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

И не забывайте, что функция print работает только при запуске в симуляторе. При запуске на реальном устройстве или в режиме отображения Live Preview отображение функции print  в консоль не работает.

Отладка в XCode Debugger

Когда Мы ищем ошибки в коде используя команду print и комментарии, признаемся откровенно – это довольно трудоемкий и неэффективный процесс. Использование команды print для поиска ошибок в большом приложении будет весьма трудоемкой, скучной и нудной задачей. Тем более надо помнить, что удаление/комментирование лишнего кода тоже окажется довольно трудоемкой задачей.

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

  • точки останова
  • просмотр значений переменных

К сожалению точки останова и просмотр значений переменных работает только в Симуляторе и не работает когда Вы используете Live Preview в панели Canvas.

Использование точек останова

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

Например, если Ваша программа переводит значения скорости из метры в секунду в километры в час, и Вы видите что значение перевода 20 м/с составляет -800 км/ч, значит что то работает неправильно в коде. Устанавливая точки останова в коде, Вы можете смотреть значения переменных в каждой точке, а также смотреть как Ваш код производит операции с этими значениями переменных. Таким образом, найдя место где Ваш код работает неправильно, Вы можете точно определить область, где Ваш код нуждается в исправлении.

Вы можете установить точки останова следующим образом:

  • Путем клика мышью или тачпадом слева от кода где Вы хотите установить точку останова(см. скринштот ниже)
  • Установив курсор на интересующую нас строку где мы хотим установить точку останова и нажав Cmd + \
  • Остановиться на интересующей нас строке кода и выбрать в редакторе – Debug – Breakpoints – Add Breakpoint

Среда XCode по умолчанию подсвечивает синим цветом точки останова. Как видно на картинке ниже, мы установили 2 точки останова.

Точки останова в среде XCode

Проход кода в режиме отладки

После того как Вы запустили Ваше приложение в эмуляторе, Вы можете осуществлять проход Вашего кода по каждой строке используя команду Step. В среде XCode есть множество вариантов команды Step, мы же остановимся на 3 наиболее важных

  • Step over
  • Step into
  • Step out

Разберем каждую по отдельности. Команда Step over означает переход к следующей строке кода. Применительно к скринштоту свыше при остановке на 23 строке кода, это будет означать переход к 24 строке.

Команда Step Into работает схожим образом. Но есть одно кардинальное отличие. Когда среда XCode перейдет к функции или вызову метода, при выборе Step Into отладчик перенесет отладку к первой строке вызываемой функции. Например  в нашем примере при остановке на 16 строке кода и выборе команды Step Into, следующая точка останова будет на 22 строке кода.

Соответственно команда Step Out позволяет преждевременно выйти из функции или метода, в которые мы зашли используя команду Step Into обратно к тому месту, где мы выбрали команду Step Into. Таким образом мы возвратимся обратно к 16 строке кода из нашего примера.

Все 3 команды Step используются когда приложения остановится в точке останова. Используя команды Step, можно провести анализ всех интересующих участков кода, строка за строкой и увидеть какие именно значения сохраняются в различных переменных или увидеть результаты выполнения тех или иных функций.

Отладка ПО с использованием точек останова является наиболее предпочтительным путем разработки, потому что добавление или удаление точек останова – это быстрая процедура, не нарушающая структуру и процесс понимания кода. В отличии от поиска и удаления всех команд print и комментариев, удаление точек останова в проект выполняется предельно просто. Теперь рассмотрим как это выглядит на практике. Вернемся к нашей функции velocityToKilometerPerHour.  

func velocityToKilometerPerHour(velocityMpS: Float) -> String {
        print(velocityMpS)
        var velocityKpH: Float
        velocityKpH = velocityMpS * 3.6
        return String(format: "%.2f", velocityKpH)
}

Изменим строку velocityKpH = velocityMpS * 3.6, поменяв коэффициент 3.6 на 4. Поставим в  точку останова в месте вызова функции velocityToKilometerPerHour – Comand + \ Запустим наше приложение в эмуляторе и увидим пустой экран. Это произойдет потому что выполнение приложения остановилось на установленной нами точке. Интерсующая нас при этом строка выделится зеленым цветом. После нажмем клавишу F7(Step Into). Значения интересующих переменных мы можем увидеть в панели отладки

отладка кода в XCode SwiftUI

После завершения отладки достаточно выбрать команду Debug – Deactivate breakpoints. Установленные точки останова отобразятся потускневшими и при последующем запуске приложения в симуляторе, приложение больше не будет останавливаться для отладки.

Удаление точек останова осуществляется путем перетаскивания точки влево или вправо либо выбором команды Удалить все точки остановка – Debug – Breakpoints – Delete all breakpoints.

Управление точками останова

В среде XCode нет лимита на количество используемых точек останова. Поэтому Вы можете использовать их столько, сколько Вам понадобится для поиска ошибки в коде. Поэтому Вы вполне можете столкнуться с ситуацией, когда Вы забыли сколько и где вы установили точек. Для этого Apple в IDE XCode реализовала Навигатор точек останова(BreakPoint Navigator). 

Открыть навигатор точек останова можно 3 способами:

  • выбрать в редакторе View-Navigators-Breakpoints
  • комбинация клавиш Cmd+8
  • или нажатием на иконку Show Breakpoint Navigator в панели Navigator.

Навигатор точек останова содержит в себе список все точек установленных в Вашем проекте. Он содержит в себе список всех файлов исходных кодов с установленными точками и номер строки исходного файла.

панель Navigator Breakpoint

XCode. Использование символьных точек останова

Когда мы хотим установить точку останова в коде, нам необходимо поместить ее вручную в коде в том месте, где мы хотим провести отладку кода. Этот процесс похож на процесс угадывания места в коде, где проблема может скрываться и необходимость использования различных команд – Step Into, Step Out… для входа и выхода в отлаживаемые методы, строка за строкой.

Для решения этой небольшой проблемы, XCode предлагает символические точки останова. Давайте рассмотрим подробнее. Символические точки останова запускают процесс отладки функции или метода только в случае наступления заданных условий для отладки. Например мы можем указать необходимость входить в отлаживаемый метод один раз в 10 запусков. То есть отладка метода будет произведена только на 11 вызов отлаживаемого метода. В наших простых примерах это не особо необходимо и заметно, но в дальнейших главах мы рассмотрим многопоточное программирование, циклы, запуск и проигрывание аудио и видео. Именно в этих задачах данный функционал весьма и весьма пригодится Вам в будущем.

Для создания символьной точки останова необходимо указать следующее:

  • Symbol – имя функции, которую мы собираемся отлаживать
  • Module –  имя файла содержащего интересующую нас функцию, определенную в пункте выше
  • Ignore – число запусков функции от 0 до необходимого нам количества, которое необходимо пропустить отладчику перед входом в отладку

Рассмотрим как работают символьные точки останова.

  • Выбираем Debug – Breakpoints – Create Symbolic Breakpoint  или нажимаем комбинацию клавиш Option+Command+\

Отладка кома символьные точки останова

  • В поле Symbol мы введем имя нашей функции – velocityToKilometerPerHour. 
  • В поле Field мы введем имя файла нашего исходного кода. В нашем случае это ConvertView.swift Конкретно в нашем примере это делать необязательно, так как в проекте однозначно нет больше никаких других функций с данным именем. Но рассказать об его назначении необходимо.
  • Поле Ignore мы тоже в данном случае не трогаем. Оно необходимо для случаев, когда необходимо указать какое количество запусков функции необходимо пропустить отладчику.
  • После этого необходимо запустить наш проект в эмуляторе.
  • Удалять точку останова можно через меню удалить все точки или в навигаторе точек останова.

Symbolic Breakpoints

Также Вы можете установить точку останова другим способом без указания конкретной строки кода. Для этого мы создаем Exception breakpoint. Обычно если приложение рушится, XCode отображаем текст критической ошибки, и нам нужно проделать определенный алгоритм действий чтобы понять что и как сломалось. При установке точки останова Exception, XCode распознает строку кода, где произошла ошибка и Вы сможете исправить ее.

Использование условных точек останова

Точки останова предназначены чтобы останавливать программу каждый раз в конкретной строке кода. Конечно, использование символьных точек останова предоставляет такой функционал, что можно хоть раз в 100 или даже 1000 запусков осуществлять остановку приложения для отладки. Как же могло быть хорошо, если бы мы могли запускать отладку кода только в случае выполнения определенных событий, например как будет себя вести программа если получит с сервера не 200 код ответа, а 403 или 500. И именно такой функционал реализован средой XCode! Мы можем запускать отладку именно в том случае, если наступает выполнение условия, заложенного нами. Рассмотрим подробнее, как это делается.

  • установим точку останова на строке

            velocityKpH = velocityMpS * 3.6

  • в навигаторе точек останова выберем нашу точку и в контекстном меню выберем пункт –  Edit Breakpoint.
  • установим значение velocityMpS>21. Сейчас у нас в коде прописано значение 20 и значит при запуске приложения не будет никаких прерываний на отладку. Запускаем и убеждаемся в правильности вывода.

XCode Conditional breakpoint

  • теперь установим значение переменной velocity равной 22 и снова запустим приложение.

Отладка кода создание условных точек останова. Condition breakpoint XCode

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

отладка кода swiftUI. Заключение

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

Самый простой способ поиска ошибок – это использование команды print и комментирование подозрительных участков кода. Более правильным при поиске и исправлении ошибок считается использование встроенного в среду XCode отладчика. С помощью отладчика Вы можете установить точки останова в коде и просматривать какие значения сохраняются в Ваших переменных.

Условные точки останова, выполняют остановку приложения для отладки только в случае наступления определенного условия. Символьные условия останавливают приложение только в случае вызова указанного метода или функции. После того как iOs программа остановится в точке останова, Вы можете продолжить отладку кода используя различные варианты команды Step. Команда Step Into указывает отладчику, что необходимо войти в функцию или метод для отладки, а команда Step Out приказывает выйти отладчику из функции на уровень выше к коду, который вызвал этот метод.

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

1 thought on “Глава 2. Отладка кода

Leave a Reply

Please disable your adblocker or whitelist this site!