Navigate between view controllers with ease. π«
π More stable version (written in Swift 5) coming soon.
These instructions will help you integrate CoreNavigation into your project.
- Xcode 9 or higher
- iOS 8 or higher
- Cocoapods
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapodsCocoaPods 1.1+ is required to build CoreNavigation 1.0+.
To integrate CoreNavigation into your Xcode project using CocoaPods, specify it in your Podfile:
target '<Your Target Name>' do use_frameworks! pod 'CoreNavigation', '1.0.0-beta-4' endThen, run the following command:
$ pod installCarthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with Homebrew using the following command:
$ brew update $ brew install carthageTo integrate CoreNavigation into your Xcode project using Carthage, specify it in your Cartfile:
github "aronbalog/CoreNavigation" == "1.0.0-beta-4" class PersonProfileViewController: UIViewController, DataReceivable { // DataReceivable associatedtype typealias DataType = Person func didReceiveData(_ data: Person) { // configure UI with data } }Navigate.present { $0 .to(PersonProfileViewController()) .withData(person) }Navigate.push { $0 .to(PersonProfileViewController()) .withData(person) }Why use the Destination instead navigating directly to view controller?
Read about it on Medium:
- #0 present & push⦠For how long?
- #1 Forget about segues.
- #2 Passing data between view controllers.
- #3 Handle Universal Links Like a Boss.
struct PersonProfile: Destination, Routable { // Destination associatedtype typealias ViewControllerType = PersonProfileViewController // Routable patterns static var patterns: [String] = [ "https://myapp.com/person/:personId(.*)", "https://myapp.com/user/:personId(.*)" ] let personId: String init(_ personId: String) { self.personId = personId } var parameters: [String : Any]? { return [ "personId": personId ] } static func resolve(context: Context<PersonProfile>) { guard let personId = context.parameters?["personId"] as? String else { // cancel navigation with some error context.cancel(error: NavigationError.Destination.notFound) return } // fetch person fetchPerson(id: personId, completion: { (person: Person) in // continue to navigation context.complete(data: person) }, failure: { (error: Error) in // cancel navigation with some error context.cancel(error: error) }) } }In order to use Matchable types (String, URL, etc.) to navigate, every Destination type must be registered. Think about it as internal DNS.
PersonProfile.register()Additional syntax
Navigate.router.register(routableType: PersonProfile.self)Destination type can be routable without conforming to Routable protocol. Use this if you intend to create some kind of destination manifest and/or if route patterns are fetched from an external source:
Navigate.router.register(destinationType: PersonProfile.self, patterns: [ "https://myapp.com/person/:personId(.*)", "https://myapp.com/user/:personId(.*)" ])Additional syntax
PersonProfile.self <- [ "https://myapp.com/person/:personId(.*)", "https://myapp.com/user/:personId(.*)" ] Settings.self <- [ "https://myapp.com/settings" ]// present Navigate.present { $0 .to(PersonProfile("sherlock_holmes")) ... } // or push Navigate.push { $0 .to(PersonProfile("sherlock_holmes")) ... }Additional syntax
// present PersonProfile("sherlock_holmes").present { $0 ... } // or push PersonProfile("sherlock_holmes").push { $0 ... }Additional syntax
// present PersonProfile("sherlock_holmes").present() // or push PersonProfile("sherlock_holmes").push()// present Navigate.present { $0 .to("https://myapp.com/person/sherlock_holmes") ... } // or push Navigate.push { $0 .to("https://myapp.com/person/sherlock_holmes") ... }Additional syntax
// present "https://myapp.com/person/sherlock_holmes".present { $0 ... } // or push "https://myapp.com/person/sherlock_holmes".push { $0 ... }Additional syntax
// present "https://myapp.com/person/sherlock_holmes".present() // or push "https://myapp.com/person/sherlock_holmes".push()PersonProfile("sherlock_holmes").viewController { (viewController) in // vc is `PersonProfileViewController` }"https://myapp.com/person/sherlock_holmes".viewController { (viewController) in ... }do { let viewController = try PersonProfile("sherlock_holmes").viewController() } catch let error { // handle error }do { let viewController = try "https://myapp.com/person/sherlock_holmes".viewController() } catch let error { // handle error }Note:
If you implement custom destination resolving, it must happen on the main thread; otherwise, an error is thrown.
URL types can also be used to navigate or resolve view controller. Actually, any type conforming Matchable protocol can be used.
struct Person { let id: String ... } extension Person: Matchable { var uri: String { return "https://myapp.com/person/" + id } }let person: Person = Person(id: "sherlock_holmes", ...) // getting view controller let personProfileViewController = try! person.viewController // or navigating person.present() person.push() // or more configurable syntax Navigate.present { $0 .to(person) ... }- Animating
- Observing completion
- Observing success
- Observing failure
- Embedding
- Passing data
- Caching
- Protection
- State restoration
- Specifying origin view controller
Available in CoreNavigationTests target.
Current release:
- 1.0.0-beta-4
Please read Contributing for details on code of conduct, and the process for submitting pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.