Однажды я почти полностью отказался от мышки для навигации по Xcode и вполне этому рад. Следующий шаг — это отказ от визуальных средств управления отладчиком. Зачем? — Увеличиваем возможности, уменьшаем время дебага, тратим меньше калорий для перемещения тяжеленькой ручишки (нам калории нужны, чтобы головой работать) и тем самым провоцируем меньше туннельного синдрома.
.
Особо новых открытий в статье не будет, просто подытожу, что вы и сами хорошо знали и как это можно использовать для кого-то по-новому.
Не рассматриваю такие темы: как работать в Xcode, как вообще отлаживать приложение, в какой момент нужно это делать и зачем, что такое LLDB, что такое Step Into и Step Over и т.д.
Сразу к примерам:
Настраиваем консоль
Отказываем вот от этой панельки:
Да и вот про эту скоро забудем
Теперь наш новый лучший друг вот этот заманчивый белый холст, можно растянуть его даже на всю длину или вообще весь экран.
Спасибо моему коллеге: он осуществил мою давнишнюю мечту — открывать консоль отладчика в новом окне. А то всегда напрягало, что только открыл и настроил вкладки как тебе надо, так сразу же при первом брейкпоинте всё запоролось. Чтобы этого не было идем Xcode -> Behaviours -> Edit behaviours… Далее нам нужна секция Running -> Pause.
Выбираем Show tab named, пишем туда наше уникальное название вкладки, например Debug (замечу, что при повторных запусках вкладка не дублируется), в конце ставим active window — это, как ни странно, открывает новую вкладку (Cmd + T) для нашего отладчика. Ешё я скрыл ненужную правую панель — но это по желанию. Вообще кастомизация среды при разных условиях — это в разделе Behaviours
Всё, мы настроены, двигаем дальше.
Управляем отладчиком
Добавляем сразу в копилку полезных hotkey’ев кто не знал Cmd + Shift + C. Это быстрый переход в консоль.
Сmd + Shift + Y — это скрыть/показать консоль.
Наши новые команды:
Step Into — step или коротко s
Step Over — next или коротко n
Step Out — finish
Continue — continue или c
Отключить все брейкпоинты — breakpoint disable
За полным списком команд lldb можно отправиться вот сюда
Не буду перечислять все возможности прямых команд LLDB, но их список больше, чем позволяет сделать визуальная среда Xcode и каждый сам вправе решить использовать ему подобный подход или нет и какие команды нужны и интересны. Остановлюсь на том, что показал куда смотреть.
Удобство выполнения команд еще в том, что есть привычный как в терминале переход к предыдущей/последующей команде через стрелки вверх-вниз.
В результате наша работа с отладчиком выглядит вот так:
Swift и obj-c! Что внутри объекта?
Не знаю как вам, но мне не повезло писать проект на Swift с нуля, а пришлось с выходом нового языка в огромном obj-c проекте все новые файлы писать на Swifte. Не пишу про все несостыковки, но основная проблема в отладке, наверное, в следующем:
Создаем простой класс модели на Swift
class TestObject: NSObject { var name: String = "name" var index: Int = 123 }
Теперь пишем на obj-c простой массив с нашим классом:
NSArray *array = @[[[TestObject alloc] init], [[TestObject alloc] init], [[TestObject alloc] init]];
Теперь ставим брейкпоинт на следующей строчке и смотрим на то, что бы мы увидели в Variables:
Знакомо? А где же наши name и index
Теперь смотрим, что мы можем сами руками в консоле:
(lldb) p array (__NSArrayI *) $0 = 0x00007f9a1878c6b0 @"3 objects" (lldb) po array <__NSArrayI 0x7f9a1878c6b0>( <CornerApp.TestObject: 0x7f9a1870fc60>, <CornerApp.TestObject: 0x7f9a1878c650>, <CornerApp.TestObject: 0x7f9a1878c680> ) (lldb) po [array debugDescription] <__NSArrayI 0x7f9a1878c6b0>( <CornerApp.TestObject: 0x7f9a1870fc60>, <CornerApp.TestObject: 0x7f9a1878c650>, <CornerApp.TestObject: 0x7f9a1878c680> ) (lldb) po array[0] <CornerApp.TestObject: 0x7f9a1870fc60> (lldb) po array[0].name error: property 'name' not found on object of type 'id' error: 1 errors parsing expression (lldb) po [array[0] name] name (lldb)
p — это print
po — это print object, кидает объекту сообщение description, обратите внимание, что объектам еще можно послать сообщение debugDescription
po array[0].name — не работат, потому что для отладчика нулевой элемент в массиве типа id. А вот посылка сообщения name (po [array[0] name]) прекрасно работает. Не забываем, про то, что obj-c — это message oriented язык программирования.
Найди меня
Следующий кейс: у нас есть API — мы ходим на сервер за списком стран, потом преобразуем их во внутреннюю логику и где-то храним. Например, наша modelView идет за данными в хранилище и ищет модельку в словаре по ключу:
- (CACountry *)countryByCode:(NSString *)code { return [_countries objectForKey:code]; }
Что мы видим в Variables? 242 страны, отлично, как нам быстро найти Россию?
Знаю, вот так:
(lldb) po [_countries objectForKey:@"RU"] <CACountry: 0x7fae00630ba0> (lldb) po [[[_countries objectForKey:@"RU"] title] string] Россия
И хочу заметить, что в строке отладчика прекрасно работает автодополнение для посылки сообщений в objective-c
Магические UIView
Наверняка, если делали какой-нибудь нетривиальный UI были ситуации, когда что-нибудь в интерфейсе съехало и нужно разобраться, кто виноват. При это перезапуск приложение грозит тем, что может не удастся воспроизвести ситуацию. Вот тут-то работа с отладчиком незаменима.
В результате выполнения простого
(lldb) po self.view.subviews
увидим что-то вроде такого:
<UICollectionView: 0x7fd9fb81a200; frame = (0 0; 375 667); clipsToBounds = YES; opaque = NO; autoresize = W+H; gestureRecognizers = <NSArray: 0x7fd9fb416cb0>; layer = <CALayer: 0x7fd9fb4067f0>; contentOffset: {0, -180}; contentSize: {375, 843}> collection view layout: <TGLStackedLayout: 0x7fd9fb410000>, <CASortView: 0x7fd9fb4468c0; frame = (67.5 607; 240 60); clipsToBounds = YES; alpha = 0; opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fd9fb481290>>, <UIView: 0x7fd9fb47e240; frame = (0 0; 375 687); alpha = 0; layer = <CALayer: 0x7fd9fb4895a0>>
Сразу видим набор view, их фреймы, свойства, всё то, что запихнули разработчики Apple в стандартное сообщение description.
Если нужно легко можем уточнить какое-нибудь свойство, можно использовать адрес в памяти напрямую:
(lldb) po [0x7fae2b792ba0 backgroundColor] UIDeviceWhiteColorSpace 0 1
А вот вам напоследок кусок кода, который может доставать по иерархии все view заданного класса, может покажется полезным. Сам использую.
import UIKit extension UIView { func debugAllSubviewsOfClass(cls: AnyClass) -> [String] { func goDeepAndPrint(inout views: [String], currentView: UIView) { for v in currentView.debugSubview() { views.append(v.debugDescriptionWithParent()) goDeepAndPrint(&views, currentView:v) } } var views = [String]() goDeepAndPrint(&views, currentView:self) return views } func debugDescriptionWithParent() -> String { let parentAddress = self.superview != nil ? String(format: "%p", self.superview!) : "nil" return "\(self.description), parent = \(parentAddress)" } func debugSubview() -> [UIView] { return self.subviews } } extension UITableView { override func debugSubview() -> [UIView] { return self.subviews + self.visibleCells } } extension UICollectionView { override func debugSubview() -> [UIView] { return self.subviews + self.visibleCells() } }
Summary
- С отладчиком можно работать не только через кнопочки Xcode.
- Как настроить открытие консоли при отладке в новой вкладке? Самое начало — большая картинка
- Быстрый переход в консоль — Cmd + Shift + C,
свернуть/развернуть консоль — Cmd + Shift + Y - Наши новые команды:
Step Into — step или коротко s
Step Over — next или коротко n
Continue — continue или c
Отключить все брейкпоинты — breakpoint disable
Вот тут весь список команд LLDB. - Obj-c не видит свойства объекта Swift-ового класса? Не беда:
(lldb) po [array[0] name]
- В окне variables 242 ключа у словаря?
Ищем быстро:
(lldb) po [[[_countries objectForKey:@"RU"] title] string] Россия
- Облегчаем себе отладку UIView — чуть выше summary есть немного полезного кода
Всем спасибо, кто прочитал. Надеюсь пару приёмчиков кто-то для себя новых открыл.
Описал каждую из возможностей не подробно, но старался показать направление, кому нужно — может разобраться глубже или спросить в комментариях!
ссылка на оригинал статьи http://habrahabr.ru/post/269095/
Добавить комментарий