Добро пожаловать в шестую часть серии Mobiletuts + Beginning для iOS. Эта часть будет посвящена основам отладки Xcode. Он будет включать в себя небольшую часть теории отладки программного обеспечения и практического приложения для демонстрации использования точек останова и отладчика Xcode. Статья завершится некоторыми общими советами и рекомендациями, а также списком полезных ресурсов, доступных для продолжения обучения.
Screencast:
Проблемы с просмотром СМИ выше? Получите доступ к полной, высококачественной версии этого видео в оригинальном формате MOV .
Учебное пособие:
Вместо того, чтобы создавать новое приложение специально для этого урока, я взял приложение FortuneCrunch, которое мы создали во второй части этой серии, и я ввел ряд различных ошибок в исходный код. Загрузите BrokenCrunch, сломанную версию FortuneCrunch, сопровождающую этот пост , и я покажу, как использовать инструменты отладки Xcode.
Теория отладки
Прежде чем мы начнем отладку BrokenCrunch, давайте немного поговорим о теории отладки программного обеспечения. В целом, ошибки программного обеспечения (также известные как «ошибки») можно классифицировать следующим образом:
- Ошибки компиляции
- Ошибки во время выполнения
- Логические ошибки
Ошибки компиляции
Как видно из названия, при компиляции исходного кода приложения возникает ошибка времени компиляции. В XCode это происходит, когда вы выбираете «Build and Run» или «Build and Debug» для запуска приложения на устройстве или симуляторе. Когда возникает ошибка времени компиляции, это буквально препятствует запуску вашего приложения. Как мы увидим, ошибки в этой категории могут возникать из-за бессмысленных или неправильных синтаксических операторов или из-за проблем, возникающих на этапе компоновки вашей сборки приложения. Вообще говоря, ошибки времени компиляции — это самая простая из трех категорий, которую нужно разрешить, потому что компилятор обычно выдает значимое сообщение об ошибке или предупреждающее сообщение, которое предупредит вас о природе проблемы.
Ошибки во время выполнения
Ошибки во время выполнения возникают после того, как ваше приложение было скомпилировано и запущено в Simulator или на устройстве. Сбой приложения или утечка памяти, возникающая в результате плохого управления памятью объекта, является примером ошибки во время выполнения.
Логические ошибки
Логическая ошибка возникает во время фазы выполнения приложения и приводит к неожиданному или нежелательному поведению приложения, которое вступает в конфликт с намеченным результатом разработчика программного обеспечения или заинтересованного лица проекта. Хорошим примером логической ошибки является математическая формула, которая была реализована неправильно. Рассмотрим теорему Пифагора:
Если разработчик программного обеспечения непреднамеренно реализовал эту формулу как:
Результатом будет логическая ошибка, но, скорее всего, она не приведет к сбою приложения. Это то, что делает логические ошибки настолько опасными: приложение может казаться «безошибочным» для разработчика, в то время как на самом деле выдает неверный или нежелательный вывод.
Отладка BrokenCrunch
Имея эти теоретические знания, откройте BrokenCrunch и начнем. После загрузки нашего примера приложения выберите « Build»> «Build and Debug». Вы заметите, что приложение не запускается, и компилятор выдал ряд ошибок. Чтобы просмотреть результаты попытки компиляции, выберите « Сборка»> «Результаты сборки» .
Выбор перечисленных ошибок приведет вас непосредственно к строке кода, где сообщается об ошибке. Однако важно помнить, что число ошибок, сообщаемых компилятором, и номера строк этих ошибок следует рассматривать как «лучшее предположение» о том, что не так с вашим приложением, а не как окончательное заявление.
Фактически, одна простая синтаксическая ошибка может привести к тому, что компилятор сообщает о множественных ошибках, которые, по-видимому, не связаны с проблемой. В качестве примера рассмотрим строку ошибки «Ожидаемая скобка перед setImage» . Если вы изучите данную строку, вы обнаружите, что синтаксис идеален. Как оказалось, проблема здесь не в сообщаемой строке, а в строке чуть выше. Ты видишь проблему?
Оператор NSLog()
не заканчивался точкой с запятой. Это означает, что компилятор не знает, что вы намеревались завершить строку после последней круглой скобки, и просматривает все от NSLog
до заключительной закрывающей скобки и точки с UIControlStateNormal
после UIControlStateNormal
как один оператор.
Добавьте точку с запятой, чтобы завершить оператор NSLog
:
NSLog (@ "In crunchCookie");
Сохраните исходный файл и снова нажмите «Build and Debug». Две из трех первоначально отображенных ошибок теперь должны быть устранены.
Далее выберите ошибку «Нет объявления свойства» . Как видите, эта ошибка сообщает о том, что свойство, которое мы пытаемся синтезировать, не существует. Чтобы убедиться в этом, откройте файл FortuneCrunchViewController.h, где должно было быть объявлено свойство. Если вы изучите строку 17, синтаксис правильный, но у нас есть несоответствие между объявленным нами свойством и тем, которое мы пытаемся синтезировать. Objective-C — это регистрозависимый язык, означающий, что буква C в cookie должна быть написана заглавными буквами, чтобы соответствовать свойству, которое мы пытаемся синтезировать. Обновите объявление свойства в заголовочном файле следующим образом:
@property (nonatomic, retain) IBOutlet * fortuneCookieButton;
Сохраните исходный файл, соберите и отладьте еще раз. На этот раз, вместо того, чтобы открывать результаты сборки из Build> Build and Debug , просто щелкните значок ошибки в правом нижнем углу Xcode.
Один шаг вперед, четыре шага назад. Ошибка, касающаяся строки свойств синтеза, исчезла, но у нас есть совершенно новый список ошибок. Что произошло?
Это хорошее время, чтобы обратить внимание на различные фазы, отображаемые в окне результатов сборки:
Обратите внимание, что у нас есть одно предупреждение в разделе «Compile» вывода результатов сборки. Это тот же раздел, в котором сообщалось о наших предыдущих ошибках. Теперь, когда предыдущие три ошибки были устранены, мы смогли перейти от фазы компиляции к фазе компоновки нашей сборки приложения, и все новые ошибки ошибки связывания. Когда вы сталкиваетесь с ошибкой компоновки, обычно это происходит потому, что вы пытаетесь использовать функции из инфраструктуры, которую вы на самом деле не включили в свое приложение. В этом случае результаты сборки ссылаются на функцию с именем _UIApplicationMain
в файле _UIApplicationMain
Main.o — это скомпилированная версия main.m с машинным кодом. Давайте посмотрим на исходный код в этом файле. В строке 13 вы можете увидеть вызов функции для UIApplicationMain
:
int retVal = UIApplicationMain (argc, argv, nil, nil);
UIApplicationMain
— это центральная функция для каждого приложения iOS, но как вы можете узнать больше об этом и выяснить, в какую инфраструктуру он включен? К счастью, iOS SDK поставляется с отличной документацией. Если вы удерживаете нажатой кнопку «Option» (или «Alt») и дважды щелкаете по имени функции, вы запускаете реферат из официальной документации iOS SDK, где обсуждается эта функция. Нажмите на значок «книга» в правом верхнем углу, чтобы просмотреть всю доступную документацию. Вы можете видеть, что при этом была запущена справочная документация по функциям для инфраструктуры UIKit. Бинго, у нас есть недостающие рамки. Однако, прежде чем мы добавим инфраструктуру в проект, давайте рассмотрим другой метод, который вы могли бы использовать для определения происхождения UIApplicationMain
.
Закройте окно документации. Теперь, удерживая нажатой командную кнопку, дважды щелкните функцию UIApplicationMain
. Теперь вы смотрите на источник UIApplication.h, файл объявления заголовка, который содержит UIApplicationMain
функции UIApplicationMain
. Если вы прокрутите до верхней части окна, вы увидите, что этот файл импортирует несколько других заголовков UIKit, и что комментарий вверху содержит имя фреймворка «UIKit».
Давайте перейдем к решению этих ошибок компоновки с помощью инфраструктуры UIKit. Для этого щелкните правой кнопкой мыши или удерживайте нажатой клавишу Control на папке Frameworks на панели «Группы и файлы» и выберите « Добавить»> «Существующие платформы» . Найдите фреймворк UIKit и нажмите «Добавить». Чтобы протестировать нашу работу, снова выберите «Построить и отладить».
Как видите, симулятор успешно запущен и мы можем просматривать наше приложение. Это означает, что мы исправили все ошибки времени компиляции в нашем приложении.
Идите дальше и нажмите печенье с предсказанием. , .Как вы видите, щелчок cookie приводит к ошибке во время выполнения, и приложение падает. Сообщение, отображаемое в левом нижнем углу экрана Xcode, не очень полезно, поэтому давайте внимательнее рассмотрим, открыв консоль.
Консоль отображает как стек вызовов того, что происходило при выполнении нашей программы во время сбоя, так и более подробное объяснение: «Завершение приложения из-за необработанного исключения. .FortuneCrunchViewController cookieCruncher: нераспознанный селектор, отправленный экземпляру». Это сообщение означает, что наша кнопка вызывает неправильный селектор для события, которое мы запустили, щелкнув файл cookie. Поскольку интерфейс для FortuneCrunch был построен в Интерфейсном Разработчике, давайте откроем XIB-файл Интерфейсного Разработчика для «FortuneCrunchViewController», чтобы более подробно рассмотреть.
Нажмите кнопку «cookie» и щелкните элемент управления или щелкните правой кнопкой мыши, чтобы просмотреть список подключенных действий:
Вы можете видеть, что событие Touch Up Inside ссылается на несуществующую цель, обозначенную желтым текстом. Удалите несуществующую цель «cookieCruncher» и повторно подключите touchUpInside к владельцу файла, выбрав цель «crunchCookie», которая появляется в раскрывающемся списке. Сохраните свою работу в Интерфейсном Разработчике, переключитесь обратно в Xcode и перезапустите приложение.
Повторное нажатие на файл cookie состояния приводит к ошибке во время выполнения. На этот раз консольное сообщение не очень полезно, оно просто отображает «EXC_BAD_ACCESS» .
Посмотрите еще раз на результаты сборки, выбрав « Сборка»> «Результаты сборки» . Вы заметили предупреждение раньше? Предупреждения компилятора часто указывают на потенциальную ошибку во время выполнения, но поскольку нет ничего неправильного в фактическом синтаксисе строки, для которой выдается предупреждение, компилятор все еще может успешно построить приложение. Конечно, бывают случаи, когда предупреждение компилятора является «ложным флагом» и не приводит к ошибке во время выполнения, а превышает 95% времени, если компилятор выдал предупреждение, что вы делаете что-то не так.
Нажмите на предупреждение, чтобы перейти к строке в исходном коде, где это произошло.
Предупреждение относится к несовместимым типам указателей. Ты видишь проблему? Метод imageNamed ожидает объект NSString, но эта строка кода снабжает метод литеральной строкой в стиле C. Добавьте символ «@», чтобы сделать строку Objective-C:
[fortuneCookieButton setImage: [UIImage imageNamed: @ "cookie-closed.png"] forState: UIControlStateNormal];
Сохраните ваш прогресс и снова запустите приложение.
На этот раз, когда вы нажимаете cookie-файл с предсказаниями, вы сталкиваетесь с логической ошибкой: приложение не падает, и ярлык «Happy iPhone Hacking» отображается, как и ожидалось, но фоновое изображение остается в виде закрытого cookie-файла.
Чтобы это исправить, давайте взглянем на функцию, отвечающую за переход: (IBAction)crunchCookie
. Строка 19 отвечает за изменение фонового изображения, и вы можете видеть, что оно устанавливает новое фоновое изображение в «cookie-closed.png». Если вы посмотрите на cookie-closed в папке Resources, вы увидите, что на самом деле это то же изображение, которое отображается при первой загрузке приложения. Нам нужно изменить эту строку для перехода к «cookie-crunched.png»:
[fortuneCookieButton setImage: [UIImage imageNamed: @ "cookie-crunched.png"] forState: UIControlStateNormal];
Создайте и снова запустите приложение. , .и теперь нажатие на cookie приводит к ожидаемому фоновому изображению с меткой, отображаемой правильно.
Поздравляем! Вы только что прошли процесс исправления ошибок времени компиляции, ошибок времени выполнения и логических ошибок в приложении. Все это время мы едва пользовались мощными инструментами отладки, доступными вам в Xcode.
Чтобы продолжить изучение более продвинутых инструментов отладки, давайте попробуем расширить приложение FortuneCrunch, чтобы сделать его немного более интересным. Вместо того, чтобы отображать статическую строку «Счастливого взлома iPhone!» Каждый раз, когда cookie-файл хрустит, давайте создадим массив из нескольких значений NSString
которые могут отображаться.
Вернитесь к Xcode и откройте файл FortuneCrunchViewController.h. Добавьте следующий элемент данных:
NSArray * fortunes;
Этот массив будет использоваться для хранения наших случайных строк состояния.
Теперь добавьте следующую сигнатуру метода:
- (NSString *) generateRandomFortune;
В этой строке будет объявлен новый метод в нашем классе, который будет использоваться для выбора случайного состояния из нашего массива состояний.
Затем переключитесь на FortuneCrunchViewController.m. Поскольку этот класс будет инициирован из нашего файла XIB, нам нужно переопределить метод initWithCoder
и выделить массив, который мы объявили в файле .h, инициализируя его некоторыми новыми состояниями:
- (ID) initWithCoder: aDecoder { self = [super initWithCoder: aDecoder]; если (сам) { fortunes = [[NSArray alloc] initWithObjects: @ «Тот, кто бросает грязь, теряет почву»., @ «Закрытый рот не собирает ног»., @"Помогите! Я заключенный в пекарне! », Ноль]; } вернуть себя; }
Теперь, когда мы создали новый NSArray
, не забудьте выпустить его в методе dealloc
:
- (недействительными) dealloc { [релиз удачи];
Давайте перейдем к кодированию функции generateRandomFortune
:
- (NSString *) generateRandomFortune { int selected_index = arc4random ()% 3 * 10; return [fortunes objectAtIndex: selected_index]; }
Эти строки просто генерируют новый случайный индекс, который мы будем использовать для возврата соответствующей строки состояния.
Наконец, измените метод crunchCookie
чтобы использовать одно из наших случайных состояний вместо статического текста «Счастливый взлом iPhone!»:
fortuneLabel.text = [self generateRandomFortune];
Создайте и запустите приложение после сохранения этих изменений. Если вы нажмете на cookie, вы создадите ошибку во время выполнения. Чтобы выяснить, почему это происходит, мы будем использовать отладчик Xcode и пользовательские точки останова.
Точка останова — это флаг, который сигнализирует вашему приложению, что выполнение программы должно «приостановиться» при достижении строки с точкой останова. Запуск вашего приложения в «режиме сборки и отладки» позволяет вам использовать точки останова. Чтобы установить точку останова, просто щелкните в редакторе «желоб» на строке, которую вы хотите вызвать точку останова. Чтобы выяснить, что происходит в нашем приложении, мы собираемся установить точку останова в строке NSLog
сразу после вызова метода crunchCookie:
Создайте и отладьте приложение с этой новой точкой останова.
После загрузки приложения щелкните файл cookie. Если вы посмотрите в левом нижнем углу Xcode, вы увидите сообщение о состоянии «Остановлен в точке останова 1». Это означает, что отладчик успешно остановил выполнение программы на заданной вами точке останова. Вы также заметите, что красная стрелка указывает текущую строку выполнения, где отладчик «приостановил» программу.
Итак, что вы можете сделать с отладчиком? Больше, чем можно описать в одном уроке. Однако на этом этапе вы можете предпринять три основных действия: шаг за шагом, шаг вперед и выход. Все эти опции доступны вам в строке меню отладчика кода.
Если вы нажмете кнопку «перешагнуть» в меню отладчика кода, вы заметите, что выполнение программы продолжается до следующей строки. «Step over» просто продолжит выполнение по одной строке за раз в текущем методе, но не будет следовать за выполнением вашего кода, если он разветвляется на другой метод. Если вы действительно хотите следить за выполнением кода при вызове других методов в вашем коде, вам нужно использовать кнопку «войти в».
Как вы можете видеть, шаг вперед фактически привел нас к методу generateRandomFortune
, который именно то, что мы хотим. Снова нажмите « arc4random()
», чтобы увидеть, что происходит, когда arc4random()
. Разве не было бы хорошо, если бы мы знали, что переменная selected_index только что была установлена? К счастью, мы можем! Одной из лучших особенностей использования отладчика является возможность просто навести курсор мыши на переменные, чтобы быстро увидеть их значение.
Ясно, что значение chosen_index
намного больше, чем длина нашего массива. В отличие от некоторых других языков программирования, используемая нами функция рандомизации возвращает целое число, поэтому нет необходимости преобразовывать десятичное число в целое, умножая значение на 10. Обновите строку следующим образом:
int selected_index = arc4random ()% 3;
Мы закончили вносить изменения в эту функцию, поэтому используйте кнопку «Выход», чтобы выйти из этой crunchCookie
и вернуться в crunchCookie
. Обратите внимание, что хотя мы этого не видели, остальная часть функции выполнялась как обычно.
Наконец, обратите внимание на кнопку «Активировать / Деактивировать» точку останова и кнопку «Продолжить выполнение» в строке меню отладчика кода. «Продолжить выполнение» просто позволит продолжить выполнение программы в обычном режиме. Вы можете думать об этом как о кнопке «отменить». Идите и нажмите это сейчас.
Прежде чем мы перейдем к отключению точек останова, необходимо решить еще одну проблему: то, что вы только что испытали, называется «отладчик в коде». Он очень мощный, но есть также два других режима отладки: полное окно отладчика и перспектива мини-отладчика.
Чтобы получить доступ к полному окну отладчика, щелкните значок «отладка» в строке меню отладчика кода. Это окно содержит значительно больше информации, чем встроенный отладчик. Слева у вас есть трассировка стека, отображающая контекст выполнения программы (у вас также есть возможность выбрать любой из порожденных в данный момент потоков). Справа вы можете быстро увидеть различные переменные, хранящиеся в памяти. Выбор другой подписи стека вызовов изменит ваше представление в отладчике. Вы можете изменить макет окна отладчика, выбрав « Выполнить»> «Отладка дисплея» .
Наконец, мини-отладчик — это еще одна перспектива отладки, доступная вам. Я редко использую эту точку зрения, но она доступна вам из Run> Mini-Debugger .
Поскольку мы только что исправили ошибку, внесенную в наш случайный код состояния, нам больше не нужен включенный отладчик. Отключить точки останова. Однако, прежде чем мы снова создадим приложение, давайте настроим размер шрифта нашей метки состояния.
Откройте Interface Builder, выберите метку и измените шрифт в Инспекторе на Arial Black, 9 точек, а затем установите флажок «Подгонка под размер» и измените минимальный размер шрифта на 6 пунктов. Теперь соберите и запустите наш проект снова.
Вуаля! Наше приложение теперь работает так, как мы планировали.
Советы и подсказки по отладке
Теперь, когда вы познакомились с основами использования отладчика в XCode, рассмотрите возможность применения следующих рекомендаций в повседневной работе:
Тест в симуляторе и на физическом устройстве
Хотя симулятор является полезным методом тестирования приложения на этапе разработки вашего продукта, он не является заменой для тестирования на физическом устройстве. Это связано с тем, что симулятор и устройство iOS отличаются по важности и фундаментальности. Например, симулятор, очевидно, работает в OS X, а файловая система в OS X не чувствительна к регистру. Однако файловая система на iOS чувствительна к регистру. Так что ссылка на файл cookie-CRUNChed.png
вместо cookie-crunched.png
будет отлично работать в симуляторе, но не будет работать на реальном устройстве iOS. Еще одним ключевым соображением является то, что симулятор имеет гораздо больше доступной памяти, чем фактическое устройство, и этот факт часто будет сильно влиять на пользовательский опыт. Наконец, не все приложения по умолчанию, которые поставляются с iOS, доступны в симуляторе, включая приложения «Карты» и «Магазин приложений». Это означает, что вы не сможете протестировать код, который генерирует маршруты движения, с помощью приложения «Карты» или перекрестного продвижения приложений в App Store на симуляторе. Это лишь некоторые из существующих различий. Я настоятельно рекомендую тестировать на как можно большем количестве физических устройств iOS, работающих под максимально возможным количеством различных целевых версий iOS.
Используйте Clang Static Analyzer
Clang Static Analyzer — это специальный инструмент статического анализа C / Objective-C, который поставляется с Xcode. Этот инструмент может проанализировать ваш код на наличие ошибок или несоответствий, которые в противном случае могли бы остаться незамеченными.
Хотя детали работы анализатора выходят за рамки данной статьи, его использование, к счастью, очень просто. Чтобы выполнить статический анализ вашего кода, просто выберите « Построить»> «Построить и проанализировать» в меню сборки XCode.
Если вы хотите узнать больше о том, как работает опция «Построить и проанализировать», вы можете прочитать о Статическом анализе кода и Clang Static Analyzer онлайн.
Установите глобальную точку останова на objc_exception_throw
В этом уроке мы узнали о том, как работают точки останова, установив точки останова для конкретных проектов в нашем коде. В дополнение к определенным точкам останова проекта, Xcode также позволит вам установить «глобальные» точки останова, которые будут применяться ко всем проектам iOS, которые вы создаете в Xcode. Установка глобальной точки останова на objc_exception_throw
позволит вам автоматически запускать отладчик всякий раз, когда возникает исключение (тип ошибки во время выполнения). Чтобы узнать больше о преимуществах этого подхода и о том, как реализовать его в коде, обратитесь к моему быстрому совету iOS по objc_exception_throw и глобальным точкам останова .
Относитесь к предупреждениям как к ошибкам
Как упоминалось ранее в этом руководстве, подавляющее большинство выдаваемых предупреждений компилятора должно быть разрешено до запуска проекта, и в действительности никогда не должно быть сценария, когда код, генерирующий предупреждения компилятора, должен оставаться неизменным, чтобы приложение функционировало должным образом. , Следовательно, некоторые программисты рекомендуют рассматривать все предупреждения компилятора как ошибки, заставляя их разрешать их как часть обычного процесса разработки.
Для всех случаев, за исключением нескольких, я поддерживаю эту идею, и Xcode облегчает реализацию. Перейдите в Project> Edit Project Settings и затем выберите вкладку Build. Введите «Обрабатывать предупреждение» в строке поиска, и вы увидите логическое значение «Обрабатывать предупреждения как ошибки». Установите этот флажок, чтобы включить эту функцию.
Сборка и проверка перед отправкой в App Store
Еще один шаг, который вы можете предпринять, чтобы увеличить вероятность того, что ваше приложение будет принято в первый раз, когда вы отправляете его в iTunes Store, — это включить флаг «Сборка и проверка» в настройках сборки проекта. Введите «validate» в поле поиска на вкладке сборки параметров проекта, а затем выберите «Validate Build Product». Этот параметр запустит некоторые тесты, выполненные рецензентами Apple, что позволит вам избежать отклонения в App Store. Следует отметить, что установка этого флажка не является гарантией того, что ваше приложение пройдет проверку App Store, но это лучше, чем ничего.
Дополнительные инструменты отладки
В дополнение к консоли, результатам сборки и отладчику, есть несколько других замечательных инструментов отладки и оптимизации, о которых вам следует знать в своих усилиях по разработке. Для дальнейшего чтения, посмотрите на документацию для следующих инструментов:
Вывод
Это был вихревой тур по отладке с помощью iOS SDK. Еще многое можно сделать, но, надеюсь, этого урока было достаточно, чтобы помочь вам быстрее устранить ошибки в ваших собственных приложениях и написать лучшее программное обеспечение! Если вы хотите узнать больше о некоторых расширенных инструментах, обсуждаемых в этом руководстве, таких как Instruments, Shark или SpinControl, или если вы хотите узнать больше об отладке в целом, оставьте комментарий ниже и дайте мне знать!