我发现Clean Swift架构中的Router
负责导航并向/ view controllers.
传递数据。有些示例和articles描述了Routers
使用segues传递并与视图控制器通信。当我不想使用来自Storyboard
的任何segue时,便利设计会是什么?是不是可以在Clean Swift中传递没有segue的数据?如果您用最简单的完整示例进行描述,我将不胜感激。
答案 0 :(得分:5)
文章说你可以:
// 2.以编程方式呈现另一个视图控制器
您可以使用它来手动创建,配置和推送viewController。
实施例
让我们假装你有ViewController
按钮(手柄推):
final class ViewController: UIViewController {
private var router: ViewControllerRouterInput!
override func viewDidLoad() {
super.viewDidLoad()
router = ViewControllerRouter(viewController: self)
}
@IBAction func pushController(_ sender: UIButton) {
router.navigateToPushedViewController(value: 1)
}
}
此ViewController
具有router
实施ViewControllerRouterInput
协议。
protocol ViewControllerRouterInput {
func navigateToPushedViewController(value: Int)
}
final class ViewControllerRouter: ViewControllerRouterInput {
weak var viewController: ViewController?
init(viewController: ViewController) {
self.viewController = viewController
}
// MARK: - ViewControllerRouterInput
func navigateToPushedViewController(value: Int) {
let pushedViewController = PushedViewController.instantiate()
pushedViewController.configure(viewModel: PushedViewModel(value: value))
viewController?.navigationController?.pushViewController(pushedViewController, animated: true)
}
}
navigateToPushedViewController
func可以使用你想要的任何参数(最好在配置新的vc之前封装参数,所以你可能想要这样做。)
并且PushedViewController
没有任何具体实施。只需configure()
方法和assert
(通知您有关configure()
次来电的通知):
final class PushedViewModel {
let value: Int
init(value: Int) {
self.value = value
}
}
final class PushedViewController: UIViewController, StoryboardBased {
@IBOutlet weak var label: UILabel!
private var viewModel: PushedViewModel!
func configure(viewModel: PushedViewModel) {
self.viewModel = viewModel
}
override func viewDidLoad() {
super.viewDidLoad()
assert(viewModel != nil, "viewModel is nil. You should call configure method before push vc.")
label.text = "Pushed View Controller with value: \(viewModel.value)"
}
}
注意:同样,我使用Reusable
pod来减少样板代码。
结果:
答案 1 :(得分:2)
如上所述,根据您的应用设计,您可以使用navigateToSomewhere
方法的选项2/3/4。
func navigateToSomewhere()
{
// 2. Present another view controller programmatically
// viewController.presentViewController(someWhereViewController, animated: true, completion: nil)
// 3. Ask the navigation controller to push another view controller onto the stack
// viewController.navigationController?.pushViewController(someWhereViewController, animated: true)
// 4. Present a view controller from a different storyboard
// let storyboard = UIStoryboard(name: "OtherThanMain", bundle: nil)
// let someWhereViewController = storyboard.instantiateInitialViewController() as! SomeWhereViewController
// viewController.navigationController?.pushViewController(someWhereViewController, animated: true)
}
答案 2 :(得分:1)
您需要跨协议传递数据
protocol SecondModuleInput {
// pass data func or variable
var data: Any? { get set }
}
protocol SecondModuleOutput {
// pass data func or variable
func send(data: Any)
}
第一位主持人
class FirstPresenter: SecondModuleOutput {
var view: UIViewController
var secondModuleInputHandler: SecondModuleInput?
// MARK: SecondModuleInput
func send(data: Any) {
//sended data from SecondPresenter
}
}
第二位主持人
class SecondPresenter: SecondModuleInput {
var view: UIViewController
var secondModuleOutputHandler: SecondModuleOutput?
static func configureWith(block: @escaping (SecondModuleInput) -> (SecondModuleOutput)) -> UIViewController {
let secondPresenter = SecondPresenter()
secondPresenter.secondModuleOutputHandler = block(secondPresenter)
return secondPresenter.view
}
// Sending data to first presenter
func sendDataToFirstPresenter(data: Any) {
secondModuleOutputHandler?.send(data: data)
}
// MARK: FirstModuleInput
var data: Any?
}
路由器
class FirstRouter {
func goToSecondModuleFrom(firstPresenter: FirstPresenter, with data: Any) {
let secondPresenterView = SecondPresenter.configureWith { (secondPreseter) -> (SecondModuleOutput) in
firstPresenter.secondModuleInputHandler = secondPreseter
return firstPresenter
}
//Pass data to SecondPresenter
firstPresenter.secondModuleInputHandler?.data = data
//Go to another view controller
//firstPresenter.view.present(secondPresenterView, animated: true, completion: nil)
//firstPresenter.view.navigationController.pushViewController(secondPresenterView, animated: true)
}
}