CoreNavigation 
   📱 
  
   📲 
  
 
Navigate between view controllers with ease. 
 
Getting Started
These instructions will help you integrate CoreNavigation into your project.
Prerequisities
- Xcode 9 or higher
 - iOS 8 or higher
 - Cocoapods
 
Installation
CocoaPods
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapods 
CocoaPods 1.1+ is required to build CoreNavigation 1.0+.
To integrate CoreNavigation into your Xcode project using CocoaPods, specify it in your Podfile:
target '
   
    '
     do
    use_frameworks!
    
    pod 'CoreNavigation', '1.0.0-beta-4'
end 
Then, run the following command:
$ pod install 
Carthage
Carthage 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 carthage 
To integrate CoreNavigation into your Xcode project using Carthage, specify it in your Cartfile:
github "aronbalog/CoreNavigation" == "1.0.0-beta-4"
 
API Reference
API reference
Example Use
Defining view controller:
class PersonProfileViewController: UIViewController, DataReceivable {
    // DataReceivable associatedtype
    typealias DataType = Person
    func didReceiveData(_ data: Person) {
        // configure UI with data
    }
} 
Presenting view controller:
Navigate.present { $0
    .to(PersonProfileViewController())
    .withData(person)
} 
Pushing view controller:
Navigate.push { $0
    .to(PersonProfileViewController())
    .withData(person)
} 
Routing & deep linking:
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.
 
Defining Destination
 
 
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
   ) {
        
   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)
        })
    }
}
    
Registering Routable types
 
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"
] 
 Navigating using Destination
 
// 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() 
 Navigating using route
// 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() 
 Getting view controller asynchronously using Destination
 
PersonProfile("sherlock_holmes").viewController { (viewController) in
    // vc is `PersonProfileViewController`
} 
Getting view controller asynchronously using route
"https://myapp.com/person/sherlock_holmes".viewController { (viewController) in
    ...
} 
Getting view controller synchronously using Destination
 
 
do {
    let viewController = try PersonProfile("sherlock_holmes").viewController()
} catch let error {
    // handle error
} 
Getting view controller synchronously using route
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.
Matchable protocol
URL types can also be used to navigate or resolve view controller. Actually, any type conforming Matchable protocol can be used.
Conforming to matchable:
struct Person {
    let id: String
    ...
}
extension Person: Matchable {
    var uri: String {
        return "https://myapp.com/person/" + id
    }
} 
Example usage:
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)
    ...
} 
Configuration
- Animating
 - Observing completion
 - Observing success
 - Observing failure
 - Embedding
 - Passing data
 - Caching
 - Protection
 - State restoration
 - Specifying origin view controller
 
Example Apps
Running the Tests
Available in CoreNavigationTests target.
Versioning
Current release:
- 1.0.0-beta-4
 
Authors
Contributing
Please read Contributing for details on code of conduct, and the process for submitting pull requests.
License
This project is licensed under the MIT License - see the LICENSE file for details.