5 ключових помилок iOS-розробника-початківця: як їх уникнути | robot_dreams
Для отслеживания статуса заказа — авторизируйтесь
Введите код, который был выслан на почту Введите код с SMS, который был выслан на номер
 
Код действителен в течение 5 минут Код с sms действителен в течение 5 минут
Вы уверены, что хотите выйти?
Сеанс завершен
На главную
5 ключових помилок iOS-розробника-початківця

5 ключових помилок iOS-розробника-початківця

І як їх уникнути

IOS-розробка всіяна дрібними деталями, які легко пропустити. Деякі з них — мінорні, а деякі переростають у звички, яких складно позбутися. 

В цій статті підкреслюємо наш курс із Мобільної розробки на Flutter і розповідаємо про поширені помилки новачків в iOS-розробці. Для зручності ділимо їх на дві групи — ті, що відносяться до хард- і до софт-скілів. Перші часто повʼязані з тим, що розробник може не знати особливостей iOS або підходів до написання коду (SOLID/DRY). Другі — зі страхом погано проявити себе у новій команді.

Hard skills

Помилка №1: Не додали модифікатор weak під час використання патерну делегування

Ця помилка — найпоширеніша на старті, але водночас і найлегша для виправлення. Розгляньмо приклад.

Під час рев’ю коду легко не помітити, що делегат в UserDetailsViewController оголошений без модифікатора weak. На перший погляд здається, що нічого страшного не відбувається — застосунок працює, екрани відкриваються. Але проблема ховається глибше.

Уявімо простий застосунок із двома екранами:

  • Перший екран — список користувачів
  • Другий екран — деталі конкретного користувача, де можна відредагувати його дані.

Користувач відкриває список, натискає на людину, переходить на екран деталей, потім повертається назад. І так багато разів — наприклад, адміністратор переглядає та редагує десятки користувачів за одну сесію.

В коді ж усе відбувається так:

Перший екран (UsersListViewController) створює другий екран (UserDetailsViewController) і зберігає на нього посилання. Це нормально — так система знає, який екран зараз відкритий.

Але в UserDetailsViewController є делегат, який вказує назад на UsersListViewController. І якщо цей делегат оголошений без weak, виходить така ситуація:

  • UsersListViewController сильно тримає UserDetailsViewController
  • UserDetailsViewController сильно тримає UsersListViewController

Вони наче тримаються один одного і не дозволяють системі видалити себе з пам’яті.

На практиці ж це означає ось що:

Коли користувач закриває екран деталей та повертається до списку, UserDetailsViewController не звільняється з пам’яті, хоча вже не потрібен. Це і є витік пам’яті.

Якщо користувач відкрив 10 різних профілів — у пам’яті залишаться 10 непотрібних об’єктів UserDetailsViewController. З часом таких об’єктів стає все більше, застосунок починає споживати забагато пам’яті — і в підсумку може просто впасти. В цей момент фонові процеси зупиняються, і частина даних може не встигнути синхронізуватися з сервером.

Саме тому делегати майже завжди потрібно оголошувати як weak: це дозволяє системі коректно звільняти пам’ять і уникати подібних проблем.

Помилка №2: Один Storyboard для всіх екранів застосунку

Використовувати storyboard з кількома екранами — це нормально, особливо в середніх та великих застосунках. Так ми зберігаємо пов’язані користувацькі сценарії в одному місці, і кодову базу простіше підтримувати.

Проблеми починаються тоді, коли в одному storyboard намагаються зберігати всі екрани застосунку одразу. Уявімо, що в storyboard уже є 2–3 складних екрани, і ви додаєте ще один. Що відбувається далі?

Кожного разу, коли ви відкриваєте storyboard, Xcode змушений прочитати його XML-код і зібрати інтерфейс для всіх екранів усередині файлу. І хоча Xcode інколи кешує відкриті раніше storyboard, цей кеш легко може очиститися.

В результаті чим більше екранів у storyboard, тим складніші в них UI-ієрархії — і тим довше Xcode відкриває файл. Ви просто сидите і чекаєте, поки інтерфейс прогрузиться і відмалюється. З часом робота зі storyboard перетворюється на біль.

При цьому Apple вже давно дала інструменти, які дозволяють уникати такої ситуації.

Як розв’язати проблему

  • Виносьте складні UI-блоки в окремі UIView

Замість того щоби будувати великий екран із десятків вкладених елементів прямо в storyboard, краще створювати окремі компоненти, що наслідуються від UIView, та використовувати їх як готові блоки. Так екран у storyboard стає простішим, а підтримувати код — легше. Маленькі незалежні компоненти набагато зручніші за одну величезну і заплутану ієрархію.

  • Розбивайте складний екран на кілька UIViewController

Якщо екран настільки складний, що простіше мислити не UIView, а цілими контролерами, його можна зібрати з кількох UIViewController. У такому випадку один контролер виступає контейнером, а інші — його дочірніми.

  • Діліть один великий storyboard на кілька менших

