Skip to content

Commit aa0b59e

Browse files
committed
Add Coordinator cases
1 parent 753ee3a commit aa0b59e

File tree

12 files changed

+606
-29
lines changed

12 files changed

+606
-29
lines changed

LeakDetectorDemo.xcodeproj/project.pbxproj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
7FE0480D25681B29005BE7C7 /* NestedClosuresViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FE0480C25681B29005BE7C7 /* NestedClosuresViewController.swift */; };
4545
7FF11903256736BE000B6C59 /* Closure.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7FF11902256736BE000B6C59 /* Closure.storyboard */; };
4646
7FF1190925673784000B6C59 /* NoLeakNonEscapingClosureViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FF1190825673784000B6C59 /* NoLeakNonEscapingClosureViewController.swift */; };
47+
D62DE9522588B2C200CF5CE1 /* CoordinatorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62DE94E2588B2C200CF5CE1 /* CoordinatorViewController.swift */; };
48+
D62DE9532588B2C200CF5CE1 /* CoordinatorRootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62DE94F2588B2C200CF5CE1 /* CoordinatorRootViewController.swift */; };
49+
D62DE9542588B2C200CF5CE1 /* BaseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62DE9502588B2C200CF5CE1 /* BaseCoordinator.swift */; };
50+
D62DE9552588B2C200CF5CE1 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62DE9512588B2C200CF5CE1 /* Coordinator.swift */; };
4751
D640D9DE2563AD7E005ABD34 /* DispatchQueueRootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D640D9DD2563AD7E005ABD34 /* DispatchQueueRootViewController.swift */; };
4852
D640D9E42563AE04005ABD34 /* DispatchQueue.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D640D9E32563AE04005ABD34 /* DispatchQueue.storyboard */; };
4953
D640D9EA2563AE60005ABD34 /* NoLeakDispatchAsyncViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D640D9E92563AE60005ABD34 /* NoLeakDispatchAsyncViewController.swift */; };
@@ -104,6 +108,10 @@
104108
7FE0480C25681B29005BE7C7 /* NestedClosuresViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedClosuresViewController.swift; sourceTree = "<group>"; };
105109
7FF11902256736BE000B6C59 /* Closure.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Closure.storyboard; sourceTree = "<group>"; };
106110
7FF1190825673784000B6C59 /* NoLeakNonEscapingClosureViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoLeakNonEscapingClosureViewController.swift; sourceTree = "<group>"; };
111+
D62DE94E2588B2C200CF5CE1 /* CoordinatorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoordinatorViewController.swift; sourceTree = "<group>"; };
112+
D62DE94F2588B2C200CF5CE1 /* CoordinatorRootViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoordinatorRootViewController.swift; sourceTree = "<group>"; };
113+
D62DE9502588B2C200CF5CE1 /* BaseCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseCoordinator.swift; sourceTree = "<group>"; };
114+
D62DE9512588B2C200CF5CE1 /* Coordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
107115
D640D9DD2563AD7E005ABD34 /* DispatchQueueRootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DispatchQueueRootViewController.swift; sourceTree = "<group>"; };
108116
D640D9E32563AE04005ABD34 /* DispatchQueue.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = DispatchQueue.storyboard; sourceTree = "<group>"; };
109117
D640D9E92563AE60005ABD34 /* NoLeakDispatchAsyncViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoLeakDispatchAsyncViewController.swift; sourceTree = "<group>"; };
@@ -151,6 +159,7 @@
151159
7F4F1C3A255EE07800A90DA8 /* Leak */ = {
152160
isa = PBXGroup;
153161
children = (
162+
D62DE94D2588B2C200CF5CE1 /* Coordinator */,
154163
7FB179E8257375C000209C04 /* SimpleCases */,
155164
7FB179D4257296FA00209C04 /* LazyVar */,
156165
7FB179C7257225DD00209C04 /* Delegate */,
@@ -281,6 +290,17 @@
281290
path = NestedClosures;
282291
sourceTree = "<group>";
283292
};
293+
D62DE94D2588B2C200CF5CE1 /* Coordinator */ = {
294+
isa = PBXGroup;
295+
children = (
296+
D62DE94E2588B2C200CF5CE1 /* CoordinatorViewController.swift */,
297+
D62DE94F2588B2C200CF5CE1 /* CoordinatorRootViewController.swift */,
298+
D62DE9502588B2C200CF5CE1 /* BaseCoordinator.swift */,
299+
D62DE9512588B2C200CF5CE1 /* Coordinator.swift */,
300+
);
301+
path = Coordinator;
302+
sourceTree = "<group>";
303+
};
284304
D640D9DC2563AD6C005ABD34 /* DispatchQueue */ = {
285305
isa = PBXGroup;
286306
children = (
@@ -473,11 +493,14 @@
473493
7FB179D62572970800209C04 /* LazyVarRootViewController.swift in Sources */,
474494
7FB179F02573768B00209C04 /* SimpleCasesViewController.swift in Sources */,
475495
7F4F1C40255EE0C700A90DA8 /* CombineViewController.swift in Sources */,
496+
D62DE9542588B2C200CF5CE1 /* BaseCoordinator.swift in Sources */,
476497
7F18D5992565FA730045F6FC /* MainViewController.swift in Sources */,
477498
7FB179E02572971C00209C04 /* LazyVarViewController.swift in Sources */,
499+
D62DE9522588B2C200CF5CE1 /* CoordinatorViewController.swift in Sources */,
478500
7F4F1C712562A78000A90DA8 /* ClosureRootViewController.swift in Sources */,
479501
7FE047EC2567F76C005BE7C7 /* AnimatorViewController.swift in Sources */,
480502
7FB179C9257225F100209C04 /* DelegateRootViewController.swift in Sources */,
503+
D62DE9552588B2C200CF5CE1 /* Coordinator.swift in Sources */,
481504
7FE0480725681A3E005BE7C7 /* NestedClosuresRootViewController.swift in Sources */,
482505
7F4F1C5A25617CBA00A90DA8 /* UIApplication+TopMostController.swift in Sources */,
483506
D640D9EA2563AE60005ABD34 /* NoLeakDispatchAsyncViewController.swift in Sources */,
@@ -489,6 +512,7 @@
489512
7FBA06D5256A8782000A42C4 /* URLSessionRootViewController.swift in Sources */,
490513
7F18D5912565F4E70045F6FC /* ChildViewController.swift in Sources */,
491514
7F1131782562D8C500438910 /* LeakDetectableViewController.swift in Sources */,
515+
D62DE9532588B2C200CF5CE1 /* CoordinatorRootViewController.swift in Sources */,
492516
7FF1190925673784000B6C59 /* NoLeakNonEscapingClosureViewController.swift in Sources */,
493517
7FBA06F2256B22E2000A42C4 /* FutureViewController.swift in Sources */,
494518
7FE047E82567F6E0005BE7C7 /* AnimateRootViewController.swift in Sources */,

LeakDetectorDemo/Base.lproj/Main.storyboard

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,29 @@
244244
</subviews>
245245
</tableViewCellContentView>
246246
</tableViewCell>
247+
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="gcY-qA-I68" style="IBUITableViewCellStyleDefault" id="tPN-E0-m1f">
248+
<rect key="frame" x="0.0" y="593.5" width="414" height="43.5"/>
249+
<autoresizingMask key="autoresizingMask"/>
250+
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="tPN-E0-m1f" id="M5Y-Vg-3RY">
251+
<rect key="frame" x="0.0" y="0.0" width="383" height="43.5"/>
252+
<autoresizingMask key="autoresizingMask"/>
253+
<subviews>
254+
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Leak by Coordinator" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="gcY-qA-I68">
255+
<rect key="frame" x="20" y="0.0" width="355" height="43.5"/>
256+
<autoresizingMask key="autoresizingMask"/>
257+
<fontDescription key="fontDescription" type="system" pointSize="17"/>
258+
<nil key="textColor"/>
259+
<nil key="highlightedColor"/>
260+
</label>
261+
</subviews>
262+
</tableViewCellContentView>
263+
</tableViewCell>
247264
</cells>
248265
</tableViewSection>
249266
<tableViewSection headerTitle="No Leak" id="w2m-HG-JUB" userLabel="No Leak">
250267
<cells>
251268
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="mfo-rT-f1S" style="IBUITableViewCellStyleDefault" id="SrQ-Fr-ZSC">
252-
<rect key="frame" x="0.0" y="649.5" width="414" height="43.5"/>
269+
<rect key="frame" x="0.0" y="693" width="414" height="43.5"/>
253270
<autoresizingMask key="autoresizingMask"/>
254271
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="SrQ-Fr-ZSC" id="8x2-zc-fwW">
255272
<rect key="frame" x="0.0" y="0.0" width="383" height="43.5"/>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// Copyright © 2020 Standard Chartered. All rights reserved.
3+
//
4+
5+
import Combine
6+
import LeakDetector
7+
import UIKit
8+
9+
open class BaseCoordinator<T>: UINavigationController, Coordinator {
10+
11+
public let dependency: T
12+
private var cancellables = Set<AnyCancellable>()
13+
14+
private var trackingViewControllers = WeakSet<UIViewController>()
15+
16+
public init(with dependency: T) {
17+
self.dependency = dependency
18+
super.init(nibName: nil, bundle: nil)
19+
}
20+
21+
@available(*, unavailable)
22+
public required init?(coder aDecoder: NSCoder) {
23+
fatalError("init(coder:) has not been implemented")
24+
}
25+
26+
open func start() {}
27+
28+
open func navigate(to destination: Destination, presentInModal: Bool = false, animated: Bool) {
29+
guard let viewController = makeViewController(for: destination) else {
30+
return
31+
}
32+
33+
trackingViewControllers.insert(viewController)
34+
35+
if presentInModal {
36+
present(viewController, animated: animated, completion: nil)
37+
return
38+
}
39+
40+
if viewControllers.isEmpty {
41+
viewControllers = [
42+
viewController,
43+
]
44+
} else {
45+
pushViewController(viewController, animated: animated)
46+
}
47+
}
48+
49+
open func makeViewController(for destination: Destination) -> UIViewController? {
50+
nil
51+
}
52+
53+
deinit {
54+
guard let topViewController = topViewController else {
55+
return
56+
}
57+
LeakDetector.instance.expectDeallocate(objects: trackingViewControllers).sink {}.store(in: &cancellables)
58+
}
59+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// Copyright © 2020 Standard Chartered. All rights reserved.
3+
//
4+
5+
import UIKit
6+
7+
public protocol Destination {}
8+
9+
public protocol Coordinator: UINavigationController {
10+
associatedtype CoordinatorDependency
11+
var dependency: CoordinatorDependency { get }
12+
13+
func start()
14+
func navigate(to destination: Destination, presentInModal: Bool, animated: Bool)
15+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//
2+
// Copyright © 2020 An Tran. All rights reserved.
3+
//
4+
5+
import Foundation
6+
import UIKit
7+
8+
class CoordinatorRootViewController: LeakDetectableTableViewController {
9+
10+
private enum Scenarios {
11+
12+
enum Leak: String, CaseIterable {
13+
case coordinator1 = "Leak - 1"
14+
}
15+
16+
enum NoLeak: String, CaseIterable {
17+
case coordinator1 = "No Leak - 1"
18+
}
19+
}
20+
21+
override func viewDidLoad() {
22+
super.viewDidLoad()
23+
title = "Coordinator"
24+
}
25+
26+
override func numberOfSections(in tableView: UITableView) -> Int {
27+
2
28+
}
29+
30+
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
31+
switch section {
32+
case 0:
33+
return "Leak"
34+
case 1:
35+
return "No Leak"
36+
default:
37+
fatalError("invalid section")
38+
}
39+
}
40+
41+
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
42+
switch section {
43+
case 0:
44+
return Scenarios.Leak.allCases.count
45+
case 1:
46+
return Scenarios.NoLeak.allCases.count
47+
default:
48+
fatalError("invalid section")
49+
}
50+
}
51+
52+
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
53+
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell")
54+
55+
switch indexPath.section {
56+
case 0:
57+
cell.textLabel?.text = Scenarios.Leak.allCases[indexPath.row].rawValue
58+
case 1:
59+
cell.textLabel?.text = Scenarios.NoLeak.allCases[indexPath.row].rawValue
60+
default:
61+
fatalError("invalid section")
62+
}
63+
return cell
64+
}
65+
66+
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
67+
switch indexPath.section {
68+
case 0:
69+
let scenario = Scenarios.Leak.allCases[indexPath.row]
70+
switch scenario {
71+
case .coordinator1:
72+
let viewController = CoordinatorViewController()
73+
viewController.title = scenario.rawValue
74+
weakViewController = viewController
75+
navigationController?.pushViewController(viewController, animated: true)
76+
}
77+
case 1:
78+
let scenario = Scenarios.NoLeak.allCases[indexPath.row]
79+
switch scenario {
80+
case .coordinator1:
81+
let viewController = NoLeakDelegateViewController1()
82+
viewController.title = scenario.rawValue
83+
weakViewController = viewController
84+
navigationController?.pushViewController(viewController, animated: true)
85+
}
86+
87+
default:
88+
fatalError("invalid section")
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)