Оформление и структурирование классов в Swift

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Краткое руководство по грамотному оформлению интерфейсов.

Предисловие

Это руководство я публикую для своих учеников, которые только начинают свой пусть в изучении языка Swift. В этой небольшой заметке я хочу расписать основные аспекты правильного структурирования классов, что бы навигация по ним была интуитивно понятной, как для создателя, так и для стороннего наблюдателя.

Введение

Читаемость кода является одним из самых важным аспектом в программировании и поэтому существуют определенные стандарты, как в написании кода, так и в оформлении интерфейсов. Особенно это касается вью контроллеров, которые сами по себе являются довольно массивными объектами и поэтому навигация по ним должна быть предсказуемой, в не зависимости от того работаете ли вы со своим проектом или же со сторонним.

Структура класса

Класс всегда начинается со свойств, к которым относятся аутлеты, вычисляемые свойства, а также публичные и приватные переменные и константы:

final class ViewController: UIViewController {

  // MARK: - IB Outlets
  @IBOutlet var mainLabel: UILabel!
  @IBOutlet var secondaryLabel: UILabel!
  @IBOutlet var someLabel: UILabel!

  @IBOutlet var mainTextField: UITextField!
  @IBOutlet var secondaryTextField: UITextField!

  // MARK: - Public Properties
  var dataModel: DataModel!
  var someString = ""

  // MARK: - Private Properties
  private let dataManager = DataManager.shared
  private let networkManager = NetworkManager.shared
  private let imageManager = ImageManager.shared
}

Обратите внимание в какой последовательности объявлены свойства: сначала объявляются аутлеты, затем публичные переменные и константы, после которых уже идут приватные свойства. Так же обратите внимание на то, что аутлеты для лейблов разделяет пустая строка от аутлетов для текстовых полей. Такие разделители в виде пустых строк визуально отделяют логические блоки кода друг от друга, что повышает его читаемость. Не пренебрегайте ими, но и не злоупотребляйте. Достаточно одной пустой строки, что бы отделить одно от другого.

При помощи комментария // MARK: класс можно поделить на разделы. Эти комментарии играют роль заголовков, по которым можно быстро перемещаться по разделам. У каждого файла в проекте есть содержание, открыть которое можно, кликнув на название класса в верхней строке, в которой прописан путь до класса:

Содержание файла
Содержание файла

В этом списке отображаются все свойства и методы класса, а заголовки позволяют легче ориентироваться по всему содержимому и перемещаться в нужное место в один клик.

После свойств класса объявляются инициализаторы, если в них есть необходимость:

// MARK: - Initializers
init(name: String) {
  self.name = name
}

После инициализаторов объявляются переопределенные методы родительского класса. Это те методы, которые помечены ключевым словом override:

// MARK: - View Life Cycles
override func viewDidLoad() {
  super.viewDidLoad()
}

override func viewWillAppear(_ animated: Bool) {
  super.viewWillAppear(animated)
}

// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  
}

После переопределенных методов объявляются IB Actions, т.е. методы связанные с элементами пользовательского интерфейса:

// MARK: - IB Actions
@IBAction func buttonDidTapped() {
  
}

@IBAction func sliderValueOnChange(_ sender: UISlider) {
  
}

После IB Actions определяются методы экземпляра:

// MARK: - Public Methods
func fetchData(from url: URL) {
  
}

func doSomething() {
  
}

И в самом конце класса объявляются приватные методы. Это те методы, которые создаются для реализации внутренней логики самого класса:

// MARK: - Private Methods
private func setupUI() {
  
}

private func setupNavigationBar() {
  
}

private func showAler(witnTitle title: String, andMessage message: String) {
  
}

Так же классы могу иметь расширения или extensions. Расширения позволяют группировать методы со связанным функционалом в одном месте, что делает код более организованным и читаемым. Так если класс необходимо подписать под протокол, то для этого лучше определить отдельное расширение с соответствующим заголовком:

// MARK: - UITabvleViewDataSource
extension ViewController: UITableViewDataSource {
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
  }

  func tableView(_ tableView: UITabvleView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
  }
}

Кроме того расширения полезно использовать для распределения обязанностей между командой. В этом случае для каждого расширения создается отдельный файл, что позволяет работать над одним классом сразу нескольким участникам проекта.

В итоге структура класса должна выглядеть следующим образом:

// MARK: - IB Outlets

// MARK: - Public Properties

// MARK: - Private Properties

// MARK: - Initializers

// MARK: - Overrides Methods

// MARK: - IB Actions

// MARK: - Public Methods

// MARK: - Private Methods

Общие советы

  • Не храните в классе методы, которые ни как не используются. Т.е. если у вас есть метод viewDidLoad(), но при этом он пустой, то смело его удаляйте. Ни чего лишнего в коде быть не должно

  • Удаляйте все шаблонные комментарии, которые достаются вам “из коробки” при добавлении новых классов

  • Используйте в качестве разделителей логических блоков кода пустые строки, но не более одной

  • Названия классов должны быть емкими и отражать их суть. В проекте не должно быть классов с именем ViewController. Не сокращайте имена классов. В проекте не должно быть классов с именем MainVC.

Источник: https://habr.com/ru/articles/744470/


Интересные статьи

Интересные статьи

Не секрет, что на сегодняшний день Swift обладает одними из самых (возможно самыми) функциональными и гибкими в настройке перечислениями. Каждый Swift-разработчик может подтвердить, что работать с ним...
В Dart 3.0.0 появилось много новых вещей. Об одной из таких – модификаторы классов – мы сегодня и поговорим. Спойлер: 5 новых модификаторов + их комбинации: Base, Interface, Final, ...
Всем привет, на связи Никита и Технократия! В прошлой статье мы уже обсудили проблемы текущего состояния concurrency в Swift. Давайте двигаться дальше и сегодня мы начнем свое знакомство с необхо...
Думаю, вы знакомы с графиками сравнения точности архитектур. Их применяют в задачах по классификации изображений на ImageNet. В каждом сравнении которые я мог встретить ранее в Интернете, как пра...
Kotlin имеет много классных особенностей: null safety, smart casts, интерполяция строк и другие. Но одной из самых любимых разработчиками, по моим наблюдениям, являются data-классы. Нас...