Единственной постоянной в разработке програмного обеспечения являются баги. Давайте посмотрим правде в глаза, нам никогда не удавалось сделать все правильно с первого раза. Из-за небрежности или неправильных предположений, разработка программного обеспечения становится похожа на приготовление пирога в мотеле, кишащим тараканами, за исключением того, что в нашем случае мы сами создаем жуков. К счастью Xcode дает нам множество инструментов для того, чтобы держать насекомых в ужасе. Очевидно что для этой цели существует отладчик, который мы знаем и любим, но есть еще многое что он умеет помимо просмотра переменных и построчной отладки. Это туториал для начинающих и продвинутых iOS разработчиков, где вы сможете получить практический опыт работы с некоторыми менее известными но черезвычайно полезными методами отладки, таких как:
— как избавится от NSLog в пользу логирования брейкпоинтов;
— как избавится от списка TODO в пользу генерации предупреждений компилятора;
— остановка на условиях с выражениями;
— динамическое изменение данных с помощью LLDB и многое другое.
Как вы можете заметить, целью для меня является быть ленивым разработчиком. К счастью LLDB позволяет сохранить мое время на мартини. Он предоставляет мне отличные инструменты для того, чтобы я не был приклеен к моему компьютеру в течении дня и ночи. Устраивайтесь поудобнее в кресле и открывайте свой любимый напиток. Время становиться ленивым!
Замечу что данный туториал подразумевает что вы уже знакомы с основами отладки в Xcode. Если вы новичек, рекомендую пройти сначала этот туториал.
Я собрал образец приложения для это проекта, который вы можете скачать здесь.
Это приложение называется Gift Lister. Оно отслеживает продарки, которые вы хотите купить своим друзьям. Это приложение похоже на проложение Gifts 2 HD, которое недавно получило награду Most Visually Impressive. Gift Lister похож на Gifts 2 HD но много, много хуже.
Для начала, Gift Lister просто кишит багами. Разработчик (это был я в другой футболке) был очень амбициозен и пытался исправить все старомодным путем. И да, приложение все еще не работает.
В этом туториале вы увидите методы, как починить приложение действуя настолько лениво, насколько это вообще возможно.
Открыв проект, вы увидете различные файлы. Вы можете увидить, что наше приложение это фронтенд к модели под управлением CoreData.
Теперь, когда вы осмотрелись, постройте и запустите проект. Не удивительно, но приложение падает. Давайте же починим его.
Первым делом вам необходимо открыть консоль дебаггера. Вы можете открыть ее нажав на эту ктопку на главной панели:
Хотя эта кнопка очень хорошая, милая и удобная, ее нажатие при каждом сеансе отладки ведет к ненужному износу пальцев. По этому я предпочитаю чтобы Xcode делал это за меня.
Для этого необходимо открыть настройки Xcode нажав ⌘, либо зайти в меню и выбрать Xcode\Preferences и нажать кнопку Behaviors
Выберите пункт Starts с левой стороны появившегося диалогового окна. С правой стороны появится группа опций, выберите седьмой чекбокс и выберите Variables & Console в последнем чекбоксе.
Проделайте те же самые действия для пунктов Pauses и Generates Output, которые находятся прямо под пунктом Starts.
Опция Variables & Console говорит отладчику при старте сессии показать как консоль, так и список локальных переменных. Если вы хотите чтобы показывалась только консоль, выберете Console View, если вы хотите видеть только список локальных переменных выберите Variable View.
Опция Current Views запускает тот вид, который был в последней сессии отладки. Например если вы закрыли отображение локальных переменных и оставили только консоль, при следующем запуске отладчика отобразится только консоль.
Закройте диалоговое окно, затем постройте и запустите приложение.
Теперь при каждом запуске вашего приложение будет появляться отладчик, что освободит вас от мучительного бремени нажатия кнопки.
Перед тем как продолжить рассмотрим определение breakpoint.
Breakpoint это точка, которая позволяет остановить программу в некоторый момент времени и выполнить некоторые действия над запущенной программой.
Программа остановится в назначенной точке и позволит оценить свое текущее состояние и позволит осуществить свое выполнение по шагам.
Также вы можете запускать код, изменять переменные, и даже заставить компьютер цитировать Шекспира. И вы все это сделаете в течении этого туториала.
Хорошо, постройте и запустите приложение. Такой выглядит первая попытка запуска:
Тут есть над чем подумать. В текущий момент вы не можете увидеть источник ошибок компилятора. Для того, чтобы найти источник, вам необходимо поставить breakpoint.
Итак, переключитесь на breakpoint navigator, как показано на картинке ниже:
Затем нажмите на плюс внизу панели. Из появившегося меню выберите Add Exception Breakpoint.
Далее вы должны увидить диалоговое окно:
Поле Exception предоставляет опцию включить breakpoint для Objective-C, C++ кода или для всего. Оставьте значение по умолчанию (All).
Поле Break позволяет остановить выполнение при возникновении ошибки либо при ловле (Catch) исключения. Оставьте выбранным пункт On Throw. Если вы собираетесь использовать в вашем коде обработчик исключений, тогда вам нужен пункт On Catch. Для нашего туториала оставьте On Throw.
Два последних поля мы рассмотрим по ходу обучения. Нажмите кнопку Done и, затем, Build and run.
На этот раз результат стал гораздо понятнее.
Взгляните на консоль, теперь она заполнена логами, причем многие из них нам не нужны.
Логи это важная часть отладки приложения. Но нам необходимо убрать ненужные сообщения, чтобы не захламлять консоль. Если вы не уберете ненужные сообщения, вы будете тратить больше времени на поиск нужных сообщений, и, как следствие, тратить на ошибку больше времени, чем она того заслуживает.
Откройте AppDelegate.m и вы должны будете увидить много старых сообщений в методе didFinishLauncingWithOptions. Выберите их все удалите.
Давайте найдем следующий журнал логов. Откройте поиск и найдите NSLog (@«in viewDidLoad»);
Нажмите в результатах поиска на FriendSelectionViewController.m и далее откроется строка, которая выводит сообщения в лог.
На данный момент усилия, которые вы затрачиваете на ведение логов начинают накапливаться. Возможно вам кажется что вы потратили не так уж и много времени, но потраченное время имеет свойство накапливаться. К концу проекта потраченное время будет измеряться уже в часах.
Другим недостатком хардкодинга логов является то, что каждый раз добавляя что то новое к вашей кодовой базе, вы берете на себя риск возникновения новых ошибок. Все это занимает несколько нажатий клавиш, немного автозаполнения, немного отвлечения внимания и, однажды, в вашем работающем приложении появляется баг.
Теперь настало время избавиться от логов.
Сначала закомментируйте две наших строки, генерирующие логи. Затем добавьте breakpoints кликнув левее каждого выражения.
Ваше окно с кодом должно теперь выглядеть следующим образом:
Кликните на первом breakpoint левой кнопкой мыши с зажатым Control либо правой кнопкой и выберите Edit Breakpoint. В диалоговом окне выберите Log Message из меню Action. В текстовом поле напишите «in viewDidLoad». Диалоговое окно должно выглядеть как на рисунке:
Нажмите кнопку Done, затем запустите приложение. Теперь в консоли вы должны увидить сообщения «in viewDidLoad», но сейчас оно генерируется не NSLog, а с помощью breakpoint!
Но есть одна большая проблема. Программа останавливается, достигая breakpoint в то время как мы не хотим этого. Изменить такое поведение давольно просто.
Кликните на breakpoint левой кнопкой мыши с зажатым Control либо правой кнопкой и выберите чекбокс «Automatically continue after evaluating». Теперь снова запустите приложение.
На этот раз при достижении первого breakpoint только выводится сообщение, программа останавливается только на втором breakpoint.
Кликните на втором breakpoint левой кнопкой с зажатым Control либо правой кнопкой мыши. Выберите «Log Message» в меню, затем напишите «Loading Friends...». В нижней части диалогового окна выберите чекбокс «Automatically continue after evaluating». Нажмите Done и запустите приложение.
Приложение работает отлично, до той поры пока оно не падает, но не все же сразу.
Верите или нет, но вы все еще делаете слишком много работы. Кликните на первом breakpoint левой кнопкой мыши с зажатым Control либо правой кнопкой и замените «in viewDIdLoad» на %B. Запустите приложение еще раз. Консоль будет выглядить следующим образом:
Ключ %B выводит имя метода в котором выполнился breakpoint. Вы так же можете использовать %H для того, чтобы увидеть сколько раз был вызван метод. Так же сюда могут включаться простые выражения.
Так вы можете написать: %B has been touch %H times. В консоле будет выведено: -viewWillLoad has been touched 1 times.
Перед тем как вы исправите критичный баг, давайте еще немного повеселимся. Кликните на первом breakpoint левой кнопкой мыши с зажатым Control либо правой кнопкой и выберите Edit Breakpoint. В диалоговом окне нажмите кнопку плюс. Эта кнопка позволяет выполнять несколько действий на одном breakpoint.
Выберите «Log Message» и введите “To be, or not to be”. Выберите опцию «Speak Message» и нажмите Done. Диалоговое окно должно выглядить следующим образом:
Запустите приложение и насладитесь представлением.
К сожалению, Log Messages не обладает гибкостью NSLog. Для ее достижения нам необходимо добавить некоторые Debugger Actios.
Для демонстрации вы исправите критический баг. Запустите приложение и дайте программе упасть. Стэк будет выглядеть следующим образом:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Friend'
Что-то не работает в Core Data.
Проверяя код вы увидите что NSManagedObjectContext тянется из объекта DataStore. Тут у вас возникает предчуствие, что, возможно, DataStore и есть источник проблемы. DataStore не является частью CoreData. Это вручную созданный синглтон для инкапсуляции некоторых основных объектов CoreData.
Добавьте breakpoint под строкой: DataStore *dataStore = [DataStore sharedDataStore];
Кликните на breakpoint левой кнопкой с зажатым Control либо правой кнопкой мыши, выберите «Edit Breakpoint» и затем выберите «Debugger Command». В текстовом поле введите следующее:
po dataStore
Отметьте чекбокс “Automatically continue after evaluating” и запустите.
Как вы и ожидали значение dataStore равно nil.
Откройте DataStore.m и вы увидите что sharedInstance всегда возвращает nil. Измените возвращаемое значение с
return nil;
на
return sharedInstance;
Запустите приложение. Ура, оно работает (вроде бы как)!
Чем дальше, тем лучше, но как вы могли заметить логи выведенные с помощью breakpoint не показывают время возникновения сообщения, что может быть иногда полезно для отладки приложения. Но есть хорошая новость, это легко исправить с помощью breakpoint выражений!
Давайте восстановим логи во всей их красе. Выполним правый клик или control клик на предидущий breakpoint в FriendSelectionViewController.m. Выберите «Edit Breakpoint». В диалоговом окне измените комманду на
expr (void)NSLog(@«dataStore: %@», dataStore)
Комманда expr будет вычислять выражение в реальном времени. Комманда выражения должна точно знать тип возвращаемого значения, поэтому приведение типов необходимо. Так как у NSLog не существует возвращаемого значения, тип возвращаемого значения должен быть void. Запустите приложение.
Вы должны увидеть примерно следующее:
2012-12-20 08:57:39.942 GiftLister[1984:11603] dataStore: <DataStore: 0x74c3170>
Возможность выводить NSLog выражения через breakpoint позволит вам больше не останавливать программу только для того, чтобы вывести важные данные, да и теперь у вас не будет шанса привнести новые баги в программу просто по тому, что вы не трогаете код, но лучше всего то, что вам не придется лихорадочно удалять ваши отладочные сообщения в ночь перед релизом.
Существует небольшая разница между вызовом NSLog в отладчике и вызовом в коде. В отличие от кода, будет выводится текст "". Это сообщение генерируется LLDB, и к сожалению, вы не сможете его подавить. Хорошие новости в том, что такое поведение должно исправится в следующем релизе XCode.
Давайте тепеть отключим логирование приложения. Это можно сделать просто нажав кнопку breakpoints.
Нажмите на нее и затем запустите приложение. Логов больше не генерируется. Вы также можете индивидуально отключить логирование в breakpoint navigator.
Дни когда вы наполняли свой код вызовами логов наконец то прошли!
Приложение работает. Следующее что нам нужно сделать это добавить друзей для того чтоб вы могли составить список предпочтений для выбора подарков. Запустите приложение, и когда приложение запустится, нажмите кнопку на которой написано «Add a friend». Приложение загрузит другой view controller в котором будет поле для ввода текста и выбор даты. Введите имя и выберите день рождения друга. Нажмите OK.
Вы вернетесь к корневому view controller и запись о вашем друге будет добавлена в таблицу. Нажмите Add friend еще раз.
Введите имя еще одного друга, но на этот раз выберите ему день рождения 31 февраля 2010 года.
В обычном Date picker такой даты нет, но не в случае нашего приложения. В порыве бреда я решил быть амбициозным и выбрал обычный picker вместо date picker. Сделав так, мне пришлось переписать всю логику проверки дат, и, конечно, это привело к возникновению новых ошибок.
нажмите кнопку OK. К сожалению записалась неверная дата. Время провести отладку, чтобы понять что не так.
Откройте AddFriendViewController.m и поставьте breakpoint в начало метода — (void) saveFriend.
В симуляторе нажмите «Add a friend» и также как и в прошлый раз, введите неправильную дату. Выполняйте метод по шагам пока не достигните строки:
Зайдите в данный метод. Код проверки значений отсутствует. Но это еще не все, здесь просто комментарий, обещающий поправить ситуацию в будущем.
Комментарии это хороший способ описать значения некоторых кусков кода, но их исользования для управления задачами бесполезно. Даже в небольших проектах слишко много различных пунктов для того, чтобы гарантировть что не один из таких комментариев не будет просто забыт.
Лучший способ не потерять такие комментарии, это сделать их действительно заметными.
В первой строке метода -(void)isValidDateComposedOfMonth напишите следуюший код:
С этого момента проект будет сообщать о новом предупреждении. Нажмите на Issue Navigator и вы увидите там новое предупреждение с вашим сообщением.
Если вы из тех разработчиков что игнорируют предупреждения, попробуйте следующий метод
С этого момента в проекте появится новая ошибка. Причем вы не сможете скомпилировать приложение пока не устрените ее. Это был один из способов для слежения за своими комментариями.
Удалите оба сообщения чтобы приложение смогло скомпилироваться.
В первой строке метода — (void) isValidDateComposedOfMonh, напишите следующий код:
Сохраните код и откройте Jump bar. Вы должны увидеть что то вроде этого:
Вы также можете написать: FIXME:, ???:, и !!!:. ???: значит «У меня есть вопросы» в то время как !!!: значит «это важно».
Эти сообщения не привлекают столько внимания как предупреждения или ошибки, но они более заметны чем одинокий комментарий внизу метода. Лучше всего оставлять комментарии для, ну допустим для комментирования и вести список задач за пределами кода.
Давайте теперь рассмотрим одну небольшую особенность, которая пояилась в Xcode 4.4.
Запустите приложения оставив breakpoint в пустом методе валидации. Посмотрите на список переменных в отладчике. Тепрь выполните step out. Вновь посмотрите на список переменных. Вы должны увидеть следующее:
Эта особенность не получила особого внимания, но она способна сделать вашу жизнь гораздо проще. Отметьте, что код был вызван отсюда:
Код, который вызывает метод теперь немедленно использует возвращаемое значение в выражении. Раньше, если бы вы захотели проверить возвращаемое значение, вам нужно бы было разбивать строку и затем выводить значение.
Теперь вы можете просто выйти из метода и посмотреть в отладчике возвращаемое значение.
На данный момент у вас есть уже достаточно данных в приложении. Настало время их сохранить. В приложениях вроде этого, сохранения должны быть настолько частыми, чтобы не потерять данные. Но это не для нашего конкретного приложения. Наше приложение сохраняет данные только тогда, когда пользователь его закрывает.
Нажимте кнопку назад на навигационной панели, что вернет вас к корневому контроллеру, затем симулируйте нажатие кнопки Home. Вы можете сделать это из меню симулятора выбрав пункт Hardware\Home или нажав shift-command-h.
Теперь остановите программу из Xcode и снова ее запустите. Таблица пуста. Приложению не удалось ничего сохранить.
Откройте AppDelegate.m. В методе applicationDidEnterBackground вы сразу должны будете увидить проблему. Существует метод названный doLotsOfWork. Работа не закончилась вовремя, так что iOS закрывает ваше приложение до завершения его очистки. Результатом этого досрочного завершения является то, что метод SaveData не вызвается.
Давайте сначала убедимся что данные сохраняются. В applicationDidEnterBackground переместите вызов [[DataStore sharedDataStore] saveData]; перед вызовом doLotsOfWork следующим образом:
Теперь добавьте breakpoint на строку doLotsOfWork. Далее сделайте правый или control клик на breakpoint и выберите Edit Breakpoint. Выберите Sound Action и поставьте звук Submarine. Когда я имею дело со звуками, я пытаюсь не использовать системные звуки так как их легко не заметить.
Далее кликните на чекбокс Automatically continue after evaluating и наконец запустите приложение.
Когда приложение запустится снова, добавьте нового пользователя и нажмите кнопку Home. Сразу после закрытия приложения вы должны будете услышать звук подводной лодки, сигнализирующий о том, что данные былио сохранены.
Остановите приложение из Xcode и нажмите кнопку Run. Вы увидите ваши данные во всей красе.
Использование звуков это хороший способ узнать о выполнении определенной части кода без просмотра логов. Вы также можете использовать свой звуки если, например, вы хотите в случае падения приложения слышать звук взрыва.
Для этого просто поместите ваши звуки в папку: YOUR_HOME_DIRECTORY/Library/Sounds но вам придется перезапустить Xcode для того, чтобы он мог их увидеть.
В разработке существуют моменты, когда необходимо изменять состояние программы через определенные промежутки времени. Иногда эти изменения происходят в огромной последоательности событий, которые делают нормальную отладку невозможной. И тут игру вступают условия.
Теперь у вас есть несколько друзей сохраненных в приложении, нажмите на одно из имен чтобы открыть интерфейс для подарков. Это всего лишь простая сгрупированная таблица, которая может быть отсортирована по признаку может ли быть куплен подарок или нет.
Нажмите кнопку Add на навигаионной панели для того чтобы добавить новый элемент. Для имени выберите Shoes. Для цены 88.00. Нажмите кнопку OK. Эти туфли должны появиться в таблице подарков.
Теперь добавьте следующие вещи:
Sleigh / 540.00
Candles / 1.99
XBox / 299.99
iPad / 499.99
Упс. Вы только что поняли что на самом деле хотели записать PS3 вместо XBox. Вы можете просто нажать на ячейку для редактирования, но в целях демонстрации вы будете делать это через отладчик.
Откройте GiftListsViewController.m и найдите метод cellForRowAtIndexPath. Добавьте breakpoint на строке под кодом if (gift) {
Теперь правый клик или control клик на breakpoint и выберите «Edit Breakpoint».
Настало время для нашего условия. Относитесь к ниму так же просто как и к сообщениям. Добавьте следующий код:
LLDB требует от нас приведения типов, по-этому мы поставили BOOL перед выражением. Нажмите кнопку готово. Теперь нажмите кнопку Bought. В таблицу загружаются новые данные но breakpoint не срабатывает. Нажмите кнопку сохранить. На этот раз все остановится выбранный элемент в консоле отладчика подсветится.
В консоль отладчика добавьте следующее:
Теперь нажмите кнопку Play и таблица продолжит загружаться и PS3 заменит XBox в списке подарков.
Этого же результата можно добиться путем установки количества итераций. Control клик или правый клик на breakpoint и выберите ‘Delete Breakpoint’. Xcode может быть слегка нестабилен при изменении условий, по этому лучше все начать с чистого листа. Добавьте новый breakpoint на том же месте. На этот раз проигнорируйте текстовое поле и выберите номер 3. Нажмите Done.
Затем нажмите Bought и Saved.
Мы должны попасть в тот же самый breakpoint. Чтобы убедиться что мы на правильном объекте напишите:
Теперь вернем объект к предидущему состоянию:
Таблица должна отразить изменения. Ну разве редактирование в реальном времени не прекрасно?
При разработке приложений управляющих данными, зачастую бывает важно очищать хранилища данных. Для этого существует несколько способов, он рестарта iPhone симулятора до нахождения фактического хранилища на вашем компьютере и удалении его. Делать это снова и снова может быть несколько утомительно, по этому можно опять побыть немного ленивыми и позвольить Xcode сделать это за нас.
Мы начнем с созданиия скрипта. Скрипт это набор команд, который автоматизирует некоторые действия опереционной системы. Для создания нового скрипта выберите New file в меню приложения. Нажмите File\New\File или command-n. Выберите категорию Other и там выберите Shell script.
Введите имя wipe-db.sh
Теперь нам необходимо найти реальное хранилище данных.
Откройте ваш терминал. Если вы не знаете где находится терминал, вы можете найти его в папке вашего приложения в папке Utilities.
После запуска терминала перейдите в свой домашний каталог введя
Затем выведите список файлов и папок в вашей дериктории введя
Осмотрите ваш каталог, если вы не видите папку Library введите комманду
Затем перезапустите терминал.
Теперь переместитесь в папку с симулятором iPhone с помощью комманды:
Выведите список директории
Вы увидите много различных директорий, их количество зависит от того, скольго приложений установлено на симуляторе. Вам надо будет методом проб и ошибок нати папку с GiftLister. Для перехода в папку введите: cd THE_NAME_OF_YOUR_FOLDER
Чтобы сэкономить время вводите только первые три буквы имени папки и нажимайте Tab. Терминал будет дописывать имена папок за вас. Если нет, то продолжайте вводить буквы до тех пор, пока он не начнет автозаполнение. В моем случае это папка 0B1E5AD3-7292-45A6-BB5D-F1C004AC47F9 по этому я введу
и нажму Tab.
Внутри вы должны увидить файл GiftLister.app, если вы его не находите, попробуйте другую папку. Также этот проект выполняется на симуляторе iOS6. Если вы используете более раннюю версию симулятора введите
Затем введите ls для отображения ее содержимого. Выберите правильную версию симулятора, и зайдите в директорию с помощью:
например
Когда вы найдете папку вашего приложения введите
и введите ls.
Вы должны увидеть файл giftlister.sqlite. Джекпот.
Теперь выведите путь до файла коммандой pwd.
Скопируйте путь и вставьте его в скрипт добавив на конце /giftlister.sqlite
Ваш путь должет будет выглядеть примерно так:
К сожалению вы не сможете использовать пробелы, по этому вам придется трансформировать
в
полный путь будет выглядеть как
Далее добавьте комманду удаления, которая выглядит как просто rm.
Ваш скрипт будет выглядеть следующим образом:
Сохраните и закройте ваш скрипт.
По умолчанию скрипты создабтся только для чтения, вам необходимо будет сделать этот скрипт доступным для выполнения. Вернитесь в вашу домашнюю директорию введя
Затем выполните ls.
Перейдите в папку вашего проекта. Если вы сохранили его на рабочем столе, вы можете перейти туда просто выполнив
Для перехода на папку вверх введите cd…
После долгого блуждания по терминалу вы должны увидеть папку проекта. Для выполнения скрипта просто введите
Chmode это программа для изменения разрешений файлов. a+x позволяет файлу быть исполняемым для всех пользователей, групп и других.
Ничего себе… как много всего. Сделайте передышку. Вы это заслужили. Иногда для того, чтобы побыть ленивым приходится хорошо поработать.
Закройте терминал и вернитесь в Xcode. Откройте AppDelegate.m. Установите breakpoint на первой строке метода didFinishLaunchingWithOptions. Правый или control клик на breakpoint и выберите «Edit Breakpoint». Добавьте Action и выберите Shell Command. В следующем диалоговом окне нажмите кнопку Choose и выберите только что созданный скрипт. Нажмите на чекбокс Automatically continue after evaluating” и затем нажмите Done. Остановите симулятор если он запущен. Теперь запустите приложение. База данных будет удалена.
Симулятор имеет тенденцию к кэшированию больших объемов данных, по этому я считаю что лучше всего нажать Clean из Xcode в меню Clean, а потом нажать Build and run.
Все это потребовало немного работы при настройке, но теперь очистка базы данных может быть выполнена всего одним нажатием кнопки. Когда данное поведение нежелательно просто отключайте breakpoint.
Автором данного поста является Brian Moakley, человек, являющийся не только разработчиком iOS приложений и беллетристом, но также при этом это первый сотрудник Razerware, принятый на полный рабочий день.
P.S. О всех грамматических и синтаксических ошибках пишите в личку, они будут исправлены настолько быстро, насколько это будет возможно.
— как избавится от NSLog в пользу логирования брейкпоинтов;
— как избавится от списка TODO в пользу генерации предупреждений компилятора;
— остановка на условиях с выражениями;
— динамическое изменение данных с помощью LLDB и многое другое.
Как вы можете заметить, целью для меня является быть ленивым разработчиком. К счастью LLDB позволяет сохранить мое время на мартини. Он предоставляет мне отличные инструменты для того, чтобы я не был приклеен к моему компьютеру в течении дня и ночи. Устраивайтесь поудобнее в кресле и открывайте свой любимый напиток. Время становиться ленивым!
Замечу что данный туториал подразумевает что вы уже знакомы с основами отладки в Xcode. Если вы новичек, рекомендую пройти сначала этот туториал.
Итак, начнем
Я собрал образец приложения для это проекта, который вы можете скачать здесь.
Это приложение называется Gift Lister. Оно отслеживает продарки, которые вы хотите купить своим друзьям. Это приложение похоже на проложение Gifts 2 HD, которое недавно получило награду Most Visually Impressive. Gift Lister похож на Gifts 2 HD но много, много хуже.
Для начала, Gift Lister просто кишит багами. Разработчик (это был я в другой футболке) был очень амбициозен и пытался исправить все старомодным путем. И да, приложение все еще не работает.
В этом туториале вы увидите методы, как починить приложение действуя настолько лениво, насколько это вообще возможно.
Открыв проект, вы увидете различные файлы. Вы можете увидить, что наше приложение это фронтенд к модели под управлением CoreData.
Теперь, когда вы осмотрелись, постройте и запустите проект. Не удивительно, но приложение падает. Давайте же починим его.
Настройка консоли дебагера
Первым делом вам необходимо открыть консоль дебаггера. Вы можете открыть ее нажав на эту ктопку на главной панели:
Хотя эта кнопка очень хорошая, милая и удобная, ее нажатие при каждом сеансе отладки ведет к ненужному износу пальцев. По этому я предпочитаю чтобы Xcode делал это за меня.
Для этого необходимо открыть настройки Xcode нажав ⌘, либо зайти в меню и выбрать Xcode\Preferences и нажать кнопку Behaviors
Выберите пункт Starts с левой стороны появившегося диалогового окна. С правой стороны появится группа опций, выберите седьмой чекбокс и выберите Variables & Console в последнем чекбоксе.
Проделайте те же самые действия для пунктов Pauses и Generates Output, которые находятся прямо под пунктом Starts.
Опция Variables & Console говорит отладчику при старте сессии показать как консоль, так и список локальных переменных. Если вы хотите чтобы показывалась только консоль, выберете Console View, если вы хотите видеть только список локальных переменных выберите Variable View.
Опция Current Views запускает тот вид, который был в последней сессии отладки. Например если вы закрыли отображение локальных переменных и оставили только консоль, при следующем запуске отладчика отобразится только консоль.
Закройте диалоговое окно, затем постройте и запустите приложение.
Теперь при каждом запуске вашего приложение будет появляться отладчик, что освободит вас от мучительного бремени нажатия кнопки.
The NSLog Jam
Перед тем как продолжить рассмотрим определение breakpoint.
Breakpoint это точка, которая позволяет остановить программу в некоторый момент времени и выполнить некоторые действия над запущенной программой.
Программа остановится в назначенной точке и позволит оценить свое текущее состояние и позволит осуществить свое выполнение по шагам.
Также вы можете запускать код, изменять переменные, и даже заставить компьютер цитировать Шекспира. И вы все это сделаете в течении этого туториала.
Хорошо, постройте и запустите приложение. Такой выглядит первая попытка запуска:
Тут есть над чем подумать. В текущий момент вы не можете увидеть источник ошибок компилятора. Для того, чтобы найти источник, вам необходимо поставить breakpoint.
Итак, переключитесь на breakpoint navigator, как показано на картинке ниже:
Затем нажмите на плюс внизу панели. Из появившегося меню выберите Add Exception Breakpoint.
Далее вы должны увидить диалоговое окно:
Поле Exception предоставляет опцию включить breakpoint для Objective-C, C++ кода или для всего. Оставьте значение по умолчанию (All).
Поле Break позволяет остановить выполнение при возникновении ошибки либо при ловле (Catch) исключения. Оставьте выбранным пункт On Throw. Если вы собираетесь использовать в вашем коде обработчик исключений, тогда вам нужен пункт On Catch. Для нашего туториала оставьте On Throw.
Два последних поля мы рассмотрим по ходу обучения. Нажмите кнопку Done и, затем, Build and run.
На этот раз результат стал гораздо понятнее.
Взгляните на консоль, теперь она заполнена логами, причем многие из них нам не нужны.
Логи это важная часть отладки приложения. Но нам необходимо убрать ненужные сообщения, чтобы не захламлять консоль. Если вы не уберете ненужные сообщения, вы будете тратить больше времени на поиск нужных сообщений, и, как следствие, тратить на ошибку больше времени, чем она того заслуживает.
Откройте AppDelegate.m и вы должны будете увидить много старых сообщений в методе didFinishLauncingWithOptions. Выберите их все удалите.
Давайте найдем следующий журнал логов. Откройте поиск и найдите NSLog (@«in viewDidLoad»);
Нажмите в результатах поиска на FriendSelectionViewController.m и далее откроется строка, которая выводит сообщения в лог.
На данный момент усилия, которые вы затрачиваете на ведение логов начинают накапливаться. Возможно вам кажется что вы потратили не так уж и много времени, но потраченное время имеет свойство накапливаться. К концу проекта потраченное время будет измеряться уже в часах.
Другим недостатком хардкодинга логов является то, что каждый раз добавляя что то новое к вашей кодовой базе, вы берете на себя риск возникновения новых ошибок. Все это занимает несколько нажатий клавиш, немного автозаполнения, немного отвлечения внимания и, однажды, в вашем работающем приложении появляется баг.
Теперь настало время избавиться от логов.
Сначала закомментируйте две наших строки, генерирующие логи. Затем добавьте breakpoints кликнув левее каждого выражения.
Ваше окно с кодом должно теперь выглядеть следующим образом:
Кликните на первом breakpoint левой кнопкой мыши с зажатым Control либо правой кнопкой и выберите Edit Breakpoint. В диалоговом окне выберите Log Message из меню Action. В текстовом поле напишите «in viewDidLoad». Диалоговое окно должно выглядеть как на рисунке:
Нажмите кнопку Done, затем запустите приложение. Теперь в консоли вы должны увидить сообщения «in viewDidLoad», но сейчас оно генерируется не NSLog, а с помощью breakpoint!
Но есть одна большая проблема. Программа останавливается, достигая breakpoint в то время как мы не хотим этого. Изменить такое поведение давольно просто.
Кликните на breakpoint левой кнопкой мыши с зажатым Control либо правой кнопкой и выберите чекбокс «Automatically continue after evaluating». Теперь снова запустите приложение.
На этот раз при достижении первого breakpoint только выводится сообщение, программа останавливается только на втором breakpoint.
Кликните на втором breakpoint левой кнопкой с зажатым Control либо правой кнопкой мыши. Выберите «Log Message» в меню, затем напишите «Loading Friends...». В нижней части диалогового окна выберите чекбокс «Automatically continue after evaluating». Нажмите Done и запустите приложение.
Приложение работает отлично, до той поры пока оно не падает, но не все же сразу.
Верите или нет, но вы все еще делаете слишком много работы. Кликните на первом breakpoint левой кнопкой мыши с зажатым Control либо правой кнопкой и замените «in viewDIdLoad» на %B. Запустите приложение еще раз. Консоль будет выглядить следующим образом:
Ключ %B выводит имя метода в котором выполнился breakpoint. Вы так же можете использовать %H для того, чтобы увидеть сколько раз был вызван метод. Так же сюда могут включаться простые выражения.
Так вы можете написать: %B has been touch %H times. В консоле будет выведено: -viewWillLoad has been touched 1 times.
Перед тем как вы исправите критичный баг, давайте еще немного повеселимся. Кликните на первом breakpoint левой кнопкой мыши с зажатым Control либо правой кнопкой и выберите Edit Breakpoint. В диалоговом окне нажмите кнопку плюс. Эта кнопка позволяет выполнять несколько действий на одном breakpoint.
Выберите «Log Message» и введите “To be, or not to be”. Выберите опцию «Speak Message» и нажмите Done. Диалоговое окно должно выглядить следующим образом:
Запустите приложение и насладитесь представлением.
К сожалению, Log Messages не обладает гибкостью NSLog. Для ее достижения нам необходимо добавить некоторые Debugger Actios.
Для демонстрации вы исправите критический баг. Запустите приложение и дайте программе упасть. Стэк будет выглядеть следующим образом:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Friend'
Что-то не работает в Core Data.
Проверяя код вы увидите что NSManagedObjectContext тянется из объекта DataStore. Тут у вас возникает предчуствие, что, возможно, DataStore и есть источник проблемы. DataStore не является частью CoreData. Это вручную созданный синглтон для инкапсуляции некоторых основных объектов CoreData.
Добавьте breakpoint под строкой: DataStore *dataStore = [DataStore sharedDataStore];
Кликните на breakpoint левой кнопкой с зажатым Control либо правой кнопкой мыши, выберите «Edit Breakpoint» и затем выберите «Debugger Command». В текстовом поле введите следующее:
po dataStore
Отметьте чекбокс “Automatically continue after evaluating” и запустите.
Как вы и ожидали значение dataStore равно nil.
Откройте DataStore.m и вы увидите что sharedInstance всегда возвращает nil. Измените возвращаемое значение с
return nil;
на
return sharedInstance;
Запустите приложение. Ура, оно работает (вроде бы как)!
Выражения и breakpoints
Чем дальше, тем лучше, но как вы могли заметить логи выведенные с помощью breakpoint не показывают время возникновения сообщения, что может быть иногда полезно для отладки приложения. Но есть хорошая новость, это легко исправить с помощью breakpoint выражений!
Давайте восстановим логи во всей их красе. Выполним правый клик или control клик на предидущий breakpoint в FriendSelectionViewController.m. Выберите «Edit Breakpoint». В диалоговом окне измените комманду на
expr (void)NSLog(@«dataStore: %@», dataStore)
Комманда expr будет вычислять выражение в реальном времени. Комманда выражения должна точно знать тип возвращаемого значения, поэтому приведение типов необходимо. Так как у NSLog не существует возвращаемого значения, тип возвращаемого значения должен быть void. Запустите приложение.
Вы должны увидеть примерно следующее:
2012-12-20 08:57:39.942 GiftLister[1984:11603] dataStore: <DataStore: 0x74c3170>
Возможность выводить NSLog выражения через breakpoint позволит вам больше не останавливать программу только для того, чтобы вывести важные данные, да и теперь у вас не будет шанса привнести новые баги в программу просто по тому, что вы не трогаете код, но лучше всего то, что вам не придется лихорадочно удалять ваши отладочные сообщения в ночь перед релизом.
Существует небольшая разница между вызовом NSLog в отладчике и вызовом в коде. В отличие от кода, будет выводится текст "". Это сообщение генерируется LLDB, и к сожалению, вы не сможете его подавить. Хорошие новости в том, что такое поведение должно исправится в следующем релизе XCode.
Давайте тепеть отключим логирование приложения. Это можно сделать просто нажав кнопку breakpoints.
Нажмите на нее и затем запустите приложение. Логов больше не генерируется. Вы также можете индивидуально отключить логирование в breakpoint navigator.
Дни когда вы наполняли свой код вызовами логов наконец то прошли!
Предупреждения, ошибки, возвращаемые значения, боже ж мой
Приложение работает. Следующее что нам нужно сделать это добавить друзей для того чтоб вы могли составить список предпочтений для выбора подарков. Запустите приложение, и когда приложение запустится, нажмите кнопку на которой написано «Add a friend». Приложение загрузит другой view controller в котором будет поле для ввода текста и выбор даты. Введите имя и выберите день рождения друга. Нажмите OK.
Вы вернетесь к корневому view controller и запись о вашем друге будет добавлена в таблицу. Нажмите Add friend еще раз.
Введите имя еще одного друга, но на этот раз выберите ему день рождения 31 февраля 2010 года.
В обычном Date picker такой даты нет, но не в случае нашего приложения. В порыве бреда я решил быть амбициозным и выбрал обычный picker вместо date picker. Сделав так, мне пришлось переписать всю логику проверки дат, и, конечно, это привело к возникновению новых ошибок.
нажмите кнопку OK. К сожалению записалась неверная дата. Время провести отладку, чтобы понять что не так.
Откройте AddFriendViewController.m и поставьте breakpoint в начало метода — (void) saveFriend.
В симуляторе нажмите «Add a friend» и также как и в прошлый раз, введите неправильную дату. Выполняйте метод по шагам пока не достигните строки:
if ([self isValidDateComposedOfMonth:month day:day andYear:year]) {
Зайдите в данный метод. Код проверки значений отсутствует. Но это еще не все, здесь просто комментарий, обещающий поправить ситуацию в будущем.
Комментарии это хороший способ описать значения некоторых кусков кода, но их исользования для управления задачами бесполезно. Даже в небольших проектах слишко много различных пунктов для того, чтобы гарантировть что не один из таких комментариев не будет просто забыт.
Лучший способ не потерять такие комментарии, это сделать их действительно заметными.
В первой строке метода -(void)isValidDateComposedOfMonth напишите следуюший код:
#warning add validation code
С этого момента проект будет сообщать о новом предупреждении. Нажмите на Issue Navigator и вы увидите там новое предупреждение с вашим сообщением.
Если вы из тех разработчиков что игнорируют предупреждения, попробуйте следующий метод
#error fix your code
С этого момента в проекте появится новая ошибка. Причем вы не сможете скомпилировать приложение пока не устрените ее. Это был один из способов для слежения за своими комментариями.
Удалите оба сообщения чтобы приложение смогло скомпилироваться.
В первой строке метода — (void) isValidDateComposedOfMonh, напишите следующий код:
// TODO: Add validation code
Сохраните код и откройте Jump bar. Вы должны увидеть что то вроде этого:
Вы также можете написать: FIXME:, ???:, и !!!:. ???: значит «У меня есть вопросы» в то время как !!!: значит «это важно».
Эти сообщения не привлекают столько внимания как предупреждения или ошибки, но они более заметны чем одинокий комментарий внизу метода. Лучше всего оставлять комментарии для, ну допустим для комментирования и вести список задач за пределами кода.
Давайте теперь рассмотрим одну небольшую особенность, которая пояилась в Xcode 4.4.
Запустите приложения оставив breakpoint в пустом методе валидации. Посмотрите на список переменных в отладчике. Тепрь выполните step out. Вновь посмотрите на список переменных. Вы должны увидеть следующее:
Эта особенность не получила особого внимания, но она способна сделать вашу жизнь гораздо проще. Отметьте, что код был вызван отсюда:
if ([self isValidDateComposedOfMonth:month day:day andYear:year]) {
Код, который вызывает метод теперь немедленно использует возвращаемое значение в выражении. Раньше, если бы вы захотели проверить возвращаемое значение, вам нужно бы было разбивать строку и затем выводить значение.
Теперь вы можете просто выйти из метода и посмотреть в отладчике возвращаемое значение.
Озвучивание вашего метода для сохранения данных
На данный момент у вас есть уже достаточно данных в приложении. Настало время их сохранить. В приложениях вроде этого, сохранения должны быть настолько частыми, чтобы не потерять данные. Но это не для нашего конкретного приложения. Наше приложение сохраняет данные только тогда, когда пользователь его закрывает.
Нажимте кнопку назад на навигационной панели, что вернет вас к корневому контроллеру, затем симулируйте нажатие кнопки Home. Вы можете сделать это из меню симулятора выбрав пункт Hardware\Home или нажав shift-command-h.
Теперь остановите программу из Xcode и снова ее запустите. Таблица пуста. Приложению не удалось ничего сохранить.
Откройте AppDelegate.m. В методе applicationDidEnterBackground вы сразу должны будете увидить проблему. Существует метод названный doLotsOfWork. Работа не закончилась вовремя, так что iOS закрывает ваше приложение до завершения его очистки. Результатом этого досрочного завершения является то, что метод SaveData не вызвается.
Давайте сначала убедимся что данные сохраняются. В applicationDidEnterBackground переместите вызов [[DataStore sharedDataStore] saveData]; перед вызовом doLotsOfWork следующим образом:
[[DataStore sharedDataStore] saveData];
[self doLotsOfWork];
Теперь добавьте breakpoint на строку doLotsOfWork. Далее сделайте правый или control клик на breakpoint и выберите Edit Breakpoint. Выберите Sound Action и поставьте звук Submarine. Когда я имею дело со звуками, я пытаюсь не использовать системные звуки так как их легко не заметить.
Далее кликните на чекбокс Automatically continue after evaluating и наконец запустите приложение.
Когда приложение запустится снова, добавьте нового пользователя и нажмите кнопку Home. Сразу после закрытия приложения вы должны будете услышать звук подводной лодки, сигнализирующий о том, что данные былио сохранены.
Остановите приложение из Xcode и нажмите кнопку Run. Вы увидите ваши данные во всей красе.
Использование звуков это хороший способ узнать о выполнении определенной части кода без просмотра логов. Вы также можете использовать свой звуки если, например, вы хотите в случае падения приложения слышать звук взрыва.
Для этого просто поместите ваши звуки в папку: YOUR_HOME_DIRECTORY/Library/Sounds но вам придется перезапустить Xcode для того, чтобы он мог их увидеть.
Условия успешной отладки
В разработке существуют моменты, когда необходимо изменять состояние программы через определенные промежутки времени. Иногда эти изменения происходят в огромной последоательности событий, которые делают нормальную отладку невозможной. И тут игру вступают условия.
Теперь у вас есть несколько друзей сохраненных в приложении, нажмите на одно из имен чтобы открыть интерфейс для подарков. Это всего лишь простая сгрупированная таблица, которая может быть отсортирована по признаку может ли быть куплен подарок или нет.
Нажмите кнопку Add на навигаионной панели для того чтобы добавить новый элемент. Для имени выберите Shoes. Для цены 88.00. Нажмите кнопку OK. Эти туфли должны появиться в таблице подарков.
Теперь добавьте следующие вещи:
Sleigh / 540.00
Candles / 1.99
XBox / 299.99
iPad / 499.99
Упс. Вы только что поняли что на самом деле хотели записать PS3 вместо XBox. Вы можете просто нажать на ячейку для редактирования, но в целях демонстрации вы будете делать это через отладчик.
Откройте GiftListsViewController.m и найдите метод cellForRowAtIndexPath. Добавьте breakpoint на строке под кодом if (gift) {
Теперь правый клик или control клик на breakpoint и выберите «Edit Breakpoint».
Настало время для нашего условия. Относитесь к ниму так же просто как и к сообщениям. Добавьте следующий код:
(BOOL) [gift.name isEqualToString:@"XBox"]
LLDB требует от нас приведения типов, по-этому мы поставили BOOL перед выражением. Нажмите кнопку готово. Теперь нажмите кнопку Bought. В таблицу загружаются новые данные но breakpoint не срабатывает. Нажмите кнопку сохранить. На этот раз все остановится выбранный элемент в консоле отладчика подсветится.
В консоль отладчика добавьте следующее:
(lldb) expr (void) [gift setName:@"PS3"]
Теперь нажмите кнопку Play и таблица продолжит загружаться и PS3 заменит XBox в списке подарков.
Этого же результата можно добиться путем установки количества итераций. Control клик или правый клик на breakpoint и выберите ‘Delete Breakpoint’. Xcode может быть слегка нестабилен при изменении условий, по этому лучше все начать с чистого листа. Добавьте новый breakpoint на том же месте. На этот раз проигнорируйте текстовое поле и выберите номер 3. Нажмите Done.
Затем нажмите Bought и Saved.
Мы должны попасть в тот же самый breakpoint. Чтобы убедиться что мы на правильном объекте напишите:
(lldb) po gift
Теперь вернем объект к предидущему состоянию:
(lldb) (void)[gift setName:@"XBox 360"]
Таблица должна отразить изменения. Ну разве редактирование в реальном времени не прекрасно?
Настройка для сноса
При разработке приложений управляющих данными, зачастую бывает важно очищать хранилища данных. Для этого существует несколько способов, он рестарта iPhone симулятора до нахождения фактического хранилища на вашем компьютере и удалении его. Делать это снова и снова может быть несколько утомительно, по этому можно опять побыть немного ленивыми и позвольить Xcode сделать это за нас.
Мы начнем с созданиия скрипта. Скрипт это набор команд, который автоматизирует некоторые действия опереционной системы. Для создания нового скрипта выберите New file в меню приложения. Нажмите File\New\File или command-n. Выберите категорию Other и там выберите Shell script.
Введите имя wipe-db.sh
Теперь нам необходимо найти реальное хранилище данных.
Откройте ваш терминал. Если вы не знаете где находится терминал, вы можете найти его в папке вашего приложения в папке Utilities.
После запуска терминала перейдите в свой домашний каталог введя
YourComputer$ cd ~
Затем выведите список файлов и папок в вашей дериктории введя
YourComputer$ ls
Осмотрите ваш каталог, если вы не видите папку Library введите комманду
YourComputer$ chflags nohidden ~/Library/
Затем перезапустите терминал.
Теперь переместитесь в папку с симулятором iPhone с помощью комманды:
YourComputer$ cd ~/Library/Application\ Support/iPhone\ Simulator/6.0/Applications
Выведите список директории
YourComputer$ ls
Вы увидите много различных директорий, их количество зависит от того, скольго приложений установлено на симуляторе. Вам надо будет методом проб и ошибок нати папку с GiftLister. Для перехода в папку введите: cd THE_NAME_OF_YOUR_FOLDER
Чтобы сэкономить время вводите только первые три буквы имени папки и нажимайте Tab. Терминал будет дописывать имена папок за вас. Если нет, то продолжайте вводить буквы до тех пор, пока он не начнет автозаполнение. В моем случае это папка 0B1E5AD3-7292-45A6-BB5D-F1C004AC47F9 по этому я введу
YourComputer$ cd 0B1
и нажму Tab.
Внутри вы должны увидить файл GiftLister.app, если вы его не находите, попробуйте другую папку. Также этот проект выполняется на симуляторе iOS6. Если вы используете более раннюю версию симулятора введите
YourComputer$ cd ~/Library/Application\ Support/iPhone\ Simulator/
Затем введите ls для отображения ее содержимого. Выберите правильную версию симулятора, и зайдите в директорию с помощью:
cd VERSION_NUMBER/Applications
например
cd 6.0/Applications
Когда вы найдете папку вашего приложения введите
YourComputer$ cd Library
и введите ls.
Вы должны увидеть файл giftlister.sqlite. Джекпот.
Теперь выведите путь до файла коммандой pwd.
Скопируйте путь и вставьте его в скрипт добавив на конце /giftlister.sqlite
Ваш путь должет будет выглядеть примерно так:
/Users/Brian/Library/Application Support/iPhone Simulator/6.0/Applications/0B1E5AD3-7292-45A6-BB5D-F1C004AC47F9/Library/giftlister.sqlite
К сожалению вы не сможете использовать пробелы, по этому вам придется трансформировать
/iPhone Simulator/
/Application Support/
в
/iPhone\ Simulator/
/Application\ Support/
полный путь будет выглядеть как
/Users/Brian/Library/Application\ Support/iPhone\ Simulator/6.0/Applications/0B1E5AD3-7292-45A6-BB5D-F1C004AC47F9/Library/giftlister.sqlite
Далее добавьте комманду удаления, которая выглядит как просто rm.
Ваш скрипт будет выглядеть следующим образом:
Сохраните и закройте ваш скрипт.
По умолчанию скрипты создабтся только для чтения, вам необходимо будет сделать этот скрипт доступным для выполнения. Вернитесь в вашу домашнюю директорию введя
YourComputer$ cd ~
Затем выполните ls.
Перейдите в папку вашего проекта. Если вы сохранили его на рабочем столе, вы можете перейти туда просто выполнив
YourComputer$ cd Desktop
YourComputer$ cd GiftLister
Для перехода на папку вверх введите cd…
После долгого блуждания по терминалу вы должны увидеть папку проекта. Для выполнения скрипта просто введите
YourComputer$ chmod a+x wipe-db.sh
Chmode это программа для изменения разрешений файлов. a+x позволяет файлу быть исполняемым для всех пользователей, групп и других.
Ничего себе… как много всего. Сделайте передышку. Вы это заслужили. Иногда для того, чтобы побыть ленивым приходится хорошо поработать.
Закройте терминал и вернитесь в Xcode. Откройте AppDelegate.m. Установите breakpoint на первой строке метода didFinishLaunchingWithOptions. Правый или control клик на breakpoint и выберите «Edit Breakpoint». Добавьте Action и выберите Shell Command. В следующем диалоговом окне нажмите кнопку Choose и выберите только что созданный скрипт. Нажмите на чекбокс Automatically continue after evaluating” и затем нажмите Done. Остановите симулятор если он запущен. Теперь запустите приложение. База данных будет удалена.
Симулятор имеет тенденцию к кэшированию больших объемов данных, по этому я считаю что лучше всего нажать Clean из Xcode в меню Clean, а потом нажать Build and run.
Все это потребовало немного работы при настройке, но теперь очистка базы данных может быть выполнена всего одним нажатием кнопки. Когда данное поведение нежелательно просто отключайте breakpoint.
Автором данного поста является Brian Moakley, человек, являющийся не только разработчиком iOS приложений и беллетристом, но также при этом это первый сотрудник Razerware, принятый на полный рабочий день.
P.S. О всех грамматических и синтаксических ошибках пишите в личку, они будут исправлены настолько быстро, насколько это будет возможно.