How to develop for impending beta features while supporting older iOS versions

Hi there,

This is more of a "how-to," "am I doing this right?" question, as I've never done this before, and I couldn't find any definitive write up for how to do this, so I'm asking here.

With the release of iOS16 beta, I've been implementing some new MusicKit features in an iOS app I'm working on that was initially built for iOS 15.

Setup:

  • dev machine: masOS Monterey 12.4
  • test device 1: iOS 15.4
  • test device 2: iOS 16 beta 2

Xcode versions:

  • 14.0 beta 2 (14A5229c)
  • 13.4.1 (13F100)

The original app was written, using Xcode 13 and has an iOS Development Target of 15.0

Steps:

  1. create new branch off main called beta16
  2. open Xcode beta2 and switch to new branch
  3. set the iOS Development Target for the project to 15.0
  4. make code changes in the new branch, using ifavailable to handle both iOS 16 and fallback version code.

Results:

When I test the new code using Xcode 14 beta 2 on an iOS 16 device, things work as expected.

When I test the new code using Xcode 14 beta on an iOS 15 device, the app builds and then crashes immediately upon open with:

dyld[38909]: Symbol not found: _$s8MusicKit0A20CatalogSearchRequestV17includeTopResultsSbvs
  Referenced from: /private/var/containers/Bundle/Application/4BB8F74F-FDA6-4DF1-8B04-010EA87BA80C/MyApp.app/MyApp
  Expected in: /System/Library/Frameworks/MusicKit.framework/MusicKit
Symbol not found: _$s8MusicKit0A20CatalogSearchRequestV17includeTopResultsSbvs
  Referenced from: /private/var/containers/Bundle/Application/4BB8F74F-FDA6-4DF1-8B04-010EA87BA80C/MyApp.app/MyApp
  Expected in: /System/Library/Frameworks/MusicKit.framework/MusicKit

When coding, I followed all of Xcodes prompting that says when a potentially unsupported new feature is being used.

When I look to where .includeTopResults is being used, I can see that it was not wrapped with ifavailable:

var request = MusicCatalogSearchRequest(term: searchString, types: [Song.self])
    request.includeTopResults = true
let response = try await request.response()

If I comment out the line with .includeTopResults, the app runs on the iOS 15 device w/o issue.

If I wrap it in ifavailable, like this, it crashes as before:

var request = MusicCatalogSearchRequest(term: searchString, types: [Song.self])
if #available(iOS 16, *) {
    request.includeTopResults = true
}
let response = try await request.response()

If I check the docs here, I think I'm using .includeTopResults correctly.

Question:

My main question here is if I'm correctly developing the app toward the goal of supporting new iOS 16 features, while also supporting devices using iOS 15, via fallback.

Ultimately, I plan to merge the beta16 branch into a branch from which I'll deploy the app.

The app crashing when using .includeTopResults has me hesitant because I don't know if that's a bug or if I'm the bug. Usually, it's the latter.

It seems like the steps outlined above are the correct way to develop toward supporting upcoming features and "legacy iOS versions", but I'm not sure.

Any clarity on this would be most appreciated.

Thanks!

Accepted Reply

Hello @Kimfucious,

Sorry for the very late update, but just to close the loop on this, we did address this issue in a subsequent beta version of iOS 16.0, before the final version was offered to regular customers.

Thanks again for reporting this issue!

Best regards,

Replies

use #avaliable on mine works:

if #available(iOS 16.0, *) {
    ...
} else {
    ...
}

I'm not sure why yours don't.

  • Thanks, @makabaka1880. That same pattern works for me in all but the case I've mentioned with .includeTopResults.

Add a Comment

Hello @Kimfucious,

Thank you so much for reporting this issue.

The following code should work:

var request = MusicCatalogSearchRequest(term: searchString, types: [Song.self])
if #available(iOS 16, *) {
    request.includeTopResults = true
}
let response = try await request.response()

And it's not our intention for you to be able to compile this code:

var request = MusicCatalogSearchRequest(term: searchString, types: [Song.self])
request.includeTopResults = true
let response = try await request.response()

with a deployment target such as iOS 15.0.

This is an easy fix on our end. We just need to add the correct availability annotations for includeTopResults.

Stay tuned.

  • Thanks for the pro follow-up, @JoeKun!

    I'll await your update here.

Add a Comment

Hello @Kimfucious,

Sorry for the very late update, but just to close the loop on this, we did address this issue in a subsequent beta version of iOS 16.0, before the final version was offered to regular customers.

Thanks again for reporting this issue!

Best regards,