CocoaPods не предоставляет из коробки инструментов для повторного использования уже собранных артефактов между разными машинами разработчиков. Да и с локальным кэшированием существует ряд проблем.
Да, модули выкачиваются и сохраняются на диск, но они загружаются и подключаются к проекту в виде исходников. Это создаёт проблему, поскольку большое количество сторонних модулей, исходники которых практически никогда не требуется редактировать, замедляют индексацию и работу автокомплита в Xcode.
Конечно, из исходников модуля мы в итоге получаем бинарные артефакты при сборке. Но CocoaPods и сама система сборки Xcode не всегда корректно определяют набор модулей, которые необходимо пересобрать после изменений в коде проекта. В результате уже собранный модуль может пересобираться заново, а за ним — все зависимые от него модули также будут отправлены на пересборку. Простая очистка всего проекта приведет к тому же. А хотелось бы использовать уже собранные бинарные артефакты и не пересобирать исходники дважды, если они действительно не менялись.
В общем, я всё это к тому, что инструменты вроде Rugby, который мы упомянули в этом разделе, появились не просто так.
Нет, мы этого не делаем. Подключение подов к проекту выполняется через команду pod install, которую мы вызываем после генерации проекта. В Podfile указываются поды, которые нужно подключить к конкретному таргету проекта. Важно лишь следить за тем, чтобы имена таргетов в Project.swift для Tuist и в Podfile для CocoaPods совпадали.
Последние машины на Intel были выпущены в 2019 году. Apple обычно поддерживает свои продукты около 7 лет. Так что еще год-два скорее всего будут обновлять.
Я не специалист по хакинтошу, но предполагаю, что с большой долей вероятности потребуется яблочная железка.
Не то чтобы прям закончилась, но близится к окончанию, на мой взгляд. Apple все же еще поддерживает Intel-based машины, поэтому и версии Xcode для них еще будут выходить.
C DependencyProvider ничего делать не нужно. Он будет зарегистрирован для конкретного контейнера во внутреннем регистре фабрик __DependencyProviderRegistry в сгенерированном коде.
У каждого контейнера, который наследуется от базового класса Component, есть следующий конструктор:
В методе createDependencyProvider() и происходит обращение к фабрике, которая создает DependecyProvider без каких-либо дополнительных действий со стороны разработчика:
private func createDependencyProvider() -> DependencyType {
let provider = __DependencyProviderRegistry.instance.dependencyProvider(for: self)
if let dependency = provider as? DependencyType {
return dependency
} else {
// This case should never occur with properly generated Needle code.
// Needle's official generator should guarantee the correctness.
fatalError("Dependency provider factory for \(self) returned incorrect type. Should be of type \(String(describing: DependencyType.self)). Actual type is \(String(describing: dependency))")
}
}
В RIBs у модуля может быть сущность Component, которая отвечает за зависимости модуля и помогает Builder-у в создании частей модуля. Вот этот компонент как раз может быть DI-контейнером Needle.
Не все проекты используют RIBs. Needle позволяет получить такое дерево контейнеров для любого архитектурного подхода (MVVM, MVC, etc).
Конечная цель генератора кода заключается в предоставлении DI-контейнеру зависимостей из других DI-контейнеров.
Допустим, что у нас есть такой контейнер:
protocol SomeUIDependency: Dependency {
var router: Router { get }
}
final class SomeUIComponent: Component<SomeDependency> {
var someObject: SomeObjectClass {
shared {
SomeObjectClass(router: dependecy.router)
}
}
}
router — это зависимость, которая предоставляется каким-то другим DI-контейнером. Пусть это будет RouterComponent.
Тогда генератор кода для SomeUIComponent создаст DependencyProvider, который может выглядеть следующим образом:
private class SomeUIComponent34170097de9901d91dcProvider: SomeUIDependency {
var router: Router {
return routerComponent.router
}
private let routerComponent: RouterComponent
init(routerComponent: routerComponent) {
self.rootComponent = routerComponent
}
}
Для связи между различными DependencyProvider и контейнерами генератор кода создает глобальную функцию registerProviderFactories(),
которую мы должны вызвать в своем коде до начала использования DI-контейнеров.
Внутри этой функции для рассмотренного SomeUIComponent будут находится следующие строки:
__DependencyProviderRegistry.instance.registerDependencyProviderFactory(for: "^->RootComponent->SomeUIComponent") { component in
return SomeUIComponent34170097de9901d91dcProvider(component: component)
}
Если какая-то зависимость не находится, то генератор кода достаточно информативно оповещает об этом:
warning: Could not find a provider for (router: Router) which was required by SomeUIDependency, along the DI branch of ^->RootComponent->SomeUIComponent.
warning: Missing one or more dependencies at scope.
error: Some dependencies are missing, please look at the warnings above for the list.
CocoaPods не предоставляет из коробки инструментов для повторного использования уже собранных артефактов между разными машинами разработчиков. Да и с локальным кэшированием существует ряд проблем.
Да, модули выкачиваются и сохраняются на диск, но они загружаются и подключаются к проекту в виде исходников. Это создаёт проблему, поскольку большое количество сторонних модулей, исходники которых практически никогда не требуется редактировать, замедляют индексацию и работу автокомплита в Xcode.
Конечно, из исходников модуля мы в итоге получаем бинарные артефакты при сборке. Но CocoaPods и сама система сборки Xcode не всегда корректно определяют набор модулей, которые необходимо пересобрать после изменений в коде проекта. В результате уже собранный модуль может пересобираться заново, а за ним — все зависимые от него модули также будут отправлены на пересборку. Простая очистка всего проекта приведет к тому же. А хотелось бы использовать уже собранные бинарные артефакты и не пересобирать исходники дважды, если они действительно не менялись.
В общем, я всё это к тому, что инструменты вроде Rugby, который мы упомянули в этом разделе, появились не просто так.
Нет, мы этого не делаем. Подключение подов к проекту выполняется через команду pod install, которую мы вызываем после генерации проекта. В Podfile указываются поды, которые нужно подключить к конкретному таргету проекта. Важно лишь следить за тем, чтобы имена таргетов в Project.swift для Tuist и в Podfile для CocoaPods совпадали.
Последние машины на Intel были выпущены в 2019 году. Apple обычно поддерживает свои продукты около 7 лет. Так что еще год-два скорее всего будут обновлять.
Я не специалист по хакинтошу, но предполагаю, что с большой долей вероятности потребуется яблочная железка.
Не то чтобы прям закончилась, но близится к окончанию, на мой взгляд. Apple все же еще поддерживает Intel-based машины, поэтому и версии Xcode для них еще будут выходить.
DependencyProvider
ничего делать не нужно. Он будет зарегистрирован для конкретного контейнера во внутреннем регистре фабрик__DependencyProviderRegistry
в сгенерированном коде.У каждого контейнера, который наследуется от базового класса
Component
, есть следующий конструктор:В методе
createDependencyProvider()
и происходит обращение к фабрике, которая создаетDependecyProvider
без каких-либо дополнительных действий со стороны разработчика:В RIBs у модуля может быть сущность Component, которая отвечает за зависимости модуля и помогает Builder-у в создании частей модуля. Вот этот компонент как раз может быть DI-контейнером Needle.
Не все проекты используют RIBs. Needle позволяет получить такое дерево контейнеров для любого архитектурного подхода (MVVM, MVC, etc).
Допустим, что у нас есть такой контейнер:
router
— это зависимость, которая предоставляется каким-то другим DI-контейнером. Пусть это будетRouterComponent
.Тогда генератор кода для
SomeUIComponent
создастDependencyProvider
, который может выглядеть следующим образом:Для связи между различными
DependencyProvider
и контейнерами генератор кода создает глобальную функциюregisterProviderFactories()
,которую мы должны вызвать в своем коде до начала использования DI-контейнеров.
Внутри этой функции для рассмотренного
SomeUIComponent
будут находится следующие строки:Если какая-то зависимость не находится, то генератор кода достаточно информативно оповещает об этом: