Hi, yes, you can modify the Package.swift file included in your playground. It is normally not accessible within Xcode / Swift Playgrounds but you can edit it if you show the playground's contents in Finder. This file's names comes from Swift packages (Playgrounds are essentially a special type of Swift Package).
Be aware that this file is automatically generated, so there may be chances for it to be overwritten when you change playground's settings, as the warning at the top of it suggests (I would also like more insight into this if somebody else knows - is editing the minimum target version or the target resources a good practice, or is it at risk to be overwritten? From my testings, it seems to work fine with changing the target resources).
Check this thread for ideas on how to support older iOS versions in your code, or modify your Package.swift file like I explained above.
If this is for the Swift Student Challenge (as your tag suggests), I'm not sure if it's okay to modify the minimum target version. Perhaps the judges will have the latest version of iPadOS / macOS, but currently the website says the following:
"Your app playground must be built with and run on Swift Playgrounds 4.4 or later (requires iPadOS 16 or macOS 13.5) or Xcode 15 on macOS 13.5 or later. You may incorporate the use of Apple Pencil."
https://developer.apple.com/swift-student-challenge/eligibility/
Post
Replies
Boosts
Views
Activity
I meant tabular regression models.
I believe I finally found an overall solution that works for both compiled (.mlmodelc) and uncompiled models (.mlmodel, .mlpackage), plus an explanation of why .mlmodelc files may not be correctly copied in the bundle during the build process. I also sent a similar response in this recently opened similar thread.
Steps to fix the bundling issues
You will need to edit the Package.swift file manually. Go to the playground in Finder, control-click it and select Show Package Contents. Then, open the Package.swift file. At the bottom of this file, you'll find the following target section, which might look different for you:
targets: [
.executableTarget(
name: "AppModule",
path: ".",
resources: [
.process("Resources") // copy resources to the app bundle without keeping folder structure
]
)
]
The .process("Resources") line indicates that the resources (in your case, your model) must be copied without keeping the original folder structure. Say you have 2 folders inside the Resources folder, and in each of these you have a few files. Only the files inside will be copied in the bundle, and the 2 original folders won't appear.
You will need to replace (or add, if you don't have the process() function) process() with copy(), which maintains the internal folder structure (I explained below why). You can either use .copy("Resources"), which require you to change the model's bundle URL inside your code, not this Package.swift file to this:
Bundle.main.url(forResource: "Resources/MobileNetV2", withExtension:"mlmodelc")
Notice this includes "Resources/" inside the path.
Or you might directly copy the model folder to the Bundle using .copy("Resources/MobileNetV2") and keep the URL without the "Resources/" part - note that this way, any other files in the Resources might not be available unless you add other process / copy functions to your Package.swift file.
For more information about process() and copy(), check the docs for bundling resources with Swift Packages (since a Swift Playground is a special type of a Swift Package).
Why compiled models are not correctly copied in the bundle using process()
Compiled ML models are essentially a folder that contains one or more coremldata.bin files (and maybe other files as well) - in fact, they appear as a folder on the filesystem (you can cd into them in Terminal). The reason why these .mlmodelc aren't correctly copied to your bundle when using .process("Resources"), or may give a build error with certain models that contain more coremldata.bin files, is that the internal folder structure is not copied, but only the files inside it. That's why you found that your bundle contained a coremldata.bin file only.
Using the previously mentioned .copy() method, you can keep the internal folder structure.
How do I use my ML models, now that I can bundle them with my App?
You can create your own code that reads the model from the bundle and compiles it if necessary, or you can copy the Model Class file that is usually generated in Xcode projects. You will need to make the necessary changes related to the file's Bundle URL.
Why do uncompiled models result in build issues?
Regarding why uncompiled models cannot be built in Xcode, something similar to the compiled models issue might be happening, but these do not appear as folders on the filesystem - so this should probably not happen and perhaps it is a build issue.
It also seems that .mlmodels are not compiled at runtime, which I believe used to happen in the previous Swift Playgrounds / Xcode versions from last year. So, if the bundling issue is fixed and .mlmodels are bundled with your app, you might need to insert additional code that compiles the model with something like this:
let compiledModelURL = try await MLModel.compileModel(at: url)
let model = try MLModel(contentsOf: compiledModelURL)
Let me know if this works!
I believe I finally found an overall solution that works for both compiled (.mlmodelc) and uncompiled models (.mlmodel, .mlpackage), plus an explanation of why .mlmodelc files may not be correctly copied in the bundle during the build process (even though it succeeds).
I also sent a similar answer to this other thread, and included a few more details about an issue unique to Xcode and uncompiled models.
You will need to edit the Package.swift file manually. Go to the playground in Finder, control-click it and select Show Package Contents. Then, open the Package.swift file. At the bottom of this file, you'll find the following target section, which might look different for you:
targets: [
.executableTarget(
name: "AppModule",
path: ".",
resources: [
.process("Resources") // copy resources to the app bundle without keeping folder structure
]
)
]
The .process("Resources") line indicates that the resources (in your case, your model) must be copied without keeping the original folder structure. Say you have 2 folders inside the Resources folder, and in each of these you have a few files. Only the files inside will be copied in the bundle, and the 2 original folders won't appear.
You will need to replace (or add, if you don't have the process() function) process() with copy(), which maintains the internal folder structure (I explained below why). You can either use .copy("Resources"), which require you to change the model's bundle URL like this:
class var urlOfModelInThisBundle : URL {
let bundle = Bundle(for: self)
return bundle.url(forResource: "Resources/MobileNetV2", withExtension:"mlmodelc")!
}
Or you might directly copy the model folder to the Bundle using .copy("Resources/MobileNetV2") and keep the original URL - note that this way, any other files in the Resources might not be available unless you add other process / copy functions to your Package.swift file.
For more information about process() and copy(), check the docs for bundling resources with Swift Packages (since a Swift Playground is a special type of a Swift Package).
Why compiled models are not correctly copied in the bundle using process()
Compiled ML models are essentially a folder that contains one or more coremldata.bin files (and maybe other files as well) - in fact, they appear as a folder on the filesystem (you can cd into them in Terminal). The reason why these .mlmodelc aren't correctly copied to your bundle when using .process("Resources"), or may give a build error with certain models that contain more coremldata.bin files, is that the internal folder structure is not copied, but only the files inside it. That's why you found that your bundle contained a coremldata.bin file only.
Using the previously mentioned .copy() method, you can keep the internal folder structure.
Regarding why uncompiled models cannot be built in Xcode, something similar might be happening, but these do not appear as folders on the filesystem - so this should probably not happen and perhaps it is a build issue. It also seems that .mlmodels are not compiled at runtime, which I believe used to happen in the previous Swift Playgrounds / Xcode versions from last year.
Let me know if this works!
I think I found out why I couldn't build playgrounds with .mlmodelc files - it seems that the playground I used had a Resources folder but it didn't appear in the target's resources in Package.swift due to some reason - perhaps I manually played with it at some point and forgot about it. Editing this file / making a new playground solved the build issues for me.
However, I still get the same build problems with uncompiled models (.mlmodel) in Xcode 15.
I'm curious, have you tried using the coremldata.bin file as a resource? It should contain the model data. I haven't tried this and it's just a guess.
I'm still getting issues with tabular regressor ML models in Swift Playgrounds as well, just as in Xcode - that multiple commands produce coremldata.bin. I'll look into this further, perhaps with other models too (including MobileNetV2). Also, it seems that .mlmodel (uncompiled) files are simply copied to the bundle and not compiled - which I believed it used to happen last year, at least in Xcode 14.
Perhaps CoreML models are completely unsupported in Swift Playgrounds?
I haven’t looked into this further than you did yet, but I think I also reproduced this same issue a few days ago when I was trying to find the differences between Xcode and Swift Playgrounds regarding building projects with ML models.
What I know for sure is that at least the app builds successfully, compared to doing the same thing in Xcode - more details about this are available in this thread.
Hi! I am not entirely sure if Swift Packages (a Swift Playground is essentially a special type of Swift Package) support editing build phases like in Xcode projects.
When adding the folder to your playground (either by drag & drop or the plus button in the bottom left), wasn't it automatically placed within a "Resources" folder? It believe the USDZ needs to be placed within the generated Resources folder, not at the root of your playground.
Then, you can access it using Bundle.main.url (and perhaps also Bundle.main.path):
// make sure that "filename" doesn't contain the extension!
guard let url = Bundle.main.url(forResource: filename, withExtension:"usdz") else { fatalError("Couldn't find the USDZ file.") }
If you really need multiple Resources folders, a "hacky" thing you could do is to edit the Package.swift file. Control-click the Playground file in Finder and choose theShow package contents option, then open the Package.swift file and edit the target's resources:
targets: [
.executableTarget(
name: "AppModule",
path: ".",
resources: [
.process("Resources"),
.process("Second Folder") // your second folder
]
)
]
But make sure to pay attention to the warning that you may have at the beginning of this file:
// WARNING:
// This file is automatically generated.
// Do not edit it by hand because the contents will be replaced.
This file's contents may change when you edit other settings such as the App Icon from within Xcode. From my testings the resources folders seem to stay intact, but it's good to keep the warning in mind. Thus, the best way would be to simply use the provided "Resources" folder.
I believe this is a build issue in Xcode 15. For reference, I reported this as FB13521432.
When I add an ML model (I tried .mlmodel, .mlpackage or .mlmodelc) to my App Playground's Resources folder in Xcode 15, the build fails with 1-2 errors, even if I don't use the models within the playground's code.
The first error I get is related to multiple build files with the same name being produced. Here is what I get with an .mlmodel or .mlpackage file:
error: Unexpected duplicate tasks
note: Target 'playground' (project 'playground') has write command with output /Users/[user]/Library/Developer/Xcode/DerivedData/playground-dzqpmayqqzdqoqebzuczjghhqqbk/Build/Intermediates.noindex/playground.build/Debug-iphoneos/playground.build/e1be5a3b551803f068478ad1867f7edd.sb
note: Target 'playground' (project 'playground') has write command with output /Users/[user]/Library/Developer/Xcode/DerivedData/playground-dzqpmayqqzdqoqebzuczjghhqqbk/Build/Intermediates.noindex/playground.build/Debug-iphoneos/playground.build/e1be5a3b551803f068478ad1867f7edd.sb
A similar error is produced when using compiled models (.mlmodelc):
Multiple commands produce '/Users/[user]/Library/Developer/Xcode/DerivedData/playground-dzqpmayqqzdqoqebzuczjghhqqbk/Build/Products/Debug-iphoneos/playground.app/coremldata.bin'
The second error I get when using ML models that weren't compiled is related to COREML_CODEGEN_LANGUAGE:
No predominant language detected. Set COREML_CODEGEN_LANGUAGE to preferred language.
Did you also get these build issues?
I don't think there's a direct conversion method available, but you can copy the Swift files directly to the playground. For example, provided that you use SwiftUI, you can directly drag and drop the App, ContentView and other View files into your playground, and everything should work fine. But you will also need to copy the assets and resources separately and may require additional work. An example is when you use CoreML models (I need to look into this further, perhaps watch this thread for updates if you use ML models).
Unfortunately, I am not entirely sure what run destination will be chosen in Xcode. I also asked this last year in this thread, and you might be able to include some specific instructions with your submission. But I would definitely recommend you to take on a challenge and make your app available on iPad / Mac, especially if you use SwiftUI, since it makes things easier. By the way, the Mac and iPad app should look pretty similar since the Mac options use Catalyst.
Also, since you said you already made an app, you might need to make sure your playground will not use external resources (i.e. the internet), since that was in last years' terms.
I've tried to look into this further with the Console app, and it seems that everything might be working but very slowly due to the large dataset. However, I don't remember this process being that slow on Xcode 14.
The only reports I found were some cpu usage and wakeups diagnostic reports.
After leaving it process the data for a while, I eventually got some <private> class has successfully loaded the model at <private>. and The optimizer converged after ... iterations. streamed by the MLRecipeExecutionService (CoreML) and IntelligencePlatformComputeService (CoreML) processes after 5 minutes. But after 30 minutes the training is still not finished.
Another log message I found is the following:
<private> class was unable to load the model at <private> with error: <private>; The model loader is going to use another class.
When you created your apps in Xcode, you probably made an Xcode project (with the .xcodeproj extension). The challenge requires you to make a Swift Playground that you can make with either Xcode or Swift Playgrounds. To make a Swift Playground, check the instructions in this thread.
Regarding your age, the full terms and conditions of the 2024 challenge are not yet available, but they will be released in February according to the website. Last year, it was specified in the terms that your parents / legal guardians may send an email to swiftstudentchallenge@apple.com to request permission if your age is under the minimum one in your region. If you would like to check the terms, it was specified in the paragraph before submission requirements. Here's a thread from last year if it helps.
Hi, and happy new year! Perhaps you need an object that conforms to Observable or ObservableObject (the old protocol used before iOS 17) somewhere?
I am not sure where your icon "check.circle" or "circle" is situated in your code.
Hi and happy new year!
The error indicates that the file wasn't found - the app usually searches the file inside the Resources folder.
I am not sure if moving it inside the Resources folder inside GamePlayground would work. If it doesn't, try adding the scene again so that a "global" Resources folder is created (either drag & drop the scene or click the plus button in the bottom left.
Hi! It seems that App Playgrounds require support for iOS 16.0 on this version of Xcode (not sure if this is a bug or intended for compatibility reasons). Even though you want to run your app on an iOS 17.0 device, the App Playground is set to build for iOS 16 devices too, and this is why your build fails (remember, to run a code it must first be built, and building requires your code to work on all devices it is configured for, not just on the one you use to test it).
You should've received some relevant error messages and fixes that mention the if #available version check or the @available(iOS 17.0, *) attribute. These may be useful If you want to maintain the iOS 16 compatibility. This is analogous to changing the minimum iOS deployment version in an .xcodeproj.
You could use the if #available version check like this:
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
if #available(iOS 17.0, *) {
ScrollView {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("iOS 17.0")
}
.defaultScrollAnchor(.bottom)
} else {
ScrollView {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("iOS 16.0")
}
}
}
}
}
Or you could add the @available(iOS 17.0, *) attribute to the enclosing View like this:
import SwiftUI
@available(iOS 17.0, *)
struct ContentView: View {
var body: some View {
VStack {
ScrollView {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
.defaultScrollAnchor(.bottom)
}
}
}
And then, in the App struct, use the if #available version check:
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
if #available(iOS 17.0, *) {
ContentView()
} else {
// Fallback on earlier versions
Text("This feature requires iOS 17.0.")
}
}
}
}
Now, if you want a "hacky" method, you could edit the package files of your App Playground. To do this, go to File > Show in Finder, and then open the Package.swift file. After that, you can change the .iOS("16.0") line to 17.0.
Also, I recommend you to use the latest Xcode version & macOS (they bring bug fixes and security improvements 😁).
Good luck and Happy New Year!