Как скопировать абстрактный фрагмент в Kotlin для просмотра контроллеров в Swift - PullRequest
1 голос
/ 23 января 2020

Я работаю над реализацией iOS версии существующего Kotlin Android приложения. Специфика c, которую я воспроизводю, представляет собой пошаговый рабочий процесс мастера.

Как я это сделал в Android

В Android, библиотеке , которую я использовал * У 1006 * был следующий процесс:

  • Добавить "шаговый" вид к действию root и предоставить StepAdapter этому виду
  • StepAdapter контролирует количество шагов и возвращает каждый шаг по запросу по индексу.
  • Каждый шаг - это Fragment, реализующий интерфейс Step, который обеспечивает ловушки для проверки и перехода между шагами.

В итоге я создал абстрактный тип Fragment, который обеспечивает реализации по умолчанию для методов Step:

abstract class StepFragment(private val index: Int) : Fragment(), Step {
    ...overriding some methods from Fragment
    ...implementing methods from Step
}

Каждый шаг Fragment наследует этот класс, передавая жестко кодированный index в конструктор StepFragment. Шаги могут переопределить некоторые методы из StepFragment, а некоторые из них также вызывают реализацию суперкласса (я использую аннотацию @CallSuper, чтобы облегчить это). StepAdapter создает и возвращает каждый из этих фрагментов.

Как я пытаюсь это сделать в iOS

Вернувшись в мир iOS / Swift, я обнаружил похожая библиотека , но все, что она предоставляет, это представление индикатора выполнения. Он не обрабатывает создание и отображение содержимого каждого шага, как Android. Мне нужно разобраться с этим сам.

Однако вы можете предоставить делегату степперу, который позволит вам подключаться к переходам (willSelectIndex, didSelectIndex, canSelectIndex и т. Д. c.). Я сделал root ViewController делегатом для степпера. Это ViewController имеет вид индикатора выполнения в верхней части и контейнер для каждого шага под индикатором выполнения. ViewController каждого шага встроен в соответствующий контейнер. Чтобы контролировать переходы между шагами, я просто показываю и скрываю эти виды контейнера. Я понял эту часть.

Чего я не понял, так это как скопировать класс StepFragment из Android Fragment s в Swift ViewController s. У меня следующие проблемы:

  • Swift не имеет абстрактных классов (по некоторым причинам).
  • Я не создаю экземпляр шага ViewController s; это обрабатывается внутри раскадровкой. Это означает, что я не могу предоставить индекс шага в конструкторе, как в Android. Абстрактное свойство было бы типичным способом обойти это, но (см. Выше) Swift не имеет абстрактных классов.

Я мог бы обойти эти проблемы несколькими способами:

  • Вместо абстрактного класса я могу использовать протокол. Я могу указать требование, чтобы все классы, которые соответствуют протоколу, были ViewController с, но я не могу переопределить методы из ViewController в протоколе (насколько я мог видеть). Я могу добавить расширение к протоколу, чтобы обеспечить функции реализациями по умолчанию, которые затем могут переопределить разработчики, и они могут даже вызывать исходные функции (используя (self as Protocol).func()). Однако это кажется очень неуклюжим.
  • Вместо абстрактного класса я могу использовать обычный класс. Я могу добиться всего, чего хочу, за исключением того, что не могу добиться того, чтобы подкласс реализовывал абстрактные члены во время компиляции. Мне нужно было бы использовать что-то вроде fatalError() в базовом классе, который выбрасывает только во время выполнения. Это также кажется неуклюжим.
  • Я продолжаю слышать о шаблоне «делегат», и я думаю, что это хороший элегантный способ решить множество проблем «быстро», но я понятия не имею, как бы я используйте это здесь. Я думаю, что предпочел бы иметь возможность сделать это таким образом, чем два вышеуказанных.

TL; DR

Подводя итог моей проблеме, я ищу способ для нескольких " шаг "child ViewController s", чтобы подключиться к рабочему процессу мастера, контролируемому родителем ViewController. Они должны быть в состоянии выполнить некоторые (потенциально асинхронные c) логи c при выборе шага, перед переходами и даже переходами блоков. Я должен иметь возможность игнорировать некоторые из этих хуков, которые затем должны использовать реализацию по умолчанию.

1 Ответ

0 голосов
/ 24 января 2020

Я обнаружил, что вы на самом деле можете предоставить реализации по умолчанию для функций протокола, поэтому я пришел к решению:

protocol StepViewController: UIViewController {
    var stepIndex: Int { get }

    func onBackClicked(_ goToPreviousStep: () -> Void)

    ...
}

extension StepViewController {
    // this is a default implementation, so implementors don't have to provide it
    func onBackClicked(_ goToPreviousStep: () -> Void) {
        goToPreviousStep()
    }

    ...
}

class StepOneViewController: UIViewController, StepViewController {
    let stepIndex: Int = 0

    func onBackClicked(_ goToPreviousStep: () -> Void) {
        // if I want to call the default implementation I can do this:
        (self as StepViewController).onBackClicked(goToPreviousStep)
    }
}
...