Якщо користувацький сценарій містить 10–15 екранів (наприклад, довгий онбординг — що трапляється дуже часто), не варто тримати їх усі в одному storyboard. Хороша практика — мати окремі storyboards для екранів входу в застосунок (логін, реєстрація), для онбордингу і для основної частини застосунку.

Для переходів між такими storyboards в Xcode є спеціальний інструмент — Storyboard Reference. Він дозволяє з’єднувати різні storyboards між собою без хаосу та перевантажених файлів.

Помилка №3. Порушення принципів SOLID

Знати назви принципів SOLID — ще не означає розуміти, де і навіщо їх застосовувати. Саме тому на співбесідах розробників будь-якого рівня часто просять пояснити принципи SOLID своїми словами або виправити код, у якому ці принципи порушені.

Розберемо приклад і подивимось, у чому помилка та як правильно її виправити.

У чому проблема в коді?

В нас є клас UserDetailsViewController. У методі viewDidLoad() він:

  • Налаштовує зовнішній вигляд екрана
  • Задає header і footer для списку scrollableMenuView
  • Додає підкомпоненти (addDefaultSubviews())
  • Виставляє constraints (setupDefaultConstraints())

До цього моменту все виглядає нормально.

Але далі, після виклику super.viewDidLoad(), у цьому ж методі відбувається налаштування UINavigationController — тобто конфігурація навігації. Тут і з’являється проблема. Ми ніби припускаємо, що UserDetailsViewController завжди буде відкриватися через pushViewController(_:animated:). Отже, він точно знаходиться всередині UINavigationController, але це не гарантується.

Цей екран можуть показати:

  • Через pushViewController — тоді navigationController існує
  • Модально через present(_:animated:) — і тоді navigationController буде nil

У другому випадку код налаштування навігації або не зробить нічого, або працюватиме некоректно, або взагалі плодитиме баги.

Який принцип SOLID тут порушено?

Тут порушується D — Dependency Inversion Principle. Він передбачає, що модулі верхнього рівня не мають залежати від деталей реалізації модулів нижчого рівня.

В нашому ж випадку:

UserDetailsViewController знає занадто багато про те, як саме він буде показаний, і він напряму працює з navigationController, хоча не відповідає за навігацію. 

Навігація — це інша відповідальність і вищий рівень абстракції, ніж логіка конкретного екрана. UserDetailsViewController має займатися тільки своїм UI та логікою екрана.

Тому код, який конфігурує navigationController, потрібно повністю винести з viewDidLoad() і розмістити там, де відбувається навігація.

Soft skills

Помилка №1: Прагнення зробити ідеально замість зробити вчасно

На старті кар’єри легко потрапити в пастку перфекціонізму. Хочеться писати лише правильний код, одразу з гарною архітектурою, без жодного сумнівного рішення. Це природне бажання, але воно часто грає проти початківців.

До прикладу, задача вже може працювати й виконувати бізнес-вимоги, але замість того, щоби показати результат команді або відправити на рев’ю, новачки можуть ще трохи «покращити» роботу. Далі ж починається дрібний рефакторинг, зміни архітектури та оптимізація того, що поки не є проблемою.

Де тут проблема і що важливо зрозуміти

Поки рішення доводиться до ідеалу, дедлайн підходить усе ближче, після правок з’являються нові баги, а команді складно трекати реальний статус задачі. Тому важливо розуміти, що в командній розробці «правильно» не завжди означає «ідеально». Часто пріоритети виглядають так:

  • Функціонал працює
  • Рішення доставлено вчасно
  • Код достатньо зрозумілий для підтримки

Помилка №2: Страх проявляти ініціативу

Можна писати якісний код, але коли справа доходить до комунікації, мотивації та ініціативності, багато початківців губляться. Особливо це помітно на перших місяцях роботи в команді.

У нових командах новачкам зазвичай допомагають адаптуватися: пояснюють процеси, дають прості задачі, перевіряють результат і поступово зменшують рівень контролю. В якийсь момент це означає, що від вас очікують самостійності.

Втім, далі зʼявляється поширена помилка — сприймати задачу занадто вузько:

  • «Мені дали таску — я її просто реалізую».

В реальній же розробці цього часто недостатньо. Наприклад, вам потрібно реалізувати новий екран налаштувань, де користувач може змінювати особисті дані: ім’я, прізвище, вік, email.

І тут може виникнути купа питань:

  • Дизайн не дуже зрозумілий
  • Які поля обов’язкові, а які — опціональні
  • Немає згадки про аналітику змін
  • Незрозуміло, як ці дані використовуються далі

Якщо мовчки реалізувати те, що є в описі, і нічого більше, команда може отримати екран, який формально працює, але не розв’язує бізнес-задачу.

Тому напрошується висновок, що ініціатива — це не «робити більше, ніж просили». Це вміння побачити, чого бракує, і поставити правильні запитання. Зрештою, відсутність ініціативи виглядає гірше, ніж помилки.

Ещё статьи
Порівнюємо швидкість, якість і відповідальність за результат