Subclassing `MKMapItem` resulting in Fatal error

I would like the MKMapItem returned from MKLocalSearch to contain an "altitude" property. In order to achieve this, I've decided to create a subclass for MKMapItem.

class MapItemGeoSpatial: MKMapItem {
    var altitude: Measurement<UnitLength>
    
    public init(placemark: MKPlacemark, altitude: Measurement<UnitLength>) {
        self.altitude = altitude
        super.init(placemark: placemark)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

While the above implementation compiles, it results in a fatal error when attempting to initialise MapItemGeoSpatial.

Fatal error: Use of unimplemented initializer 'init()' for class 'MapItemGeoSpatial'

The above error occurs during the super.init(placemark:) call.

The altitude property is set by me (the source of this value is not relevant to this discussion, but it is determined by extracting the coordinates from MKMapItem) via the designated initialiser. I understand that MKLocalSearch has nothing to do with altitude, but I, as the client, found it desirable to contain this information when it is passed to other areas of my project. This is the primary reason why I chose to subclass MKMapItem, in an attempt to "inherit" all it's functionality and introduce my own functionality.

The flow diagram for this process is- MKLocalSearch -> MKMapItem  -> Determine altitude using coordinates from MKMapItem -> Initialise MapItemGeoSpatial.

I can create an override init() for the above class, but this will require me to initialise the altitude property, which is not specified for this initialiser. Initialising altitude by specifying a dummy variable (eg. 0) overcomes this issue, but appears to be a poor workaround. Making altitude optional is another workaround, but this is not a direction I wish to take. I'm aware that MKMapItem inherits from NSObject and I'm curious if this relation has an influence on the above observation. I would like to-

  1. Understand the root cause behind this issue and
  2. Determine if subclassing MKMapItem is a viable solution to the problem mentioned at the start of this post

One approach suggested is wrapping MKMapItem instead of subclassing it. This is one alternative solution for part 2. from the original question, but the root cause behind the fatal error is sidestepped with this approach.

It crashes also just by calling         let mp = MapItemGeoSpatial(placemark: MKPlacemark(), altitude: Measurement(value: 1.5, unit: UnitLength.meters))

The root cause seems to be in the interoperability of Objective-C (which MKMapItem is written in) and Swift, specifically regarding the complex rules for how initializers work. Here are two deep dives into the issue from some years ago:

My takeaway is that some Objective-C classes implement initializers in a way that doesn’t support what you’re trying to do. ☹️

I'll try and summaries the content from the links shared by Scott in the above response to make the information more accessible.

The below diagram represents the general overview for the initialisation process in Swift.

The root cause for the observed behaviour appears to be related to subclassing an Objective-C base class in Swift where the implementation of the base class initialisation process appears to trigger an unaccounted scenario resulting from the differences in the initialisation rules for Objective-C and Swift.

The difference in initialisation rules specific to this post are-

  • Ojbective-C allowing a convenience initialiser to be invoked from a base class
  • Swift classes not automatically inheriting the base class initialisers

The second point is relevant when an Objective-C class looks for an initialiser in the base class. I'm uncertain behind the exact details of this, but from what I can gather, Objective-C subclasses automatically inherit all the initialisers from the base class, and hence the initialiser from the subclass is used when a convenience initialiser from the base class invokes a designated initialiser.

Subclassing `MKMapItem` resulting in Fatal error
 
 
Q