Avatar ·

Как заменить #pragma mark из Objective-C в Swift? Есть ли аналог?

Всем привет! Я недавно перешел с Objective-C на Swift и никак не могу найти аналог привычной конструкции #pragma mark. В Objective-C я активно использовал #pragma mark - Lifecycle, #pragma mark - TableView Delegate и так далее, чтобы структурировать код в больших файлах. Это очень помогало при навигации через панель Jump Bar в Xcode.

Пробовал писать // MARK: с двумя слешами и пробелом, но Xcode иногда не отображает это в панели навигации. Вот пример моего кода:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    private func setupUI() {
        // настройка интерфейса
    }

    // MARK: - TableView DataSource

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

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

    // MARK: - Actions

    @objc private func buttonTapped() {
        print("Button tapped")
    }
}

Я хочу, чтобы в Jump Bar (выпадающем меню вверху редактора) отображались разделы: Lifecycle, TableView DataSource, Actions. Но иногда они не появляются, а иногда появляются только некоторые. Может быть, я неправильно ставлю комментарии? Или в Swift есть другой способ?

Подскажите, пожалуйста, как правильно организовать код в Swift, чтобы было удобно перемещаться по файлу? И есть ли какие-то скрытые фишки для этого?

<<>>

Правильное использование MARK, TODO и FIXME в Swift

Да, в Swift есть полный аналог #pragma mark — это комментарии // MARK:, // TODO: и // FIXME:. Они работают точно так же, как в Objective-C, но с небольшими синтаксическими особенностями. Давайте разберем всё по порядку.

Основные конструкции

В Swift для организации кода используются три типа комментариев, которые Xcode распознает в панели Jump Bar (выпадающее меню вверху редактора):

  • // MARK: — создает заголовок раздела в навигации.
  • // TODO: — отмечает незавершенную задачу (выделяется специальной иконкой).
  • // FIXME: — отмечает место, которое нужно исправить (тоже имеет свою иконку).

Синтаксис и тире

Самый важный момент: если вы хотите, чтобы в Jump Bar появилась горизонтальная линия-разделитель перед заголовком, нужно использовать дефис после двоеточия с пробелом:

// MARK: - Lifecycle

Без дефиса разделителя не будет, заголовок просто появится в списке. Вот правильный пример:

class ViewController: UIViewController {

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
    }

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

    // MARK: - TableView DataSource

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    // MARK: - Actions

    @objc private func buttonTapped() {
        print("Button tapped")
    }

    // TODO: - Добавить обработку ошибок

    // FIXME: - Исправить утечку памяти в этом методе
}

Почему ваши комментарии не отображаются?

Возможные причины:

  • Пробел после двоеточия обязателен: // MARK:- (без пробела) не сработает. Правильно: // MARK: -.
  • Комментарий должен быть на уровне класса: если вы поставите MARK внутри метода или замыкания, Xcode его не увидит.
  • Два слеша обязательно: комментарий /* MARK: */ не распознается.
  • Проблемы с кешем Xcode: иногда помогает перезапуск Xcode или очистка дериватов (Product → Clean Build Folder).

Дополнительные фишки

  • Группировка с вложенностью: нельзя создать вложенные разделы, но можно использовать названия вроде // MARK: - Network / Requests.
  • Кастомные иконки: если написать // TODO: - Сделать рефакторинг, в панели появится значок списка. Для // FIXME: — значок гаечного ключа.
  • Расширения (Extensions): лучший способ организации кода в Swift — выносить логику в отдельные расширения с MARK-комментариями. Пример:
// MARK: - ViewController

class ViewController: UIViewController { }

// MARK: - Lifecycle

extension ViewController {
    override func viewDidLoad() { }
}

// MARK: - TableView DataSource

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 }
}

Такой подход считается лучшей практикой в Swift-сообществе. Он не только делает навигацию идеальной, но и улучшает читаемость кода.

Заключение

Используйте // MARK: - Название с пробелом после двоеточия и дефисом для разделителей. Для задач и багов — // TODO: и // FIXME:. И, если файл становится слишком большим, разбивайте класс на расширения. Это стандартный подход в Swift, который полностью заменяет #pragma mark из Objective-C.

<<>>

Альтернативный подход: использование расширений (Extensions) для автоматической группировки

Вместо ручной расстановки MARK-комментариев можно использовать расширения. Когда вы выносите методы в отдельное расширение, Xcode автоматически группирует их в Jump Bar под именем расширения. Это даже удобнее, чем MARK, потому что:

  • Не нужно следить за синтаксисом комментариев.
  • Код становится модульным и легче тестируется.
  • Расширения можно выносить в отдельные файлы.
// Основной класс
class ProfileViewController: UIViewController {
    // общие свойства и методы
}

// MARK: - Lifecycle (расширение автоматически создаст раздел)
extension ProfileViewController {
    override func viewDidLoad() { }
    override func viewWillAppear(_ animated: Bool) { }
}

// MARK: - UITableViewDelegate
extension ProfileViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { }
}

В Jump Bar вы увидите разделы: ProfileViewController, Lifecycle, UITableViewDelegate. Это работает без единого MARK-комментария! Однако я рекомендую комбинировать оба подхода: использовать расширения для логических блоков и MARK для дополнительной наглядности. Так ваш код будет максимально чистым и удобным для навигации.