Discontinue Objective-C compatibility
1ec5 opened this issue · 5 comments
We’re discontinuing support for applications written purely in Objective-C to use the iOS navigation SDK. The same change will take place in MapboxDirections.swift: mapbox/mapbox-directions-swift#381. Applications written in Objective-C will need to implement compatibility shims in Swift to continue to interoperate with this library.
Since #3, we’ve half-heartedly supported Objective-C by ensuring bridgeability of key APIs, but there are many gaps in coverage, and the public API in Objective-C feels like a translation from another language. A renewed focus on Swift will eliminate a major source of technical debt. We’ll be able to write more idiomatic, less error-prone Swift code without compromising the developer experience in both languages.
Hybrid application frameworks (such as React Native) are implemented in Objective-C. Discontinuing Objective-C support makes it more difficult – but not infeasible – for a developer to write a hybrid wrapper around the SDK. For instance, a React Native wrapper such as react-native-maps-navigation would need an additional compatibility shim written in Swift to translate the navigation SDK’s API to a more basic API that can bridge to Objective-C. Regardless, we do not officially support hybrid application frameworks.
Discontinuing Objective-C support will have the following immediate impacts on the codebase:
@objc
attributes andMB
class prefixes will disappear, except in some edge cases that require Objective-C method dispatch (for key-value observation).- Methods whose sole purpose is to bridge to Objective-C will disappear.
- Enumeration declarations will move from Objective-C headers to Swift files.
- References to Objective-C compatibility will be removed from readmes and jazzy guides.
We’ll hopefully be able to take advantage of some Swift language features in the process:
- Convert value classes to structures or enumerations with associated types.
- Convert abstract classes to protocols with default implementations.
- Move global variables and global constants under structures and classes.
- Replace magic default values with optionals.
- Replace NSCoding with Codable.
/cc @mapbox/navigation-ios
Do we know the last compatible SDK version with ObjC? I've got 37 installed, but 38 doesn't want to install properly using CocoaPods. I'm working on a complete rewrite with Swift, but I want to keep the ObjC project going while I'm working. What will the final ObjC compatible version be?
v0.38.0 is still compatible with Objective-C. If you’re having difficulty installing it via CocoaPods, make sure your minimum deployment target is equal to or greater than this library’s minimum deployment target, which is iOS 10.0 following #2206.
We don’t currently have another release scheduled before we land #2230, which drops Objective-C support.
Hybrid application frameworks (such as React Native) are implemented in Objective-C. Discontinuing Objective-C support makes it more difficult – but not infeasible – for a developer to write a hybrid wrapper around the SDK. For instance, a React Native wrapper would need an additional compatibility shim written in Swift to translate the navigation SDK’s API to a more basic API that can bridge to Objective-C. Regardless, we do not officially support hybrid application frameworks.
If your application is written in Objective-C, the changes in v1.0.0-alpha.1 don’t mean you have to rewrite your application in Swift, though you’re certainly free to do so. But you would at a minimum need to write a compatibility shim around the parts of the navigation SDK’s public API that your application uses. For example, here’s a compatibility shim that allows an application to present a NavigationViewController navigating between a specific origin and destination:
@objcMembers class NavigationViewControllerProxy: NSObject {
var origin: CLLocationCoordinate2D
var destination: CLLocationCoordinate2D
init(origin: CLLocationCoordinate2D, destination: CLLocationCoordinate2D) {
self.origin = origin
self.destination = destination
super.init()
}
func present(from parentViewController: UIViewController, animated: Bool) {
// Configure and present NavigationViewController like you would in Swift.
let options = NavigationRouteOptions(coordinates: [origin, destination])
Directions.shared.calculate(options) { (waypoints, routes, error) in
guard let route = routes?.first else { return }
let navigationViewController = NavigationViewController(for: route)
navigationViewController.modalPresentationStyle = .fullScreen
parentViewController.present(navigationViewController, animated: true, completion: nil)
}
}
}
You can adjust and expand upon this code snippet to suit your application’s needs. For example, you can modify NavigationViewControllerProxy.present(from:animated:)
to set additional Directions API options or specify a NavigationOptions or additional Style subclasses. This proxy object could also conform to NavigationViewControllerDelegate, in case you need to respond to any location-related events coming out of the navigation service. This is not unlike how SwiftUI applications would interact with NavigationViewController.
Thank you! I appreciate the info.