mapbox/mapbox-navigation-ios

Discontinue Objective-C compatibility

Closed this issue · 5 comments

1ec5 commented

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 and MB 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

1ec5 commented

Work is starting in #2230.

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?

1ec5 commented

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.

1ec5 commented

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.