Is there a way to display a .icon file in SwiftUI? I want to show the app icon in the app itself but exporting and including the app icon as a PNG feels redundant. This would consume a lot of unnecessary storage especially when including a lot of alternative app icons. There has to be a better way
Otherwise I would file a feedback for that
Thank you
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I am trying to bring my iOS App to native macOS. I am using exactly the same TimelineProvider and widgets (the ones not supported on macOS surrounded by #if(os)). Running the whole app or just the WidgetExtension on iOS works perfectly fine. Running the mac app works perfectly fine apart from missing Widgets.
When running the WidgetExtension on My Mac, the WidgetKit Simulator opens and only presents Failed to load widget. The operation couldn't be completed. (WidgetKit_Simulator.WidgetDocument.Error error 4.) The code compiles fine without any warnings, only a file path is printed into the console. file:///Users/myName/Library/Developer/Xcode/DerivedData/MyAppName-dfsiuexplidieybwvbkqofchxirp/Build/Products/Debug/MyApp.app/Contents/PlugIns/MyAppNameWidgetExtensionExtension.appex/
Shortly after I get a log entry Logging Error: Failed to initialize logging system. Log messages may be missing. If this issue persists, try setting IDEPreferLogStreaming=YES in the active scheme actions environment variables.
I am not sure which further Informationen I can give to solve my problem. Destinations on main App and Widget Extension is both set to Mac (no suffix). The mac is running 14.4.1 and Xcode 15.3.
I am really thankful for any assistance you can give me to fix this problem. Thanks
Hi, is there a way to display the animated cover art in an app? Not every album has a cover art but for the ones that have one I would like to display them instead of the artwork.
Thank you :)
Apparently the @Query property wrapper from SwiftData does not update when data is loaded from CloudKit. The data can be programmatically be accessed but nothing appears in the view.
Steps to reproduce:
Create new Xcode project using the SwiftData storage option.
Provide a default value for the Item Model. That is required so data can be automatically synced by SwiftData.
Enable iCloud -> CloudKit capabilities and choose a container
Enable Background Modes -> Remote notification capability
Add a toolbar button that prints the number of items from @Query like this:
ToolbarItem {
Button {
print(items.count)
} label: {
Label("Count", systemImage: "1.circle")
}
}
Install app on a physical device that can sync to iCloud.
Add some items using the + in the toolbar
Delete app and wait for around a minute
Reinstall app with a debugger attached
Press the 1.circle button in the toolbar. It will print either 0 or the number of items you previously added. When it does not print 0 the data should be visible but it is not. Once you quit and relaunch the app or press the + button again, all of the items appear.
Has anyone else experienced this before? Anything I can do so the data appears / the view reloads once the items are available? I need to update my view once the data has been loaded from iCloud.
I already filed a bug report with id FB14619787.
I use Universal Product Codes (UPC) in my app to reliably identify albums after having used albumIDs for a time. AlbumIDs can change over time for no obvious reasons (see here for songIDs) so I switched to UPCs since I believed they cannot change. Well apparently they can.
A few days ago I populated a JSON with UPCs including 196871067713. Today trying to perform a MusicCatalogResourchRequest for the UPC does not return anything. When using that UPC and putting it into an Apple Music link like https://music.apple.com/de/album/folge-89-im-geistergarten/1683337782?l=en-GB redirects to https://music.apple.com/de/album/folge-89-im-geistergarten/1683337782?l=en-GB so I assume the UPC has changed from 196871067713 to 1683337782.
Apple Music can handle that and redirects to the new upc both in the app and as a website.
But a MusicCatalogResourceRequest cannot do that. I filed a suggestion for that (FB15167146) but I need a solution quicker. Can I somehow detect where the URL is redirecting to? Is there a way MusicCatalogResourceRequest can do this? Performing a MusicCatalogSearchRequest can be an option but seems unreliable when using the title as search term. Other ideas?
Thank you
The following complex migration consistently crashes the app with the following error:
SwiftData/PersistentModel.swift:726: Fatal error: What kind of backing data is this? SwiftData._KKMDBackingData<SwiftDataMigration.ItemSchemaV1.ItemList>
My app relies on a complex migration that involves these optional 1 to n relationships. Theoretically I could not assign the relationships in the willMigrate block but afterwards I am not able to tell which list and items belonged together.
Steps to reproduce:
Run project
Change typealias CurrentSchema to ItemSchemaV2 instead of ItemSchemaV1.
Run project again -> App crashes
My setup:
Xcode Version 16.2 (16C5032a)
MacOS Sequoia 15.4
iPhone 12 with 18.3.2 (22D82)
Am I doing something wrong or did I stumble upon a bug? I have a demo Xcode project ready but I could not upload it here so I put the code below.
Thanks for your help
typealias CurrentSchema = ItemSchemaV1
typealias ItemList = CurrentSchema.ItemList
typealias Item = CurrentSchema.Item
@main
struct SwiftDataMigrationApp: App {
var sharedModelContainer: ModelContainer = {
do {
return try ModelContainer(for: ItemList.self, migrationPlan: MigrationPlan.self)
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
This is the migration plan
enum MigrationPlan: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[ItemSchemaV1.self, ItemSchemaV2.self]
}
static var stages: [MigrationStage] = [
MigrationStage.custom(fromVersion: ItemSchemaV1.self, toVersion: ItemSchemaV2.self, willMigrate: { context in
print("Started migration")
let oldlistItems = try context.fetch(FetchDescriptor<ItemSchemaV1.ItemList>())
for list in oldlistItems {
let items = list.items.map { ItemSchemaV2.Item(timestamp: $0.timestamp)}
let newList = ItemSchemaV2.ItemList(items: items, name: list.name, note: "This is a new property")
context.insert(newList)
context.delete(list)
}
try context.save() // Crash indicated here
print("Finished willMigrate")
}, didMigrate: { context in
print("Did migrate successfully")
})
]
}
The versioned schemas
enum ItemSchemaV1: VersionedSchema {
static var versionIdentifier = Schema.Version(1, 0, 0)
static var models: [any PersistentModel.Type] {
[Item.self]
}
@Model
final class Item {
var timestamp: Date
var list: ItemSchemaV1.ItemList?
init(timestamp: Date) {
self.timestamp = timestamp
}
}
@Model
final class ItemList {
@Relationship(deleteRule: .cascade, inverse: \ItemSchemaV1.Item.list)
var items: [Item]
var name: String
init(items: [Item], name: String) {
self.items = items
self.name = name
}
}
}
enum ItemSchemaV2: VersionedSchema {
static var versionIdentifier = Schema.Version(2, 0, 0)
static var models: [any PersistentModel.Type] {
[Item.self]
}
@Model
final class Item {
var timestamp: Date
var list: ItemSchemaV2.ItemList?
init(timestamp: Date) {
self.timestamp = timestamp
}
}
@Model
final class ItemList {
@Relationship(deleteRule: .cascade, inverse: \ItemSchemaV2.Item.list)
var items: [Item]
var name: String
var note: String
init(items: [Item], name: String, note: String = "") {
self.items = items
self.name = name
self.note = note
}
}
}
Last the ContentView:
struct ContentView: View {
@Query private var itemLists: [ItemList]
var body: some View {
NavigationSplitView {
List {
ForEach(itemLists) { list in
NavigationLink {
List(list.items) { item in
Text(item.timestamp.formatted(date: .abbreviated, time: .complete))
}
.navigationTitle(list.name)
} label: {
Text(list.name)
}
}
}
.navigationTitle("Crashing migration demo")
.onAppear {
if itemLists.isEmpty {
for index in 0..<10 {
let items = [Item(timestamp: Date.now)]
let listItem = ItemList(items: items, name: "List No. \(index)")
modelContext.insert(listItem)
}
try! modelContext.save()
}
}
} detail: {
Text("Select an item")
}
}
}
Hello everyone,
I followed this (https://www.hackingwithswift.com/quick-start/swiftdata/how-to-sync-swiftdata-with-icloud) guide from Paul Hudson on how to sync swiftdata with iCloud. I tried it on my device directly and it worked exactly as I would expect. Now I tried the same version of the app on another device installed through TestFlight external tester group. It no longer works.
When deleting the app, the alert reads "Deleting this app will also delete its data, but any documents or data will be stored in iCloud will not be deleted" so the app should have said something in iCloud. When looking in Settings -> Your Name -> iCloud -> Manage Account Storage, on the working device I can see around 300 KB saved in iCloud, on the other device my app is not listed. Both have a fast and working internet connection, almost fully charged, low data mode turned off, running 17.4.1, Background modes enabled, Mobile data enabled, more than enough unused iCloud storage and plenty of time to sync.
I was streaming the logs from the Cloudkit dashboard but nothing appeared there. The data saved neither syncs to another device of the same apple id nor reappears after app removal.
The model Container is initialized without any configuration, the only relationship is optional and every value has a default value. There is A LOT of log noise when launching the app and I am unable to get any meaningful information from that. I can only get the log from the device where it is working as expected.
I have triple checked that it is exactly the same app version and no debug conditions anywhere. I have absolutely no idea what is causing this.
Thanks for any help :)
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
CloudKit
Cloud and Local Storage
SwiftData
For a kind of podcast player I need to periodically update a swiftData object to keep track of the listening progress. (Happy to hear if there are better ways) I need to do this in many places in my app so I wanted to extract the modelContext into a Singleton so I can write a global function that starts the timer.
In doing so I stumbled upon a problem: The memory used by my app is steadily increasing and the device is turning hot.
@Observable
class Helper {
static let shared = Helper()
var modelContext: ModelContext?
}
@main
struct SingletontestApp: App {
let modelContainer: ModelContainer
init() {
do {
modelContainer = try ModelContainer(
for: Item.self, Item.self
)
} catch {
fatalError("Could not initialize ModelContainer")
}
Helper.shared.modelContext = modelContainer.mainContext
}
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(modelContainer)
}
}
struct ContentView: View {
@Query private var items: [Item]
var body: some View {
NavigationSplitView {
List {
ForEach(items) { item in
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
}
}
.toolbar {
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
ToolbarItem {
Button(action: updateItemPeriodically) {
Label("Change random", systemImage: "dice")
}
}
}
} detail: {
Text("Select an item")
}
}
func addItem() {
withAnimation {
let newItem = Item(timestamp: Date())
Helper.shared.modelContext!.insert(newItem)
}
}
@MainActor
func updateItemPeriodically() { // Doesn't matter if run as global or local func
let descriptor = FetchDescriptor<Item>(sortBy: [SortDescriptor(\.timestamp)])
let results = (try? Helper.shared.modelContext?.fetch(descriptor)) ?? []
let element = results.randomElement()
let timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { timer in // Smaller time intervals worsen the problem
element?.timestamp = Date.now
}
}
}
Calling save() manually or automatically in the timer does not have any effect. I am not sure about my general way of keeping track of listening process so if you think there is a better way, feel free to correct me.
Thanks for your help
Using the hardware volume buttons on the iPhone, you have 16 steps you can adjust your volume to. I want to implement a volume control slider in my app. I am updating the value of the slider using AVAudioSession.sharedInstance().outputVolume. The problem is that this returns values rounded to the nearest 0 or 5. This makes the slider jump around. .formatted() is not causing this problem.
You can recreate the problem using code below.
@main
struct VolumeTestApp: App {
init() {
try? AVAudioSession.sharedInstance().setActive(true)
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@State private var volume = Double()
@State private var difference = Double()
var body: some View {
VStack {
Text("The volume changed by \(difference.formatted())")
Slider(value: $volume, in: 0...1)
}
.onReceive(AVAudioSession.sharedInstance().publisher(for: \.outputVolume), perform: { value in
volume = Double(value)
})
.onChange(of: volume) { oldValue, newValue in // Only used to make the problem more obvious
if oldValue > newValue {
difference = oldValue - newValue
} else {
difference = newValue - oldValue
}
}
}
}
Here is a video of the problem in action:
https://share.icloud.com/photos/00fmp7Vq1AkRetxcIP5EXeAZA
What am I doing wrong or what can I do to avoid this?
Thank you
I'm currently in the process of migrating to Swift 6. A lot of my code triggers the warning from the title. Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races. I depend on the .task/.refreshable modifiers and buttons that trigger asynchronous work that cannot be done on the Main Actor since it takes way to long.
The below code demonstrates the problem. Some comments explain my problems further. I read a lot of articles and documentations but couldn't find an answer to such a seemingly simple error
struct ContentView: View { // Marking Senable as suggested by the warning causes different warning for @State
@State private var authorizationStatus: MusicAuthorization.Status = .notDetermined // Sole purpose to trigger the errors
var body: some View {
VStack {
Text("Hello, world!")
Button("Some button") {
Task {
await doingSomeAsyncWork()
// WARNING: Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races
}
}
}
.task { // Or refreshable I believe both behave the same
await doingSomeAsyncWork()
// WARNING: Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races
}
}
// Marking @MainActor is not an option since some of these functions might be running for more than 10 seconds
// Tried marking func as nonisolated but that obviously had no effect
func doingSomeAsyncWork() async {
authorizationStatus = await MusicAuthorization.request() // Just to have a easy asynchronous function. Without some async code in here, the errors disappear
}
}
Thank you
When changing a property of a SwiftData Model from a ModelActor the memory needed slightly increases. Once you do that more often, you can see that the usage is linearly increasing. I modified the Swiftdata template as little as possible. This is the least code I need to reproduce the problem:
Changes In the @main struct :
ContentView(modelContainer: sharedModelContainer)
ContentView:
struct ContentView: View {
@Query private var items: [Item]
let dataHanndler: DataHandler
@State var timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { t in })
var body: some View {
NavigationSplitView {
List {
ForEach(items) { item in
NavigationLink {
Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
} label: {
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
}
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
ToolbarItem {
Button {
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { t in
Task {
await dataHanndler.updateRandom()
// Obviously this makes little sense but I need to update a lot of entities in my actual app. This is the simplest way to demonstrate that. updateRandom() could also be a function of a view but that doesn't make a difference
}
}
} label: {
Label("Do a lot of writing", systemImage: "gauge.with.dots.needle.100percent")
}
}
ToolbarItem {
Button {
timer.invalidate()
} label: {
Label("Invalidate", systemImage: "stop.circle")
}
}
}
} detail: {
Text("Select an item")
}
}
private func addItem() {
Task {
await dataHanndler.insert(timestamp: Date.now)
}
}
init(modelContainer: ModelContainer) {
self.dataHanndler = DataHandler(modelContainer: modelContainer)
}
}
ModelActor:
@ModelActor
actor DataHandler {
public func update<T>(_ persistentIdentifier: PersistentIdentifier, keypath: ReferenceWritableKeyPath<Item, T>, to value: T) throws {
let model = modelContext.model(for: persistentIdentifier) as! Item
model[keyPath: keypath] = value
}
public func insert(timestamp: Date) {
let item = Item(timestamp: timestamp)
modelContext.insert(item)
}
public func updateRandom() {
let count = try! modelContext.fetchCount(FetchDescriptor<Item>())
var descriptor = FetchDescriptor<Item>()
descriptor.fetchOffset = Int.random(in: 0..<count)
descriptor.fetchLimit = 1
let model = try! modelContext.fetch(descriptor)
model.first!.timestamp = Date.now
}
}
I filed a bug report FB14876920 but I am looking for other ideas to solve this before it will be fixed in a future update. The modelContext I use is created and managed by the @ModelActor macro.
Happy to hear ideas
I want to switch from using print statements to using OSLog because of the filtering options and so on. I am using MusicKit. To mute all the log noise mostly coming from CoreData I pass these arguments on launch:
-com.apple.CoreData.SQLDebug 0
-com.apple.CoreData.MigrationDebug 0
-com.apple.CoreData.ConcurrencyDebug 0
-com.apple.CoreData.CloudKitDebug 0
-com.apple.CoreData.Logging.stderr 0
This works for all the Core Data related warnings but I also need such an argument for MusicKit. Setting the environment variable OS_ACTIVITY_MODE to disable hides all the noise but also hides the log statements I sent via Logger().debug() for example.
In particular these log messages appear in great quantities.
Attempted to register account monitor for types client is not authorized to access: {(
"com.apple.account.iTunesStore"
)}
<ICMonitoredAccountStore: 0x303c5c9f0> Failed to register for account monitoring. err=Error Domain=com.apple.accounts Code=7 "(null)"
My application works fine and these log messages mean absolutely nothing to me. These two threads mention a similar problem but can't offer a solution.
https://forums.developer.apple.com/forums/thread/720835
https://forums.developer.apple.com/forums/thread/743795
Thank you
Songs can be unavailable (greyed out) in Apple Music. How can I check if a song is unavailable via the MusicKit framework? Obviously the playback will fail with MPMusicPlayerControllerErrorDomain Code=6 "Failed to prepare to play" but how can I know that in advance? I need to check the availability of hundreds of albums and therefore initiating a playback for each of them is not an option.
Things I have tried:
Checking if the release date property is set to a future date. This filters out all future releases but doesn't solve the problem for already released songs.
Checking if the duration is 0. This does not work since the duration of unavailable songs does not have to be 0.
Initiating a playback and checking for the "Failed to prepare to play" error. This is not suitable for a huge amount of Albums.
I couldn't find a solution yet but somehow other third-party-apps are able ignore/don't shows these albums. I believe the Apple Music app is only displaying albums where at least one song is available.
I am using this function to fetch all albums of an artist.
private func fetchAlbumsFor(_ artist: Artist) async throws -> [Album] {
let artistWithAlbums = try await artist.with(.albums)
var allAlbums = [Album]()
guard var currentBadge = artistWithAlbums.albums else {
return []
}
allAlbums.append(contentsOf: currentBadge)
while currentBadge.hasNextBatch {
if let nextBatch = try await currentBadge.nextBatch() {
currentBadge = nextBatch
allAlbums.append(contentsOf: nextBatch)
} else {
break
}
}
return allAlbums
}
Here is an example album where I am unable to detect its unavailability (at least in Germany):
https://music.apple.com/de/album/die-haferhorde-immer-den-n%C3%BCstern-nach-h%C3%B6rspiel-zu-band-3/1755774804
Furthermore I was unable to navigate to this album via the Apple Music app directly.
Thanks for any help
Edit: Apparently this album is not included in an apple music subscription but can be bought seperately. The question remains: How can I check that?
I am seeing a really weird behavior with Live Activities. The Live Activity is always appearing on the simulator. However the Live Activity is only appearing on my physical device when there is no other widget in the widget bundle shown below.
@main
struct HoerspielWidgetsBundle: WidgetBundle {
var body: some Widget {
// Uncomment the line below and the Live Activity will no longer appear
// UpNextWidget()
PlaybackLiveActivity()
}
}
Annotating that var with @WidgetBundle has no effect.
There are no logs indicating an error, the function to request a Live Activity does not throw and the status of the activity is active.
Both the widget and the Live Activity are working fine otherwise. NSSupportsLiveActivities is set to true in the correct Info.plist file. I am not running any beta software and the physical iPhone is on the newest version (iOS 18.5). Using the template when adding a new target in Xcode, I was able to set up a similar app where the Live Activity works as expected.
I am really at a loss here which additional information I should provide or how this issue can be resolved.
Thank you for your help.
I want to load images from my bundle, which works fine when running the main app. However this does not work when running UI Tests. I read that the test bundle is not the main bundle when running tests. I try loading the bundle via this snippet:
let bundle = Bundle(for: Frames_HoerspielUITests.self)
This is my test class wrapped these the canImport statements so it can be added to the main app target and used for getting the correct bundle:
#if canImport(XCTest)
import XCTest
final class Frames_HoerspielUITests: XCTestCase {
override func setUpWithError() throws {
continueAfterFailure = false
}
override func tearDownWithError() throws { }
@MainActor
func testExample() throws {
let app = XCUIApplication()
app.launch()
}
@MainActor
func testLaunchPerformance() throws {
measure(metrics: [XCTApplicationLaunchMetric()]) {
XCUIApplication().launch()
}
}
}
#else
final class Frames_HoerspielUITests { }
#endif
However while this works when running the main app, it still fails in the UI tests. It is a SwiftUI only app. and I can't add the images to the asset catalog because they are referenced from another location.
Any ideas? Thank you