├── title.png
├── .github
├── FUNDING.yml
└── workflows
│ └── ci.yml
├── BeelineExample
├── Supporting
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ └── Base.lproj
│ │ └── LaunchScreen.storyboard
├── BeelineExample.entitlements
├── ViewController.swift
├── AppDelegate.swift
├── AppRouter.swift
└── ViewController.xib
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── Beeline.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ ├── BeelineTests.xcscheme
│ │ └── BeelineExample.xcscheme
└── project.pbxproj
├── Beeline.podspec
├── Package.swift
├── BeelineTests
├── Info.plist
└── BeelineTests.swift
├── LICENSE
├── .gitignore
├── README.md
└── Beeline
└── Router.swift
/title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/Beeline/HEAD/title.png
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: timoliver
2 | custom: https://tim.dev/paypal
3 |
--------------------------------------------------------------------------------
/BeelineExample/Supporting/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/BeelineExample/Supporting/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Beeline.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Beeline.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: macos-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: Run a one-line script
13 | run: xcodebuild -project Beeline.xcodeproj -scheme BeelineExample -destination 'platform=iOS Simulator,name=iPhone 11' test
14 |
--------------------------------------------------------------------------------
/BeelineExample/BeelineExample.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.network.client
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Beeline.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'Beeline'
3 | s.version = '1.0.1'
4 | s.license = { :type => 'MIT', :file => 'LICENSE' }
5 | s.summary = 'An extremely lean implementation on the classic iOS router pattern.'
6 | s.homepage = 'https://github.com/TimOliver/Beeline'
7 | s.author = 'Tim Oliver'
8 | s.source = { :git => 'https://github.com/TimOliver/Beeline.git', :tag => s.version }
9 | s.source_files = 'Beeline/**/*.swift'
10 | s.swift_version = '5.0'
11 |
12 | s.ios.deployment_target = '9.0'
13 | s.tvos.deployment_target = '9.0'
14 |
15 | end
16 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "Beeline",
8 | platforms: [
9 | .iOS(.v9),
10 | .macOS(.v10_12)
11 | ],
12 | products: [
13 | .library(
14 | name: "Beeline",
15 | targets: ["Beeline"]),
16 | ],
17 | targets: [
18 | .target(
19 | name: "Beeline",
20 | path: "Beeline"),
21 | .testTarget(
22 | name: "BeelineTests",
23 | dependencies: [
24 | "Beeline"
25 | ],
26 | path: "BeelineTests")
27 | ]
28 | )
29 |
--------------------------------------------------------------------------------
/BeelineTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BeelineExample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // BeelineTest
4 | //
5 | // Created by Tim Oliver on 17/7/21.
6 | //
7 |
8 | import UIKit
9 |
10 | class ViewController: UIViewController {
11 | @IBOutlet weak var numberLabel: UILabel!
12 | private var number: Int = 0
13 |
14 | init(number: Int) {
15 | super.init(nibName: "ViewController", bundle: nil)
16 | self.number = number
17 | }
18 |
19 | required init?(coder: NSCoder) {
20 | fatalError("init(coder:) has not been implemented")
21 | }
22 |
23 | override func viewDidLoad() {
24 | super.viewDidLoad()
25 | self.numberLabel.text = String(number)
26 | }
27 |
28 | @IBAction func buttonTapped(_ sender: Any) {
29 | // Tell the router to show another view controller
30 | show(AppRoute.viewController(number: number + 1))
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/BeelineExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // BeelineTest
4 | //
5 | // Created by Tim Oliver on 13/7/21.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 | var window: UIWindow?
13 |
14 | func application(_ application: UIApplication, didFinishLaunchingWithOptions
15 | launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 |
17 | // Register our global router
18 | Router.registerDefaultClass(AppRouter.self)
19 |
20 | // Create the navigation controller
21 | let navigationController = UINavigationController(rootViewController: ViewController(number: 1))
22 |
23 | // Create and show the window
24 | window = UIWindow(frame: UIScreen.main.bounds)
25 | window?.rootViewController = navigationController
26 | window?.makeKeyAndVisible()
27 |
28 | return true
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/BeelineExample/AppRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppRouter.swift
3 | // BeelineTest
4 | //
5 | // Created by Tim Oliver on 17/7/21.
6 | //
7 |
8 | import Foundation
9 | import UIKit
10 |
11 | /// Enum containing all of our destinations
12 | enum AppRoute: Route {
13 | case viewController(number: Int)
14 | }
15 |
16 | // Our subclass of Router to contain our custom presentation logic
17 | public class AppRouter: Router {
18 |
19 | override func show(_ route: Route,
20 | from sourceViewController: UIViewController?) -> Bool {
21 | // We're only interested in routes from the AppRoute enum
22 | guard let appRoute = route as? AppRoute else { return false }
23 |
24 | // Check which enum was requested and produce a view controller for it
25 | switch appRoute {
26 | case .viewController(let number):
27 | let newViewController = ViewController(number: number)
28 | sourceViewController?
29 | .navigationController?
30 | .pushViewController(newViewController, animated: true)
31 | }
32 |
33 | return true
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Tim Oliver
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/BeelineExample/Supporting/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSupportsIndirectInputEvents
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/BeelineExample/Supporting/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Beeline.xcodeproj/xcshareddata/xcschemes/BeelineTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
44 |
45 |
47 |
48 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/BeelineExample/Supporting/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | # *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | # .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | # Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | # Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
91 |
92 | # macOS
93 |
94 | .DS_Store
95 |
96 |
--------------------------------------------------------------------------------
/BeelineTests/BeelineTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BeelineTests.swift
3 | // BeelineTests
4 | //
5 | // Created by Tim Oliver on 20/7/21.
6 | //
7 |
8 | import XCTest
9 |
10 | // Create a dummy destination to test
11 | enum TestRoute: Route {
12 | case first
13 | }
14 |
15 | // Create a subclass of Router with an external closure to test
16 | class TestRouter: Router {
17 | var showResultsClosure: ((Route) -> Void)?
18 |
19 | override func show(_ route: Route, from sourceViewController: UIViewController?) -> Bool {
20 | showResultsClosure?(route)
21 | return true
22 | }
23 | }
24 |
25 | class BeelineTests: XCTestCase {
26 |
27 | override class func tearDown() {
28 | // Set the default class back to nil just in case
29 | Router.registerDefaultClass(nil)
30 | }
31 |
32 | // Test setting and getting the same router instance from a VC
33 | func testRouterAssigning() {
34 | let viewController = UIViewController()
35 | let testRouter = TestRouter()
36 | viewController.router = testRouter
37 | XCTAssertEqual(testRouter, viewController.router)
38 | }
39 |
40 | // Test show mechanism
41 | func testRouterShowCallback() {
42 | // Set a flag we can track
43 | var success = false
44 |
45 | // Create the router and expectation
46 | let testRouter = TestRouter()
47 | testRouter.showResultsClosure = { route in
48 | if let testRoute = route as? TestRoute {
49 | success = (testRoute == .first)
50 | }
51 | }
52 |
53 | // Attach the router to a view controller nested in another view controller
54 | let viewController = UIViewController()
55 | let parentViewController = UINavigationController(rootViewController: viewController)
56 | parentViewController.router = testRouter
57 |
58 | // Call show on the view controller
59 | viewController.show(TestRoute.first)
60 |
61 | // Capture if the call was passed back up to the router
62 | XCTAssertTrue(success)
63 | }
64 |
65 | // Test default mechanism
66 | func testRouterDefaultClass() {
67 | // Register the default class
68 | Router.registerDefaultClass(TestRouter.self)
69 |
70 | // Create a nested view controller setup
71 | let viewController = UIViewController()
72 | let parentViewController = UINavigationController(rootViewController: viewController)
73 |
74 | // Call show on the child, which will auto-generate a router on the nav controller
75 | viewController.show(TestRoute.first)
76 |
77 | // Check the expected output was correct
78 | XCTAssertNotNil(parentViewController.router)
79 | XCTAssertTrue(parentViewController.router is TestRouter)
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/BeelineExample/ViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
31 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Beeline.xcodeproj/xcshareddata/xcschemes/BeelineExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
67 |
69 |
75 |
76 |
77 |
78 |
84 |
86 |
92 |
93 |
94 |
95 |
97 |
98 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [](https://github.com/TimOliver/Beeline/actions?query=workflow%3ACI)
6 | [](http://cocoadocs.org/docsets/Beeline)
7 | [](https://raw.githubusercontent.com/TimOliver/Beeline/main/LICENSE)
8 | [](http://cocoadocs.org/docsets/Beeline)
9 |
10 |
11 |
12 | Beeline is a very small library that aims to provide a lean, automatic implementation of the classic iOS router pattern. It extends `UIViewController` to retain a `Router` object that serves as the source of truth for controlling navigation flows for all of the view controller's children. When a child view controller wishes to transition to a new screen, it can call `show()` on itself and this request is passed up the view controller chain to the routing view controller.
13 |
14 | # Instructions
15 |
16 | A very basic custom implementation looks as the following. First, we create a Swift enum conforming to `Route` where we can define the types of destinations with which we want to move:
17 |
18 | ```swift
19 | enum AppRoute: Route {
20 | case viewController(number: Int)
21 | }
22 | ```
23 | Thanks to Swift associated enums, we can also include any custom parameters the new destination may need.
24 |
25 | We then also make a new class which subclasses `Router`, which serves as our single point of truth for controlling the app flow based off the destinations we defined above:
26 |
27 | ```swift
28 | public class AppRouter: Router {
29 | override func show(_ route: Route,
30 | from sourceViewController: UIViewController?) -> Bool {
31 |
32 | // Optionally, filter out routes we don't support
33 | guard let appRoute = route as? AppRoute else { return false }
34 |
35 | // Check the requested enum, and perform the transition
36 | switch appRoute {
37 | case .viewController(let number):
38 | let newViewController = ViewController(number: number)
39 | sourceViewController?
40 | .navigationController?
41 | .pushViewController(newViewController, animated: true)
42 | }
43 |
44 | return true
45 | }
46 | }
47 |
48 | ```
49 |
50 | Using Objective-C associated objects, we can assign this router to any parent view controller that contains all of the view controllers that might want to perform these transitions:
51 |
52 | ```swift
53 | let navigationController = UINavigationController(rootViewController: ViewController())
54 | navigationController.router = AppRouter()
55 | ```
56 |
57 | Finally, without any further modification to any of the child view controllers, they can start a transition by simply calling `show()` with the desired destination:
58 |
59 | ```swift
60 | class ViewController: UIViewController {
61 | func moveToNewViewController() {
62 | show(AppRoute.viewController(number: 2))
63 | }
64 | }
65 | ```
66 |
67 | And that's the entire library! 🎉
68 |
69 | # Requirements
70 | * Swift 5
71 | * UIKit-compatible platforms (iOS, tvOS, Mac Catalyst)
72 |
73 | # Installation
74 |
75 | Beeline is a very small framework, with all of its code contained in `Router.swift`. You can install it in the following ways:
76 |
77 | ## Manual Installation
78 |
79 | Drag the `Beeline/Router.swift` file into your Xcode project.
80 |
81 | ### CocoaPods
82 |
83 | ```
84 | pod 'Beeline'
85 | ```
86 |
87 | ### SPM
88 |
89 | You can add Beeline to an Xcode project by adding it as a package dependency.
90 |
91 | https://github.com/TimOliver/Beeline
92 |
93 | or, add the following to the dependencies in package.swift.
94 |
95 | ```swift
96 | dependencies: [
97 | .package(url: "https://github.com/TimOliver/Beeline", from: "1.0.2")
98 | ]
99 | ```
100 |
101 | ### Carthage
102 |
103 | No plans to support Carthage at the moment, but please consider filing a PR if you would like it!
104 |
105 | # Credits
106 |
107 | Beeline was built as a component of iComics 2 by [Tim Oliver](https://twitter.com/TimOliverAU)
108 |
109 | # License
110 |
111 | Beeline is available under the MIT License. Please check the [LICENSE](LICENSE) file for more information.
112 |
--------------------------------------------------------------------------------
/Beeline/Router.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Router.swift
3 | //
4 | // Copyright 2021 Timothy Oliver. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
23 | import UIKit
24 |
25 | /// A router is an object that is used to serve as the single source
26 | /// of truth when dealing with the navigation flow of screens in complex
27 | /// applications. Instead of child screens setting up and performing the transitions
28 | /// themselves, 'show' requests are dispatched up the view controller chain
29 | /// to a parent view controller with a router assigned, that will then perform its
30 | /// own business logic on what action to perform.
31 | ///
32 | /// `Router` is an abstract class that when subclassed, allows you to receive
33 | /// transition requests from child view controllers, and to have a single place
34 | /// to determine how the current state should transition to the requested one.
35 | ///
36 | open class Router: NSObject {
37 |
38 | /// A reference back to the view controller to which this router is assigned.
39 | weak var rootViewController: UIViewController?
40 |
41 | /// Normally view controllers that should serve as a router should have
42 | /// their router property manually configured. But for convenience, it is also
43 | /// possible to define a "default" router class. If a view controller calls `show`
44 | /// inside a view controller chain with no router, the view controller at the top
45 | /// of the chain will automatically instantiate and configure one
46 | /// - Parameter routerClass: The class (as `Class.self`) that should created by default. Must be a subclass of `Router`.
47 | class func registerDefaultClass(_ routerClass: AnyClass?) {
48 | // If nil was supplied, clear the currently registered class
49 | guard let routerClass = routerClass else {
50 | defaultRouterClass = nil
51 | return
52 | }
53 |
54 | // Ensure that the provided class is actually a subclass of Router
55 | guard routerClass.isSubclass(of: Router.self) else {
56 | fatalError("Router: Default router classes must be a subclass of the Router class.")
57 | }
58 |
59 | // Assign it as our global router
60 | defaultRouterClass = routerClass
61 | }
62 |
63 | /// Transitions the current view controller state of the view controller
64 | /// associated with this router object to the requested route destination.
65 | /// Override `show` in your subclasses in order to receive and perform
66 | /// the necessary transitions between screens that you want in your application
67 | /// - Parameters:
68 | /// - route: A custom object conforming to the `Route` protocol used to identify the intended destination of this transition
69 | /// - sourceViewController: The view controller that created this request (can be nil if the router itself directly called it)
70 | /// - Returns: Returns true if this router successfully handled the request, or false if the router decided to skip it
71 | func show(_ route: Route, from sourceViewController: UIViewController?) -> Bool {
72 | fatalError("Router: This class must be subclassed and cannot be used directly.")
73 | }
74 | }
75 |
76 | /// A route is a protocol which identifies any kind of object that can represent
77 | /// a new routing destination to a router. Any type of object can be made to conform to
78 | /// `Route`, and when submitted to a router, its type can then be checked
79 | /// by the custom overrided logic in that router's `show` method to determine what to do.
80 | public protocol Route { }
81 |
82 | // MARK: - UIKit Integration -
83 |
84 | public extension UIViewController {
85 |
86 | /// A router object that is associated with this
87 | /// view controller. This router will capture all of the
88 | /// 'show' events sent upwards from child view controllers
89 | var router: Router? {
90 | get { objc_getAssociatedObject(self, &routerKey) as? Router }
91 | set {
92 | newValue?.rootViewController = self
93 | objc_setAssociatedObject(self, &routerKey,
94 | newValue, .OBJC_ASSOCIATION_RETAIN)
95 | }
96 | }
97 |
98 | /// Transitions the calling view controller to the requested route destination
99 | /// with any associated parameters. The request is sent up the view controller
100 | /// chain until it reaches a view controller with an assigned router, which will
101 | /// then serve as the source of truth for transition
102 | /// - Parameter route: Any object conforming to `Route` used to uniquely identify the desired destination
103 | func show(_ route: Route) {
104 | var viewController: UIViewController? = self
105 |
106 | // Starting at the calling view controller, go up the parent view controller
107 | // chain until we find one with an associated router that will handle the transition for us
108 | repeat {
109 | // If the view controller doesn't have a parent
110 | // (ie, it's the top of the chain), and we have a default
111 | // class registered, make and assign a router to it
112 | if let defaultRouterClass = defaultRouterClass,
113 | viewController != nil, viewController!.parent == nil,
114 | viewController?.router == nil {
115 | let objectClass = defaultRouterClass as! NSObject.Type
116 | viewController?.router = objectClass.init() as? Router
117 | }
118 |
119 | // If this view controller has an associated router,
120 | // forward it the show command. If the router successfully
121 | // handles it, stop here. Otherwise keep going up the chain
122 | if let router = viewController?.router {
123 | if router.show(route, from: self) { return }
124 | }
125 |
126 | // Keep going up the chain until we hit the end
127 | viewController = viewController?.parent
128 | } while viewController != nil
129 | }
130 | }
131 |
132 | // MARK: - Private Global Properties -
133 |
134 | // An associated key value for storing routers inside view controllers
135 | private var routerKey: Void?
136 |
137 | // Optionally, a default Router subclass that can be deferred to by default
138 | private var defaultRouterClass: AnyClass?
139 |
--------------------------------------------------------------------------------
/Beeline.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2284DE02298028C7003A3371 /* BeelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2284DE01298028C7003A3371 /* BeelineTests.swift */; };
11 | 2284DE08298028F8003A3371 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22B3A607269DCFA500E1E843 /* Router.swift */; };
12 | 22B3A5F2269DC48000E1E843 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22B3A5F1269DC48000E1E843 /* AppDelegate.swift */; };
13 | 22B3A5FB269DC48100E1E843 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 22B3A5FA269DC48100E1E843 /* Assets.xcassets */; };
14 | 22B3A5FE269DC48100E1E843 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 22B3A5FC269DC48100E1E843 /* LaunchScreen.storyboard */; };
15 | 22B3A608269DCFA500E1E843 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22B3A607269DCFA500E1E843 /* Router.swift */; };
16 | 22BCBE6F26A29DCB0081CADE /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22BCBE6E26A29DCB0081CADE /* AppRouter.swift */; };
17 | 22BCBE7226A29F350081CADE /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22BCBE7026A29F350081CADE /* ViewController.swift */; };
18 | 22BCBE7326A29F350081CADE /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22BCBE7126A29F350081CADE /* ViewController.xib */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXContainerItemProxy section */
22 | 2284DE03298028C7003A3371 /* PBXContainerItemProxy */ = {
23 | isa = PBXContainerItemProxy;
24 | containerPortal = 22B3A5E6269DC48000E1E843 /* Project object */;
25 | proxyType = 1;
26 | remoteGlobalIDString = 22B3A5ED269DC48000E1E843;
27 | remoteInfo = BeelineExample;
28 | };
29 | /* End PBXContainerItemProxy section */
30 |
31 | /* Begin PBXFileReference section */
32 | 227B686026A719FA0000DD8D /* BeelineExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BeelineExample.entitlements; sourceTree = ""; };
33 | 2284DDF72980283D003A3371 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
34 | 2284DDF92980284A003A3371 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
35 | 2284DDFA2980285C003A3371 /* Beeline.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = Beeline.podspec; sourceTree = ""; };
36 | 2284DDFF298028C7003A3371 /* BeelineTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BeelineTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
37 | 2284DE01298028C7003A3371 /* BeelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BeelineTests.swift; sourceTree = ""; };
38 | 22B3A5EE269DC48000E1E843 /* BeelineExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BeelineExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 22B3A5F1269DC48000E1E843 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
40 | 22B3A5FA269DC48100E1E843 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
41 | 22B3A5FD269DC48100E1E843 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
42 | 22B3A5FF269DC48100E1E843 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
43 | 22B3A607269DCFA500E1E843 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; };
44 | 22BCBE6E26A29DCB0081CADE /* AppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = ""; };
45 | 22BCBE7026A29F350081CADE /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
46 | 22BCBE7126A29F350081CADE /* ViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ViewController.xib; sourceTree = ""; };
47 | /* End PBXFileReference section */
48 |
49 | /* Begin PBXFrameworksBuildPhase section */
50 | 2284DDFC298028C7003A3371 /* Frameworks */ = {
51 | isa = PBXFrameworksBuildPhase;
52 | buildActionMask = 2147483647;
53 | files = (
54 | );
55 | runOnlyForDeploymentPostprocessing = 0;
56 | };
57 | 22B3A5EB269DC48000E1E843 /* Frameworks */ = {
58 | isa = PBXFrameworksBuildPhase;
59 | buildActionMask = 2147483647;
60 | files = (
61 | );
62 | runOnlyForDeploymentPostprocessing = 0;
63 | };
64 | /* End PBXFrameworksBuildPhase section */
65 |
66 | /* Begin PBXGroup section */
67 | 2284DE00298028C7003A3371 /* BeelineTests */ = {
68 | isa = PBXGroup;
69 | children = (
70 | 2284DE01298028C7003A3371 /* BeelineTests.swift */,
71 | );
72 | path = BeelineTests;
73 | sourceTree = "";
74 | };
75 | 22B3A5E5269DC48000E1E843 = {
76 | isa = PBXGroup;
77 | children = (
78 | 22BCBE6826A293310081CADE /* Beeline */,
79 | 22B3A5F0269DC48000E1E843 /* BeelineExample */,
80 | 2284DDF72980283D003A3371 /* Package.swift */,
81 | 2284DDFA2980285C003A3371 /* Beeline.podspec */,
82 | 2284DDF92980284A003A3371 /* README.md */,
83 | 2284DE00298028C7003A3371 /* BeelineTests */,
84 | 22B3A5EF269DC48000E1E843 /* Products */,
85 | );
86 | sourceTree = "";
87 | };
88 | 22B3A5EF269DC48000E1E843 /* Products */ = {
89 | isa = PBXGroup;
90 | children = (
91 | 22B3A5EE269DC48000E1E843 /* BeelineExample.app */,
92 | 2284DDFF298028C7003A3371 /* BeelineTests.xctest */,
93 | );
94 | name = Products;
95 | sourceTree = "";
96 | };
97 | 22B3A5F0269DC48000E1E843 /* BeelineExample */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 227B686026A719FA0000DD8D /* BeelineExample.entitlements */,
101 | 22BCBE6E26A29DCB0081CADE /* AppRouter.swift */,
102 | 22B3A5F1269DC48000E1E843 /* AppDelegate.swift */,
103 | 22BCBE7026A29F350081CADE /* ViewController.swift */,
104 | 22BCBE7126A29F350081CADE /* ViewController.xib */,
105 | 22BCBE6D26A29DAF0081CADE /* Supporting */,
106 | );
107 | path = BeelineExample;
108 | sourceTree = "";
109 | };
110 | 22BCBE6826A293310081CADE /* Beeline */ = {
111 | isa = PBXGroup;
112 | children = (
113 | 22B3A607269DCFA500E1E843 /* Router.swift */,
114 | );
115 | path = Beeline;
116 | sourceTree = "";
117 | };
118 | 22BCBE6D26A29DAF0081CADE /* Supporting */ = {
119 | isa = PBXGroup;
120 | children = (
121 | 22B3A5FA269DC48100E1E843 /* Assets.xcassets */,
122 | 22B3A5FC269DC48100E1E843 /* LaunchScreen.storyboard */,
123 | 22B3A5FF269DC48100E1E843 /* Info.plist */,
124 | );
125 | path = Supporting;
126 | sourceTree = "";
127 | };
128 | /* End PBXGroup section */
129 |
130 | /* Begin PBXNativeTarget section */
131 | 2284DDFE298028C7003A3371 /* BeelineTests */ = {
132 | isa = PBXNativeTarget;
133 | buildConfigurationList = 2284DE05298028C7003A3371 /* Build configuration list for PBXNativeTarget "BeelineTests" */;
134 | buildPhases = (
135 | 2284DDFB298028C7003A3371 /* Sources */,
136 | 2284DDFC298028C7003A3371 /* Frameworks */,
137 | 2284DDFD298028C7003A3371 /* Resources */,
138 | );
139 | buildRules = (
140 | );
141 | dependencies = (
142 | 2284DE04298028C7003A3371 /* PBXTargetDependency */,
143 | );
144 | name = BeelineTests;
145 | productName = BeelineTests;
146 | productReference = 2284DDFF298028C7003A3371 /* BeelineTests.xctest */;
147 | productType = "com.apple.product-type.bundle.unit-test";
148 | };
149 | 22B3A5ED269DC48000E1E843 /* BeelineExample */ = {
150 | isa = PBXNativeTarget;
151 | buildConfigurationList = 22B3A602269DC48100E1E843 /* Build configuration list for PBXNativeTarget "BeelineExample" */;
152 | buildPhases = (
153 | 22B3A5EA269DC48000E1E843 /* Sources */,
154 | 22B3A5EB269DC48000E1E843 /* Frameworks */,
155 | 22B3A5EC269DC48000E1E843 /* Resources */,
156 | );
157 | buildRules = (
158 | );
159 | dependencies = (
160 | );
161 | name = BeelineExample;
162 | productName = RouterTest;
163 | productReference = 22B3A5EE269DC48000E1E843 /* BeelineExample.app */;
164 | productType = "com.apple.product-type.application";
165 | };
166 | /* End PBXNativeTarget section */
167 |
168 | /* Begin PBXProject section */
169 | 22B3A5E6269DC48000E1E843 /* Project object */ = {
170 | isa = PBXProject;
171 | attributes = {
172 | LastSwiftUpdateCheck = 1410;
173 | LastUpgradeCheck = 1410;
174 | TargetAttributes = {
175 | 2284DDFE298028C7003A3371 = {
176 | CreatedOnToolsVersion = 14.1;
177 | TestTargetID = 22B3A5ED269DC48000E1E843;
178 | };
179 | 22B3A5ED269DC48000E1E843 = {
180 | CreatedOnToolsVersion = 12.5;
181 | };
182 | };
183 | };
184 | buildConfigurationList = 22B3A5E9269DC48000E1E843 /* Build configuration list for PBXProject "Beeline" */;
185 | compatibilityVersion = "Xcode 9.3";
186 | developmentRegion = en;
187 | hasScannedForEncodings = 0;
188 | knownRegions = (
189 | en,
190 | Base,
191 | );
192 | mainGroup = 22B3A5E5269DC48000E1E843;
193 | productRefGroup = 22B3A5EF269DC48000E1E843 /* Products */;
194 | projectDirPath = "";
195 | projectRoot = "";
196 | targets = (
197 | 22B3A5ED269DC48000E1E843 /* BeelineExample */,
198 | 2284DDFE298028C7003A3371 /* BeelineTests */,
199 | );
200 | };
201 | /* End PBXProject section */
202 |
203 | /* Begin PBXResourcesBuildPhase section */
204 | 2284DDFD298028C7003A3371 /* Resources */ = {
205 | isa = PBXResourcesBuildPhase;
206 | buildActionMask = 2147483647;
207 | files = (
208 | );
209 | runOnlyForDeploymentPostprocessing = 0;
210 | };
211 | 22B3A5EC269DC48000E1E843 /* Resources */ = {
212 | isa = PBXResourcesBuildPhase;
213 | buildActionMask = 2147483647;
214 | files = (
215 | 22B3A5FE269DC48100E1E843 /* LaunchScreen.storyboard in Resources */,
216 | 22BCBE7326A29F350081CADE /* ViewController.xib in Resources */,
217 | 22B3A5FB269DC48100E1E843 /* Assets.xcassets in Resources */,
218 | );
219 | runOnlyForDeploymentPostprocessing = 0;
220 | };
221 | /* End PBXResourcesBuildPhase section */
222 |
223 | /* Begin PBXSourcesBuildPhase section */
224 | 2284DDFB298028C7003A3371 /* Sources */ = {
225 | isa = PBXSourcesBuildPhase;
226 | buildActionMask = 2147483647;
227 | files = (
228 | 2284DE08298028F8003A3371 /* Router.swift in Sources */,
229 | 2284DE02298028C7003A3371 /* BeelineTests.swift in Sources */,
230 | );
231 | runOnlyForDeploymentPostprocessing = 0;
232 | };
233 | 22B3A5EA269DC48000E1E843 /* Sources */ = {
234 | isa = PBXSourcesBuildPhase;
235 | buildActionMask = 2147483647;
236 | files = (
237 | 22BCBE6F26A29DCB0081CADE /* AppRouter.swift in Sources */,
238 | 22B3A608269DCFA500E1E843 /* Router.swift in Sources */,
239 | 22BCBE7226A29F350081CADE /* ViewController.swift in Sources */,
240 | 22B3A5F2269DC48000E1E843 /* AppDelegate.swift in Sources */,
241 | );
242 | runOnlyForDeploymentPostprocessing = 0;
243 | };
244 | /* End PBXSourcesBuildPhase section */
245 |
246 | /* Begin PBXTargetDependency section */
247 | 2284DE04298028C7003A3371 /* PBXTargetDependency */ = {
248 | isa = PBXTargetDependency;
249 | target = 22B3A5ED269DC48000E1E843 /* BeelineExample */;
250 | targetProxy = 2284DE03298028C7003A3371 /* PBXContainerItemProxy */;
251 | };
252 | /* End PBXTargetDependency section */
253 |
254 | /* Begin PBXVariantGroup section */
255 | 22B3A5FC269DC48100E1E843 /* LaunchScreen.storyboard */ = {
256 | isa = PBXVariantGroup;
257 | children = (
258 | 22B3A5FD269DC48100E1E843 /* Base */,
259 | );
260 | name = LaunchScreen.storyboard;
261 | sourceTree = "";
262 | };
263 | /* End PBXVariantGroup section */
264 |
265 | /* Begin XCBuildConfiguration section */
266 | 2284DE06298028C7003A3371 /* Debug */ = {
267 | isa = XCBuildConfiguration;
268 | buildSettings = {
269 | BUNDLE_LOADER = "$(TEST_HOST)";
270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
271 | CODE_SIGN_STYLE = Automatic;
272 | CURRENT_PROJECT_VERSION = 1;
273 | DEVELOPMENT_TEAM = 6LF3GMKZAB;
274 | GENERATE_INFOPLIST_FILE = YES;
275 | IPHONEOS_DEPLOYMENT_TARGET = 16.1;
276 | MARKETING_VERSION = 1.0;
277 | PRODUCT_BUNDLE_IDENTIFIER = dev.tim.BeelineTests;
278 | PRODUCT_NAME = "$(TARGET_NAME)";
279 | SWIFT_EMIT_LOC_STRINGS = NO;
280 | SWIFT_VERSION = 5.0;
281 | TARGETED_DEVICE_FAMILY = "1,2";
282 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BeelineExample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/BeelineExample";
283 | };
284 | name = Debug;
285 | };
286 | 2284DE07298028C7003A3371 /* Release */ = {
287 | isa = XCBuildConfiguration;
288 | buildSettings = {
289 | BUNDLE_LOADER = "$(TEST_HOST)";
290 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
291 | CODE_SIGN_STYLE = Automatic;
292 | CURRENT_PROJECT_VERSION = 1;
293 | DEVELOPMENT_TEAM = 6LF3GMKZAB;
294 | GENERATE_INFOPLIST_FILE = YES;
295 | IPHONEOS_DEPLOYMENT_TARGET = 16.1;
296 | MARKETING_VERSION = 1.0;
297 | PRODUCT_BUNDLE_IDENTIFIER = dev.tim.BeelineTests;
298 | PRODUCT_NAME = "$(TARGET_NAME)";
299 | SWIFT_EMIT_LOC_STRINGS = NO;
300 | SWIFT_VERSION = 5.0;
301 | TARGETED_DEVICE_FAMILY = "1,2";
302 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BeelineExample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/BeelineExample";
303 | };
304 | name = Release;
305 | };
306 | 22B3A600269DC48100E1E843 /* Debug */ = {
307 | isa = XCBuildConfiguration;
308 | buildSettings = {
309 | ALWAYS_SEARCH_USER_PATHS = NO;
310 | CLANG_ANALYZER_NONNULL = YES;
311 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
312 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
313 | CLANG_CXX_LIBRARY = "libc++";
314 | CLANG_ENABLE_MODULES = YES;
315 | CLANG_ENABLE_OBJC_ARC = YES;
316 | CLANG_ENABLE_OBJC_WEAK = YES;
317 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
318 | CLANG_WARN_BOOL_CONVERSION = YES;
319 | CLANG_WARN_COMMA = YES;
320 | CLANG_WARN_CONSTANT_CONVERSION = YES;
321 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
322 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
323 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
324 | CLANG_WARN_EMPTY_BODY = YES;
325 | CLANG_WARN_ENUM_CONVERSION = YES;
326 | CLANG_WARN_INFINITE_RECURSION = YES;
327 | CLANG_WARN_INT_CONVERSION = YES;
328 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
329 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
330 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
331 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
332 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
333 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
334 | CLANG_WARN_STRICT_PROTOTYPES = YES;
335 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
336 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
337 | CLANG_WARN_UNREACHABLE_CODE = YES;
338 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
339 | COPY_PHASE_STRIP = NO;
340 | DEBUG_INFORMATION_FORMAT = dwarf;
341 | ENABLE_STRICT_OBJC_MSGSEND = YES;
342 | ENABLE_TESTABILITY = YES;
343 | GCC_C_LANGUAGE_STANDARD = gnu11;
344 | GCC_DYNAMIC_NO_PIC = NO;
345 | GCC_NO_COMMON_BLOCKS = YES;
346 | GCC_OPTIMIZATION_LEVEL = 0;
347 | GCC_PREPROCESSOR_DEFINITIONS = (
348 | "DEBUG=1",
349 | "$(inherited)",
350 | );
351 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
352 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
353 | GCC_WARN_UNDECLARED_SELECTOR = YES;
354 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
355 | GCC_WARN_UNUSED_FUNCTION = YES;
356 | GCC_WARN_UNUSED_VARIABLE = YES;
357 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
358 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
359 | MTL_FAST_MATH = YES;
360 | ONLY_ACTIVE_ARCH = YES;
361 | SDKROOT = iphoneos;
362 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
363 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
364 | };
365 | name = Debug;
366 | };
367 | 22B3A601269DC48100E1E843 /* Release */ = {
368 | isa = XCBuildConfiguration;
369 | buildSettings = {
370 | ALWAYS_SEARCH_USER_PATHS = NO;
371 | CLANG_ANALYZER_NONNULL = YES;
372 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
373 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
374 | CLANG_CXX_LIBRARY = "libc++";
375 | CLANG_ENABLE_MODULES = YES;
376 | CLANG_ENABLE_OBJC_ARC = YES;
377 | CLANG_ENABLE_OBJC_WEAK = YES;
378 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
379 | CLANG_WARN_BOOL_CONVERSION = YES;
380 | CLANG_WARN_COMMA = YES;
381 | CLANG_WARN_CONSTANT_CONVERSION = YES;
382 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
383 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
384 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
385 | CLANG_WARN_EMPTY_BODY = YES;
386 | CLANG_WARN_ENUM_CONVERSION = YES;
387 | CLANG_WARN_INFINITE_RECURSION = YES;
388 | CLANG_WARN_INT_CONVERSION = YES;
389 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
390 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
391 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
392 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
393 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
394 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
395 | CLANG_WARN_STRICT_PROTOTYPES = YES;
396 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
397 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
398 | CLANG_WARN_UNREACHABLE_CODE = YES;
399 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
400 | COPY_PHASE_STRIP = NO;
401 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
402 | ENABLE_NS_ASSERTIONS = NO;
403 | ENABLE_STRICT_OBJC_MSGSEND = YES;
404 | GCC_C_LANGUAGE_STANDARD = gnu11;
405 | GCC_NO_COMMON_BLOCKS = YES;
406 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
407 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
408 | GCC_WARN_UNDECLARED_SELECTOR = YES;
409 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
410 | GCC_WARN_UNUSED_FUNCTION = YES;
411 | GCC_WARN_UNUSED_VARIABLE = YES;
412 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
413 | MTL_ENABLE_DEBUG_INFO = NO;
414 | MTL_FAST_MATH = YES;
415 | SDKROOT = iphoneos;
416 | SWIFT_COMPILATION_MODE = wholemodule;
417 | SWIFT_OPTIMIZATION_LEVEL = "-O";
418 | VALIDATE_PRODUCT = YES;
419 | };
420 | name = Release;
421 | };
422 | 22B3A603269DC48100E1E843 /* Debug */ = {
423 | isa = XCBuildConfiguration;
424 | buildSettings = {
425 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
426 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
427 | CODE_SIGN_ENTITLEMENTS = BeelineExample/BeelineExample.entitlements;
428 | CODE_SIGN_STYLE = Automatic;
429 | DEVELOPMENT_TEAM = 6LF3GMKZAB;
430 | INFOPLIST_FILE = "$(SRCROOT)/BeelineExample/Supporting/Info.plist";
431 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
432 | LD_RUNPATH_SEARCH_PATHS = (
433 | "$(inherited)",
434 | "@executable_path/Frameworks",
435 | );
436 | PRODUCT_BUNDLE_IDENTIFIER = dev.tim.BeelineTest;
437 | PRODUCT_NAME = "$(TARGET_NAME)";
438 | SUPPORTS_MACCATALYST = NO;
439 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
440 | SWIFT_VERSION = 5.0;
441 | TARGETED_DEVICE_FAMILY = "1,2";
442 | };
443 | name = Debug;
444 | };
445 | 22B3A604269DC48100E1E843 /* Release */ = {
446 | isa = XCBuildConfiguration;
447 | buildSettings = {
448 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
449 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
450 | CODE_SIGN_ENTITLEMENTS = BeelineExample/BeelineExample.entitlements;
451 | CODE_SIGN_STYLE = Automatic;
452 | DEVELOPMENT_TEAM = 6LF3GMKZAB;
453 | INFOPLIST_FILE = "$(SRCROOT)/BeelineExample/Supporting/Info.plist";
454 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
455 | LD_RUNPATH_SEARCH_PATHS = (
456 | "$(inherited)",
457 | "@executable_path/Frameworks",
458 | );
459 | PRODUCT_BUNDLE_IDENTIFIER = dev.tim.BeelineTest;
460 | PRODUCT_NAME = "$(TARGET_NAME)";
461 | SUPPORTS_MACCATALYST = NO;
462 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
463 | SWIFT_VERSION = 5.0;
464 | TARGETED_DEVICE_FAMILY = "1,2";
465 | };
466 | name = Release;
467 | };
468 | /* End XCBuildConfiguration section */
469 |
470 | /* Begin XCConfigurationList section */
471 | 2284DE05298028C7003A3371 /* Build configuration list for PBXNativeTarget "BeelineTests" */ = {
472 | isa = XCConfigurationList;
473 | buildConfigurations = (
474 | 2284DE06298028C7003A3371 /* Debug */,
475 | 2284DE07298028C7003A3371 /* Release */,
476 | );
477 | defaultConfigurationIsVisible = 0;
478 | defaultConfigurationName = Release;
479 | };
480 | 22B3A5E9269DC48000E1E843 /* Build configuration list for PBXProject "Beeline" */ = {
481 | isa = XCConfigurationList;
482 | buildConfigurations = (
483 | 22B3A600269DC48100E1E843 /* Debug */,
484 | 22B3A601269DC48100E1E843 /* Release */,
485 | );
486 | defaultConfigurationIsVisible = 0;
487 | defaultConfigurationName = Release;
488 | };
489 | 22B3A602269DC48100E1E843 /* Build configuration list for PBXNativeTarget "BeelineExample" */ = {
490 | isa = XCConfigurationList;
491 | buildConfigurations = (
492 | 22B3A603269DC48100E1E843 /* Debug */,
493 | 22B3A604269DC48100E1E843 /* Release */,
494 | );
495 | defaultConfigurationIsVisible = 0;
496 | defaultConfigurationName = Release;
497 | };
498 | /* End XCConfigurationList section */
499 | };
500 | rootObject = 22B3A5E6269DC48000E1E843 /* Project object */;
501 | }
502 |
--------------------------------------------------------------------------------