− С новым годом, блин, − Слава полетел к приборной панели – говорил же, что что−то не то. Корабль затрясся снова, свет полностью вырубился, датчики топлива вдруг резко замерцали красным. – да что ж за фигня такая?
− Саша, проверь двигательный отсек, топлива нет, а я только сегодня пополнял.
− нифига не вижу, дверь заклинило.
− Черт, − Слава направился в сторону голоса, − подвинься, иди в приборную, следи за датчиками. −Коля, ты там заснул, мать твою? Быстро помоги мне. Коля оцепенело водил глазами и не двигался с места. – ты глухой что ли? – заорал Слава, продолжая толкать дверь. Вдруг свет включился, корабль перестало трясти, дверь в энергетический отсек открылась.
Слава начал проверять уровень топлива в баках. Странно, еще утром все было нормально, а сейчас ощущение, что где−то в корабле дыра. Пока Слава думал, как это выяснить, в голове появлялись нехорошие мысли. Коля слишком часто жаловался на условия, был всем недоволен и всячески отлынивал от заданий.
− ах ты сука, решил домой побыстрее попасть? А о том, что мы все сдохнем не потрудился подумать? – Слава резко развернулся к двери, из которой все еще было видно оцепенелого Колю. – я щас тебя без скафандра за борт выкину и будешь дыру латать! − Похоже эти слова привели Колю в чувство, он резко подлетел к двери и захлопнул ее. Из−за двери послышались голоса девчонок:
− Коля, ты что, рехнулся, быстро дверь от……
И тут резкий безумно громкий взрыв прогремел рядом. Всё потемнело.
Обучение не бывает без проб множества идей и провала множества раз.
Наверху окна очень удобное меню. Оно показывает для какого конкретно устройства Вы соберёте проект или какой симулятор запустить.
Наверху будут показаны устройства, подключенные к macOS, а ниже - доступные симуляторы. Если Ваше устройство не особо сильное, то используйте старые устройства наподобие iPhone SE для минимального воздействия на macOS.
Запустите симулятор, нажав Cmd+R Если это Ваше первое приложение на этом macOS (за исключением игровых площадок), то Вас попросят войти в режим разработчика, для чего введите пароль. Вы увидите чистый белый экран, так как мы ничего не сделали в нашем приложении.
Чтобы менять ориентацию устройства, используйте Cmd + Стрелка влево и Cmd + Стрелка вправо
Чтобы менять масштаб, используйте Cmd + Число(1…5).
Чтобы полностью выйти из симулятора, нажмите Cmd + Q. Чаще Вам просто нужно заново запустить приложение. Если Вы работаете, будучи подключенными к сети электропитания, то оставьте симулятор запущенным. Просто нажмите Cmd + ., чтобы закрыть приложение, но оставить сам симулятор активным.
Симулятор подходит не для всех приложений - взаимодействие с камерой, например, убьёт Ваше приложение, ибо у симулятора нет камеры.
Каким бы он не был удобным, всегда проводите тесты и на реальном устройстве.
Для запуска на реальном устройстве выберите его из списка и запустите. С первого раза запуск скорее всего не выйдет: нужно дать доверие Вашему аккаунту разработчика. Конкретные инструкции будут показаны непосредственно на устройстве.
Сперва откроем файл ViewController.swift
.
Изучим немного его строение.
Наверху идёт импорт библиотеки UIKit
- эта библиотека предназначена для создания графических элементов мобильных приложений. Её аналогом для macOS выступает AppKit
. В macOS используется фреймворк Cocoa
, в iOS - Cocoa Touch
. Многие их элементы крайне схожи, однако их подходы различаются. Этот курс посвящён Cocoa Touch
.
Далее идёт объявление класса ViewController
- наследника класса UIViewController
, который отвечает за управление отображением единственного окна приложения.
Он содержит два метода:
viewDidLoad()
- этот метод вызывается, когда контроллер прогружается в память в первый раз. В приложении может быть несколько контроллеров, и не все из них держатся в памяти постоянно: это связано с тем, что память мобильных устройств довольно ограничена.didReceiveMemoryWarning()
- метод вызывается контроллером, если программа получает сигнал о чрезмерном использовании памяти. В этом методе контроллер должен вычистить некритичные ресурсы. Если контроллер не вернётся в свои лимиты памяти, то приложение будет насильно убито. Пока что мы пишем простые приложения и можем не обращать на это особого внимания. Наличие ограничения вызвано тем, что у устройств на базе iOS нет огромных объемов оперативной памяти, как персональные компьютеры или Mac. Однако даже при наличии больших объемов памяти этот механизм спасает от незаметных утечек.Чтобы больше понять об утечках памяти, запустите мощную игру на компьютере под Windows (Skyrim, Witcher 3, Fallout 4) и попробуйте измерить занимаемый объем памяти в начале запуска и спустя много часов работы. Вы заметите, что он очень сильно возрос и помогает только перезапуск игры или системы в целом. Даже крупные программы имеют свойство создавать утечки памяти - ситуации, когда память занимают объекты, которые уже не используются и никогда уже не будут использованы. Раньше такое поведение встречалось часто - в языке C выделение памяти крайне рутинный процесс с ручным заданием объёмов, в старых стандартах C++ механизм был чуть лучше, но программисту всё равно приходилось думать об освобождении ресурсов, затем были добавлены уникальные и разделяемые указатели, а в Objective-C несколькими годами ранее придумали изученный нами автоматический механизм подсчета ссылок.
Оба этих метода вызывают варианты надкласса, так как UIKit
уже берет на себя очень большой кусок по обработке этих ситуаций.
Даже лучшие программисты не пишут совершенный код, ибо люди несовершенны. (Здесь Вы можете свернуться клубочком от безысходности.)
Рассмотрим разные виды ошибок.
Предупреждения (Warning
) или же варнинги - возникают при сборке кода и их проще всего исправить. Они не помешают коду быть собранным и даже работать без логических ошибок, однако считается лучшей практикой исправлять все предупреждения. Очевидные варианты предупреждений:
Давайте создадим предупреждение: впишите в методе viewDidLoad()
код let x = 11
.
Будет выведено сообщение с жёлтым значком треугольника с восклицательным знаком о том, что неизменяемая величина никогда не использовалась. Также тут дадут совет - заменить её имя на _
, чтобы контекст съел присвоенную величину. Когда Вы будете что-либо разрабатывать, Вам часто будет выдаваться это предупреждение, так живой (в реальном времени) поиск ошибок может работать быстрее, чем Вы пишите код.
Сотрите свой код.
Ошибка или исключение сигнализирует о более серьёзной проблеме, например, о невозможности собрать код.
Давайте сделаем ошибку!
Удалите закрывающую круглую скобку в вызове super.viewDidLoad()
.
Полученная ошибка сигнализирует: "ожидается выражение в списке выражений" ("Expected expression in the list of expressions"). Это значит, что компилятор пытается использовать код после первой круглой скобки как аргументы функции и это естественно не удаётся. Заметьте, как выглядит эта ошибка - красный восьмиугольник с восклицательным знаком.
Верните закрывающую круглую скобку.
Теперь введите код:
let x = 11
x = 61
Теперь появится другой вид ошибки - вместо восклицательного знака будет изображена точка. Такие ошибки называются исправимыми.
Щелкнув по кругу, Вы увидите предложения по исправлению ошибки - заменить квалификатор let
на var
. Нажмите на кнопку fix
. Запомните, что такой подход не всегда дась исправить все ошибки - он позволяет исправлять лишь незначительные проблемы.
Теперь у нас вылезло предупреждение, что переменная x
была сразу изменена, а её изначальное значение оказалось бесполезным. Казалось бы, ничего страшного, но переменная будет создана, что съест ресурсы памяти и процессора, хоть и временно. Научитесь мыслить в понятиях цены - у Вас есть ресурсы:
Они небесконечны, а использование любого из них можно считать платой за Ваши действия. Если не сможете эффективно и экономично их использовать, то приложение будет работать медленно, что вызовет у Вашего пользователя недовольство, а Вы получите меньше денег.
Не старайтесь добиться максимальной производительности в ущерб читаемости кода и переносимости - лучшим способом написать программу с минимумом ресурсов будет использование Ассемблера, однако время разработки составит огромную величину. Выигрыш при этом будет не самым лучшим - в режиме агрессивной оптимизации компилятор выдаст близкий к такому код, при этом Вам не придётся платить его развитием и своим временем.
Сотрите плоды своего творчества прежде, чем двигаться дальше.
Баги - ошибки в логике кода, которые возникают в процессе работы программы. Они условно разделяются на два типа: ошибки написания программы и ошибки моделирования бизнес логики.
Ошибки при написании программы, которые когда-нибудь обязательно выстрелят. Необязательно, что Вы найдёте их сами. При неграмотном написании кода или отсутствии тестирования может выйти так, что пользователь просто спишет с Вашего счёта деньги. Запомните: если что-то плохое может случиться, то оно обязательно рано или поздно случиться. Это можно понимать ещё и так, что если в Вашем коде есть потенциально опасная ситуация - например, что Ваш неявно извлекаемый опционал может принять значение nil
, то рано или поздно он его обязательно примет.
Второй тип ошибок мы не сможем рассмотреть на текущем этапе разработки. Они относятся к ошибкам моделирования бизнес-логики - например, неверно выведенная формула для расчёта платежей. Их исправление намного сложнее - при прочих равных ни программа, ни компилятор о них Вам не сообщат.
Давайте создадим наш собственный баг, дабы научиться их выискивать: для этого напишите следующий код после вызова super.viewDidLoad()
:
var courses = [1, 2]
courses.removeFirst()
courses.removeFirst()
courses.removeFirst()
Соберите приложение. Всё прошло без проблем. А теперь запустите его.
У нас вылезла ошибка fatal error: can't remove first element from an empty collection
(фатальная ошибка: нельзя извлечь первый элемент из пустой коллекции).
В коде будет показана точка ошибки с не самым понятным описанием. В консоли (1) же появится надпись (lldb). lldb
- отладчик в приложениях под Apple, он расшифровывается как low level debugger
и позволяет находить многие ошибки. Давайте убедимся, что коллекция действительно пуста. Два способа сделать это:
print courses
- первая изученная нами команда lldb
- она выводит содержимое переменной в консоль.Прежде, чем двигаться дальше, обратите внимание, что наша область слева перешла с навигатора на отслеживание программы. Там можно увидеть нагрузку на процессор в реальном времени, на диск, занимаемую оперативную память, сетевое взаимодействие. Вы можете использовать эти показатели лишь в относительном виде - симулятор не показывает реальных данных из-за принципа виртуализации. При отладке на реальном устройстве Вы также сможете увидеть эти показатели, и здесь они уже более достоверны. Учтите, что программа для отладки и релиз-вариант отличаются по своей сборке - как правило, релизный вариант быстрее варианта для отладки на некоторую величину ввиду дополнительных механизмов оптимизации.
Теперь попробуем найти момент, где возникла ошибка. Сперва отпустите наше приложение в мир иной уже известной нам командой Cmd + ..
Щёлкните по номеру строки около объявления массива. Появится синяя фигура - брейкпоинт или точка останова. Пусть будет брейкпоинтом. Мы же не на 1С пишем, чтобы извращать наш язык. Чтобы убрать точку останова снова нажмите по ней (сделайте это в конце занятия). Это выключит её, но не удалит - для удаления нажмите по ней правой кнопкой и выберите Delete breakpoint
.
Теперь запустите наше приложение. Наша строка будет отмечена зелёной - ход нашей программы остановился в этой точке. Как можно заметить, переменная courses
всё ещё пуста. Нажмите на 4-ую слева иконку на панели отображения переменных. Это переместит выполнение программы на один шаг вперёд. Эта кнопка называется Step over
.
И всё равно всё замечательно - в массиве два значения. Переместитесь на ещё один шаг вперёд.
Аналогично, в массиве остался один объект. Заметьте, что зелёная линия говорит о том, что мы находимся в точке выполнения этой инструкции, однако инструкция ещё не выполнена.
Продолжим путь.
Ошибки не возникло. Однако впереди ещё одна инструкция, а наш массив уже пуст. Чувствуете витающее в воздухе напряжение и предчувствие беды? Продолжаем.
А вот и наша ошибка. Благодаря проделанной нами работе, стало ясно, что ошибка возникает, когда мы пытаемся в третий раз извлечь элемент из коллекции, которая изначально имела всего 2 элемента.
Убейте приложение. Удалите код, внесённый нами. Отключите брейкпоинт.
Теперь Вы готовы понять главную мудрость этого урока: