Xvolks
Xvolks

Reputation: 2155

Is there a way to make CoreML model available for iOS11+ at source level

I have a CoreML model in my application.

At run time, the prediction feature should be disabled on iOS8-10 and active on iOS11.

To be able to compile, on all classes that use CoreML, I have added :

@available(iOS 11.0, *)

But the .mlmodel generates the Swift code at every rebuild discarding all annotations. And so creating compile errors like :

'MLModel' is only available on iOS 11.0 or newer

Is there a way in Xcode9 to make the mlmodel iOS11 only?

EDIT: This bug was fixed in XCode 9 beta 4. The workaround is not needed anymore.

Upvotes: 4

Views: 2842

Answers (2)

Upd. 07/25/17: Apple just have introduced new API for compiling models on device. This means, that you can avoid steps 1-4 now.

  1. (optional) Switch to Xcode beta sudo xcode-select --switch /Applications/Xcode-beta.app/Contents/Developer.
  2. Compile your model: xcrun coremlcompiler compile /path/to/MyModel.mlmodel /path/to/output/folder.
  3. Put compiled model folder MyModel.mlmodelc into your app bundle.
  4. Add auto-generated swift model class (MyModel.swift) to your project manually and annotate it with @available(iOS 11.0, *). How to find model class
  5. Load and initialize your model:

    let path = Bundle.main.path(forResource: "MyModel", ofType: "mlmodelc")

    let url = URL(fileURLWithPath: path!)

    let model = try! MyModel(contentsOf: url)

Warning: I haven't tried to upload such app to the AppStore. I’ve tried it on my test device, and it works, I’m just not sure if it continues working after releasing to the Appstore.

Upvotes: 8

rickster
rickster

Reputation: 126167

This sounds like a bug — the generated Swift code should include @available annotations just like yours, so that your app compiles, can call into it while running in iOS 11, and be required to not call it when running in older iOS versions.

I’d strongly recommend filing that bug with Apple so they can hopefully fix it before Xcode 9 GM.

In the meantime, you can disable code generation for your model. In your code project settings, under Build Settings for your target, look for “CoreML Code Generation Language” and change it to “None”.

That will, of course, prevent you from using the generated Swift class in your project, though. This leaves you with two options:

  1. Use the Core Ml API directly to evaluate your model. (That is, MLModel(contentsOf: url) instead of MyModelClass(), etc.) Conveniently, the generated Swift class that you’ve seen but aren’t using shows you all the API calls you’ll need.

  2. Generate the Swift class once (compiling for iOS 11 only), then copy the code out of there and paste it in a regular source file. After pasting, you can add the required @available declarations so that you can change your minimum deployment target to iOS 10 or earlier.

In both cases, there’s work that you may need to redo if you ever change the model.

Upvotes: 2

Related Questions