Предложения по внедрению зависимостей для просмотра контроллеров в swift - PullRequest
0 голосов
/ 05 июля 2019

Я делаю приложение для iOS со Swift, которое имеет разные состояния для большинства контроллеров представления, составляющих приложение. Несколько «состояний», от которых зависят контроллеры представлений, связаны с тем, вошел ли пользователь в систему или нет, или адрес зарегистрирован, найден или отсутствует, и т. Д. В настоящее время данные передаются контроллерам представлений в prepare(for:sender) методы.

Ниже приведена структура моего приложения, и существует еще около десятка контроллеров представления с аналогичной структурой.

App.swift

struct App {
  enum LoginState {
    case unregistered
    case registered(User) // User defined elsewhere
  }

  enum OtherState {
    case stateOne
    case stateTwo(AssociatedType)
    case stateThree(OtherAssociatedType)
  }

  // Default states
  var loginState: LoginState = .unregistered
  var otherState: OtherState = .stateOne
}

HomeViewController.swift

class HomeViewController: UIViewController {
  var app: App!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)

    switch segue.identifier {
    case "Other View Controller Segue":
      let otherVC = segue.destination as! OtherViewController
      otherVC.app = app

    default:
      break
    }
}

AppDelegate.swift

class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?
  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let storybard = UIStoryboard(name: "Main", bundle: nil)
    let mainNavController = storyboard.instantiateViewController(withIdentifier: "Main Navigation Controller") as! UINavigationController
    let homeViewController = mainNavController.topViewController as! HomeViewController

    window?.rootViewController = mainNavController
    // 'injecting' app to the homeViewController
    homeViewController.app = App()

    return true
}

Я не могу найти оригинальную запись, которую я нашел, когда впервые столкнулся с «как я могу передавать данные между контроллерами представления» около года назад, но это, вероятно, один из них: Передача данных между контроллерами представления (который нигде не упоминает термин внедрение зависимости). Затем я услышал этот термин внедрение зависимостей около месяца назад, и этот причудливый термин, казалось, соответствовал моей ситуации с обработкой класса (HomeViewController и OtherViewController), который должен иметь дело с данными, которые могут иметь состояния (struct App).

Чтобы проверить этот подход к бросанию экземпляра app в segue, я провел несколько ночей исследования. Но теперь я перегружен слишком большим количеством информации о: нескольких методологиях внедрения зависимостей , модульном тестировании в быстром режиме через DI , нескольких инфраструктурах DI здесь , здесь , здесь , и здесь , рамки модульного тестирования здесь , здесь и (теперь я не могу добавить больше ссылок из-за отсутствия репутации ..) и целая куча сообщений среднего / блога / SO.

Вопрос в следующем: 1. Я делаю так называемое внедрение зависимостей здесь, и это «правильный путь»? 2. Могу ли я продолжить юнит / Тестирование пользовательского интерфейса с помощью этого подхода? 3. Если то, что я делаю, является законным внедрением зависимости, то зачем нужен каркас внедрения зависимости?

Фреймворки внедрения зависимостей выглядят ненужными, загадочные , (и страшно), по крайней мере, для меня просто попытка написать поддерживаемое приложение, которое следует принципам SOLID. Я устал от абстрактных концепций или, казалось бы, не связанных между собой примеров с моей ситуацией, поэтому я был бы рад, если бы кто-нибудь помог мне с этими концепциями и проектными решениями, включая необходимость в фреймворках.

Ответы [ 2 ]

1 голос
/ 05 июля 2019

Я бы посоветовал не концентрироваться на технических деталях различного типа DI, и я бы сосредоточился на основной концепции.DI означает, что ваш контроллер представления не получает зависимости, которые ему нужны, но зависимости предоставляются от за пределами .Таким образом, ваш otherVC.app = app является очень маленьким базовым примером DI.

Короче говоря, теперь вы можете протестировать свой контроллер представления, передавая различные экземпляры app, и это главная цель создания DI.

Можете ли вы добиться большего успеха?Ну, наверное.Например, сделать ваш App объект немного меньше, разделив «состояние» на более мелкие части.Другим улучшением может быть использование протокола вместо конкретного типа в вашем контроллере представления.Таким образом, во время теста вы можете передать фиктивный объект как зависимость, и это очень вам поможет для тестов.

0 голосов
/ 06 июля 2019

Я согласен с ответом IgnazioC и хочу добавить кое-что.

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

  • Могу ли я получить любого моего потребителя (viewController) и запустить его с новыми зависимостями, которые я установил снаружи. Если ответ да. Это хорошая практика для DI.
  • Как легко я могу это сделать и как легко я могу написать необходимый код, чтобы использовать это. Этот ответ решает, насколько хороша ваша практика.

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

  • Хорошая идея - решить зависимости viewControllers от другого viewController? Действительно, это работа viewController? или так и должно быть? Я не думаю, что это хорошая практика в большинстве случаев.

  • Что происходит, когда у вас есть сценарий, когда цепочка viewController представляет себя, и большинство ваших зависимостей (например, информация о пользователе) должны переноситься между первым и последним viewController в этой цепочке, но не все. Это создает некоторые коды копирования. Возможно, что-то из этого можно сделать с помощью составного шаблона или что-то вроде этого, но не для всех.

Я думаю (может быть, я снова ошибаюсь) переносить зависимости между потребителями не очень хорошая идея По крайней мере, в основном. Может быть, вы напишите достаточно маленькое приложение, чтобы справиться с этими проблемами. Но в большинстве случаев зависимости должны разрешаться вне цепочек viewController.

Примечание: я не включаю зависимости, которые были созданы из предыдущего контроллера, как это происходит в сценариях с мастер-деталями. Они разные вещи.

На данный момент это довольно сложно. Может быть, Swift нуждается в некоторых улучшениях, сделать это проще (например, лучший отражатель). Но я нахожу статью об использовании DI в Swift 5.1. Я еще не использовал это. Но это кажется полезным решением. Может быть, это может помочь вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...