1 |
//
|
|
2 |
// RouteComposer
|
|
3 |
// UIViewController+Extension.swift
|
|
4 |
// https://github.com/ekazaev/route-composer
|
|
5 |
//
|
|
6 |
// Created by Eugene Kazaev in 2018-2022.
|
|
7 |
// Distributed under the MIT license.
|
|
8 |
//
|
|
9 |
// Become a sponsor:
|
|
10 |
// https://github.com/sponsors/ekazaev
|
|
11 |
//
|
|
12 |
|
|
13 |
import UIKit
|
|
14 |
|
|
15 |
public extension UIViewController {
|
|
16 |
|
|
17 |
/// Iterates through the view controller stack to finds a `UIViewController` instance.
|
|
18 |
///
|
|
19 |
/// - Parameters:
|
|
20 |
/// - viewController: A `UIViewController` instance to start from.
|
|
21 |
/// - options: A combination of `SearchOptions`.
|
|
22 |
/// - containerAdapterLocator: A `ContainerAdapterLocator` instance.
|
|
23 |
/// - predicate: A block that should return `true` if the `UIViewController` instance provided is the
|
|
24 |
/// one that is being searched for.
|
|
25 |
/// - Returns: A `UIViewController` instance if found, `nil` otherwise.
|
|
26 |
static func findViewController(in viewController: UIViewController,
|
|
27 |
options: SearchOptions = .currentAndUp,
|
|
28 |
containerAdapterLocator: ContainerAdapterLocator = RouteComposerDefaults.shared.containerAdapterLocator,
|
|
29 |
using predicate: (UIViewController) -> Bool) throws -> UIViewController? {
|
1360x |
30 |
guard !viewController.isBeingDismissed else {
|
1360x |
31 |
return nil
|
2x |
32 |
}
|
1350x |
33 |
|
1350x |
34 |
if options.contains(.current), predicate(viewController) {
|
1350x |
35 |
return viewController
|
322x |
36 |
}
|
1030x |
37 |
|
1030x |
38 |
if options.contains(.parent),
|
1030x |
39 |
let parentViewController = viewController.parentViewController,
|
1030x |
40 |
let foundViewController = try findViewController(in: parentViewController,
|
1030x |
41 |
options: [.current, .parent],
|
1030x |
42 |
containerAdapterLocator: containerAdapterLocator,
|
1030x |
43 |
using: predicate) {
|
1030x |
44 |
return foundViewController
|
6x |
45 |
}
|
1030x |
46 |
|
1030x |
47 |
if let container = viewController as? ContainerViewController, options.contains(.visible) || options.contains(.contained) {
|
1030x |
48 |
var viewControllers: [[UIViewController]] = []
|
660x |
49 |
let containerAdapter = try containerAdapterLocator.getAdapter(for: container)
|
660x |
50 |
viewControllers.append(containerAdapter.visibleViewControllers)
|
660x |
51 |
if options.contains(.contained) {
|
660x |
52 |
viewControllers.append(containerAdapter.containedViewControllers)
|
336x |
53 |
}
|
660x |
54 |
for currentViewController in Array(viewControllers.joined()).uniqueElements() {
|
809x |
55 |
var internalOptions: SearchOptions = options.contains(.visible) ? .currentVisibleOnly : [.current, .contained]
|
809x |
56 |
if options.contains(.presented) {
|
809x |
57 |
internalOptions.insert(.presented)
|
320x |
58 |
}
|
809x |
59 |
if let foundViewController = try findViewController(in: currentViewController,
|
809x |
60 |
options: internalOptions,
|
809x |
61 |
containerAdapterLocator: containerAdapterLocator,
|
809x |
62 |
using: predicate) {
|
809x |
63 |
return foundViewController
|
412x |
64 |
}
|
412x |
65 |
}
|
397x |
66 |
}
|
619x |
67 |
|
619x |
68 |
if options.contains(.presented),
|
619x |
69 |
let presentedViewController = viewController.presentedViewController {
|
619x |
70 |
let presentedOptions = options.subtracting(.presenting)
|
18x |
71 |
if let foundViewController = try findViewController(in: presentedViewController,
|
18x |
72 |
options: presentedOptions,
|
18x |
73 |
containerAdapterLocator: containerAdapterLocator,
|
18x |
74 |
using: predicate) {
|
18x |
75 |
return foundViewController
|
3x |
76 |
}
|
15x |
77 |
}
|
616x |
78 |
|
616x |
79 |
if options.contains(.presenting),
|
616x |
80 |
let presentingViewController = viewController.presentingViewController {
|
616x |
81 |
let presentingOptions = options.subtracting(.presented)
|
52x |
82 |
if let foundViewController = try findViewController(in: presentingViewController,
|
52x |
83 |
options: presentingOptions,
|
52x |
84 |
containerAdapterLocator: containerAdapterLocator,
|
52x |
85 |
using: predicate) {
|
52x |
86 |
return foundViewController
|
6x |
87 |
}
|
46x |
88 |
}
|
610x |
89 |
|
610x |
90 |
return nil
|
610x |
91 |
}
|
616x |
92 |
|
|
93 |
}
|
|