-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
606 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// | ||
// Copyright © 2020 Standard Chartered. All rights reserved. | ||
// | ||
|
||
import Combine | ||
import LeakDetector | ||
import UIKit | ||
|
||
open class BaseCoordinator<T>: UINavigationController, Coordinator { | ||
|
||
public let dependency: T | ||
private var cancellables = Set<AnyCancellable>() | ||
|
||
private var trackingViewControllers = WeakSet<UIViewController>() | ||
|
||
public init(with dependency: T) { | ||
self.dependency = dependency | ||
super.init(nibName: nil, bundle: nil) | ||
} | ||
|
||
@available(*, unavailable) | ||
public required init?(coder aDecoder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
open func start() {} | ||
|
||
open func navigate(to destination: Destination, presentInModal: Bool = false, animated: Bool) { | ||
guard let viewController = makeViewController(for: destination) else { | ||
return | ||
} | ||
|
||
trackingViewControllers.insert(viewController) | ||
|
||
if presentInModal { | ||
present(viewController, animated: animated, completion: nil) | ||
return | ||
} | ||
|
||
if viewControllers.isEmpty { | ||
viewControllers = [ | ||
viewController, | ||
] | ||
} else { | ||
pushViewController(viewController, animated: animated) | ||
} | ||
} | ||
|
||
open func makeViewController(for destination: Destination) -> UIViewController? { | ||
nil | ||
} | ||
|
||
deinit { | ||
guard let topViewController = topViewController else { | ||
return | ||
} | ||
LeakDetector.instance.expectDeallocate(objects: trackingViewControllers).sink {}.store(in: &cancellables) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// | ||
// Copyright © 2020 Standard Chartered. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
|
||
public protocol Destination {} | ||
|
||
public protocol Coordinator: UINavigationController { | ||
associatedtype CoordinatorDependency | ||
var dependency: CoordinatorDependency { get } | ||
|
||
func start() | ||
func navigate(to destination: Destination, presentInModal: Bool, animated: Bool) | ||
} |
91 changes: 91 additions & 0 deletions
91
LeakDetectorDemo/Leak/Coordinator/CoordinatorRootViewController.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// | ||
// Copyright © 2020 An Tran. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import UIKit | ||
|
||
class CoordinatorRootViewController: LeakDetectableTableViewController { | ||
|
||
private enum Scenarios { | ||
|
||
enum Leak: String, CaseIterable { | ||
case coordinator1 = "Leak - 1" | ||
} | ||
|
||
enum NoLeak: String, CaseIterable { | ||
case coordinator1 = "No Leak - 1" | ||
} | ||
} | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
title = "Coordinator" | ||
} | ||
|
||
override func numberOfSections(in tableView: UITableView) -> Int { | ||
2 | ||
} | ||
|
||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { | ||
switch section { | ||
case 0: | ||
return "Leak" | ||
case 1: | ||
return "No Leak" | ||
default: | ||
fatalError("invalid section") | ||
} | ||
} | ||
|
||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | ||
switch section { | ||
case 0: | ||
return Scenarios.Leak.allCases.count | ||
case 1: | ||
return Scenarios.NoLeak.allCases.count | ||
default: | ||
fatalError("invalid section") | ||
} | ||
} | ||
|
||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | ||
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell") | ||
|
||
switch indexPath.section { | ||
case 0: | ||
cell.textLabel?.text = Scenarios.Leak.allCases[indexPath.row].rawValue | ||
case 1: | ||
cell.textLabel?.text = Scenarios.NoLeak.allCases[indexPath.row].rawValue | ||
default: | ||
fatalError("invalid section") | ||
} | ||
return cell | ||
} | ||
|
||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { | ||
switch indexPath.section { | ||
case 0: | ||
let scenario = Scenarios.Leak.allCases[indexPath.row] | ||
switch scenario { | ||
case .coordinator1: | ||
let viewController = CoordinatorViewController() | ||
viewController.title = scenario.rawValue | ||
weakViewController = viewController | ||
navigationController?.pushViewController(viewController, animated: true) | ||
} | ||
case 1: | ||
let scenario = Scenarios.NoLeak.allCases[indexPath.row] | ||
switch scenario { | ||
case .coordinator1: | ||
let viewController = NoLeakDelegateViewController1() | ||
viewController.title = scenario.rawValue | ||
weakViewController = viewController | ||
navigationController?.pushViewController(viewController, animated: true) | ||
} | ||
|
||
default: | ||
fatalError("invalid section") | ||
} | ||
} | ||
} |
Oops, something went wrong.