I'm facing a weird issue with SwiftData. I want to have one database that's local to the device and one that syncs to iCloud. In this example, LTRLink should be synced via iCloud while LTRMetadata should stay on-device only. I've it configured like the following:
let schema = Schema([LTRLink.self, LTRMetadata.self])
let cloudkitConfiguration = ModelConfiguration("Remote",
schema: schema,
url: FileManager.remoteDatabaseFolderURL.appending(path: "Remote.sqlite"),
cloudKitDatabase: .private("iCloud.com.xavimoll.abyss3"))
let localConfiguration = ModelConfiguration("Local",
schema: schema,
url: FileManager.localDatabaseFolderURL.appending(path: "Local.sqlite"),
cloudKitDatabase: .none)
return try ModelContainer(for: schema,
configurations: [cloudkitConfiguration, localConfiguration])
For some reason, when I create the iCloud schema, both models end up appearing as records on iCloud. I create the schema like this:
let schema = Schema([LTRLink.self, LTRMetadata.self])
let cloudkitConfiguration = ModelConfiguration("Remote",
schema: schema,
url: FileManager.remoteDatabaseFolderURL.appending(path: "Remote.sqlite"),
cloudKitDatabase: .private("iCloud.com.xavimoll.abyss3"))
#if DEBUG
// Needed to create the schema on iCloud
try autoreleasepool {
let desc = NSPersistentStoreDescription(url: cloudkitConfiguration.url)
let opts = NSPersistentCloudKitContainerOptions(containerIdentifier: cloudkitConfiguration.cloudKitContainerIdentifier!)
desc.cloudKitContainerOptions = opts
desc.shouldAddStoreAsynchronously = false
if let mom = NSManagedObjectModel.makeManagedObjectModel(for: [LTRLink.self]) {
let container = NSPersistentCloudKitContainer(name: "Remote", managedObjectModel: mom)
container.persistentStoreDescriptions = [desc]
container.loadPersistentStores {_, err in
if let err {
fatalError(err.localizedDescription)
}
}
try container.initializeCloudKitSchema()
if let store = container.persistentStoreCoordinator.persistentStores.first {
try container.persistentStoreCoordinator.remove(store)
}
}
}
#endif
let localConfiguration = ModelConfiguration("Local",
schema: schema,
url: FileManager.localDatabaseFolderURL.appending(path: "Local.sqlite"),
cloudKitDatabase: .none)
return try ModelContainer(for: schema,
configurations: [cloudkitConfiguration, localConfiguration])
The logic to initialize the CloudKit schema follows the documentation found here: https://developer.apple.com/documentation/swiftdata/syncing-model-data-across-a-persons-devices#Initialize-the-CloudKit-development-schema
It looks like setting cloudKitDatabase: .none on the init for the ModelConfiguration doesn't do anything, and ends up being synced with iCloud either way. When I go to the iCloud console, I see the following:
Does anyone know if there's any workaround that would allow me to have two databases where only one of them syncs to iCloud when using SwiftData?
Post
Replies
Boosts
Views
Activity
Hello, I've a question about performance when trying to render lots of items coming from SwiftData via a @Query on a SwiftUI List. Here's my setup:
// Item.swift:
@Model final class Item: Identifiable {
var timestamp: Date
var isOptionA: Bool
init() {
self.timestamp = Date()
self.isOptionA = Bool.random()
}
}
// Menu.swift
enum Menu: String, CaseIterable, Hashable, Identifiable {
var id: String { rawValue }
case optionA
case optionB
case all
var predicate: Predicate<Item> {
switch self {
case .optionA: return #Predicate { $0.isOptionA }
case .optionB: return #Predicate { !$0.isOptionA }
case .all: return #Predicate { _ in true }
}
}
}
// SlowData.swift
@main
struct SlowDataApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([Item.self])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
return try! ModelContainer(for: schema, configurations: [modelConfiguration])
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
// ContentView.swift
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@State var selection: Menu? = .optionA
var body: some View {
NavigationSplitView {
List(Menu.allCases, selection: $selection) { menu in
Text(menu.rawValue).tag(menu)
}
} detail: {
DemoListView(selectedMenu: $selection)
}.onAppear {
// Do this just once
// (0..<15_000).forEach { index in
// let item = Item()
// modelContext.insert(item)
// }
}
}
}
// DemoListView.swift
struct DemoListView: View {
@Binding var selectedMenu: Menu?
@Query private var items: [Item]
init(selectedMenu: Binding<Menu?>) {
self._selectedMenu = selectedMenu
self._items = Query(filter: selectedMenu.wrappedValue?.predicate,
sort: \.timestamp)
}
var body: some View {
// Option 1: touching `items` = slow!
List(items) { item in
Text(item.timestamp.description)
}
// Option 2: Not touching `items` = fast!
// List {
// Text("Not accessing `items` here")
// }
.navigationTitle(selectedMenu?.rawValue ?? "N/A")
}
}
When I use Option 1 on DemoListView, there's a noticeable delay on the navigation. If I use Option 2, there's none. This happens both on Debug builds and Release builds, just FYI because on Xcode 16 Debug builds seem to be slower than expected: https://indieweb.social/@curtclifton/113273571392595819
I've profiled it and the SwiftData fetches seem blazing fast, the Hang occurs when accessing the items property from the List. Is there anything I'm overlooking or it's just as fast as it can be right now?
I've just updated to Xcode 15.3 and iOS 17.4 (simulator). Every time I launch the app, I see a CPU spike keeping the CPU at 100% for about 30 seconds on a background thread. After those 30 seconds, there's a 'Thread Performance Checker' error posted on the console.
This does not happen when using Xcode 15.2 and running on iOS 17.2. or iOS 16.4.
Thread Performance Checker: Thread running at User-initiated quality-of-service class waiting on a thread without a QoS class specified (base priority 33). Investigate ways to avoid priority inversions
PID: 70633, TID: 2132693
Backtrace
=================================================================
3 CFNetwork 0x000000018454094c estimatedPropertyListSize + 28648
4 CFNetwork 0x00000001843d7fc0 cfnTranslateCFError + 1864
5 libdispatch.dylib 0x000000010557173c _dispatch_client_callout + 16
6 libdispatch.dylib 0x0000000105573210 _dispatch_once_callout + 84
7 CFNetwork 0x00000001843d7f8c cfnTranslateCFError + 1812
8 CFNetwork 0x0000000184540814 estimatedPropertyListSize + 28336
9 libdispatch.dylib 0x000000010557173c _dispatch_client_callout + 16
10 libdispatch.dylib 0x0000000105573210 _dispatch_once_callout + 84
11 CFNetwork 0x0000000184540728 estimatedPropertyListSize + 28100
12 CFNetwork 0x0000000184540794 estimatedPropertyListSize + 28208
13 libdispatch.dylib 0x000000010557173c _dispatch_client_callout + 16
14 libdispatch.dylib 0x0000000105573210 _dispatch_once_callout + 84
15 CFNetwork 0x0000000184540780 estimatedPropertyListSize + 28188
16 CFNetwork 0x00000001844e8664 _CFNetworkHTTPConnectionCacheSetLimit + 191584
17 CFNetwork 0x00000001844e78dc _CFNetworkHTTPConnectionCacheSetLimit + 188120
18 CFNetwork 0x000000018439ce5c _CFURLCachePersistMemoryToDiskNow + 25460
19 CFNetwork 0x0000000184483068 _CFStreamErrorFromCFError + 609680
20 CFNetwork 0x000000018445105c _CFStreamErrorFromCFError + 404868
21 CFNetwork 0x000000018443a040 _CFStreamErrorFromCFError + 310632
22 CFNetwork 0x000000018453be14 estimatedPropertyListSize + 9392
23 CFNetwork 0x000000018440fa5c _CFStreamErrorFromCFError + 137092
26 CFNetwork 0x000000018445b398 _CFStreamErrorFromCFError + 446656
27 CFNetwork 0x0000000184459db8 _CFStreamErrorFromCFError + 441056
28 CFNetwork 0x000000018445cf60 _CFStreamErrorFromCFError + 453768
29 CFNetwork 0x0000000184541838 estimatedPropertyListSize + 32468
30 libdispatch.dylib 0x000000010556fec4 _dispatch_call_block_and_release + 24
31 libdispatch.dylib 0x000000010557173c _dispatch_client_callout + 16
32 libdispatch.dylib 0x0000000105579a30 _dispatch_lane_serial_drain + 916
33 libdispatch.dylib 0x000000010557a774 _dispatch_lane_invoke + 420
34 libdispatch.dylib 0x000000010557b6e4 _dispatch_workloop_invoke + 864
35 libdispatch.dylib 0x00000001055871a8 _dispatch_root_queue_drain_deferred_wlh + 324
36 libdispatch.dylib 0x0000000105586604 _dispatch_workloop_worker_thread + 488
37 libsystem_pthread.dylib 0x0000000106b87924 _pthread_wqthread + 284
38 libsystem_pthread.dylib 0x0000000106b866e4 start_wqthread + 8
If you have configured your workflows to use 'Latest Release', and there's a Release Candidate available, Xcode Cloud decides to use it.
The problem is that the App Store rejects builds submitted with Release Candidate builds, at least that's what I'm encountering with Xcode 15.3 on the 27th of February, 2024:
This is the error:
Unsupported SDK or Xcode version. Your app was built with an SDK or version of Xcode that isn’t supported. Although you can use beta versions of SDKs and Xcode to build and upload apps to App Store Connect, you need to use the latest Release Candidates (RC) for SDKs and Xcode to submit the app. For details on currently supported SDKs and versions of Xcode, visit: https://developer.apple.com/news/releases.
I'm not really sure if the issue is on Xcode Cloud or on the App Store, but something's up and they don't like each other right now!
Recently Xcode Cloud has stopped showing new branches on the branch picker. For example, I still see our main branch on the list, but branches that I pushed recently do not appear when trying to generate a manual build.
We have another app where none of the branches appear, and the same app (with a different bundle ID we use for Production, they all appear except for the new ones).
The GitHub integration seems fine since when PRs are merged to main, all workflows that listen to changes to main work fine, and on the Settings I can see that the last access to the GitHub repository is from a few minutes ago when pushing new things.
The same issue happens on the integration of Xcode Cloud inside Xcode, none of the new branches is listed there.
Looks like the issue is on whatever lists the branches available. Has anyone noticed this?
For the past few days we've been observing a degraded performance on Xcode Cloud. Some builds get queued for hours and never start. I just cancelled one that's been queued for an hour and a half:
Is this a known issue?
We've been running Xcode Cloud smoothly for the last few months, and everything's been great. Yesterday everything was fine, but builds triggered today, start failing. Since last night to today there's been no changes in the project, but we're getting this:
Invalid Provisioning Profile. The provisioning profile included in the bundle fm.here.ios.dev [Payload/Here.app] is invalid. [Missing code-signing certificate]. A Distribution Provisioning profile should be used when submitting apps to the App Store. For more information, visit the iOS Developer Portal.
Not sure why out of the blue the provisioning profile is missing the code-signing certificate. Everything's automatically managed by Xcode, so I'm not sure what has changed. We get it for our fm.here.ios.dev app and for the regular fm.here.ios one, so not isolated to a single one, seems to be happening to all of them.
I can't see anything expired on the developer portal, has there been a deploy of Xcode Cloud / App Store Connect that could trigger this?
Since a couple of days ago, the tab for Xcode Cloud on App Store Connect never ends up loading. The console seems to log some errors about the ci, so I'd assume something's broken? Works fine from Xcode though, and the builds do go though, might be just a Javascript rendering issue.
We've recently (since yesterday) have been experiencing an issue where builds submitted to TestFlight via Xcode Cloud get queued for ~3 hours.
Here's an example:
The build itself takes ~20 mins:
Is anyone experiencing such issue?
We've started hitting this limitation when submitting builds using Xcode Cloud.
ITMS-90382: Upload limit reached - The upload limit for your application has been reached. Please wait 1 day and try again.
We generate TestFlight builds for every PR (builds from PR get sent to QA & devs) & for every merge (builds get sent to everybody in the team). Is there any way to know what's the limit so we can try to work around it?
Edit: I've just checked, and TestFlight only reports 19 builds that are expiring in 90 days (aka were uploaded within the last 24h). Is the limit that low?
Since last night we've been seeing this error on every build:
The Build - iOS action could not complete due to an error. Something went wrong and the Xcode Cloud team has been notified to investigate. The error may not occur on rebuild.
Is there anything that we can do? Every build fails now.
Thanks.
I'm facing a weird alignment issue with a floating menu when the keyboard appears and I've no idea if there's a workaround. To reproduce the issue, simply copy and paste this code:
struct ContentView: View {
@State var searchQuery = ""
var customToolbarButton: some View {
VStack {
Text("Example").font(.footnote)
Image(systemName: "arrowtriangle.down.fill").imageScale(.small)
}.foregroundColor(.accentColor)
}
var body: some View {
NavigationView {
Rectangle().fill(.red)
.safeAreaInset(edge: .bottom) {
HStack(alignment: .center) {
customToolbarButton
Spacer()
Menu { } label: {
customToolbarButton
}
}
.frame(height: 52)
.padding(.horizontal)
.background(Color.white)
.clipShape(Capsule(style: .continuous))
}
}.searchable(text: $searchQuery)
}
}
When the keyboard appears and moves the HStack up, the views that are a Menu are wrongly placed, all other views seem fine. Any idea if there's a fix?
Video to illustrate the issue: https://twitter.com/xmollv/status/1616851571832229889
I'm facing a weird issue with contextMenu(forSelectionType:menu:primaryAction:) attached to a List. It works fine if you enable edit mode, and start selecting the rows by tapping, but if you have a button that what it does is manually modify the selection, the returned rows when the contextMenu is invoked is incorrect.
Furthermore, if you use the select all button, but actually scroll to the bottom of the list, the returned values is correct, so it seems that unless the cell is rendered, the contextMenu won't return it.
Does anybody know if I'm doing something wrong? Here's a quick example to reproduce the issue:
struct ContentView: View {
let rows = (0..<100).map{ "Row: \($0)" }
@State var selection: Set<String> = []
var body: some View {
List(selection: $selection) {
ForEach(rows, id: \.self) { row in
Text(row).tag(row)
}
}.contextMenu(forSelectionType: String.self) { contextMenuRows in
Button("Number of rows in the contextMenu: \(contextMenuRows.count)") {}
}.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
if selection.isEmpty {
Button("Select All") { selection = Set(rows) }
} else {
Button("Deselect All") { selection = [] }
}
}
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
}
}
}
Make sure to embed the ContentView inside a NavigationView to be able to see the navigation bar.
Video demo showing the issue: https://imgur.com/a/fxKk5Cs
Works fine when selecting manually
When selecting all only displays the first 9 rows
After scrolling, all rows are available to the contextMenu
I've been working on a macOS app using pure SwiftUI, and I've found a strange behavior that I've no idea how to solve. If you have enabled the System Preferences > Dock & Menu Bar > Minimize windows into application icon flag, when you minimize the window it never launches again when clicking the app icon on the dock. This does not happen with an AppKit application.
The issue can be seen here (video + 2 sample projects): https://github.com/xmollv/macOSMinimizeIssueOnSwiftUI
Literally they're empty apps, just created them using Xcode's assistant (the SwiftUI one has the steps to repro the issue in the UI). The only solution that I found to launch the SwiftUI one is rick clicking the app icon, and then selecting the window, but of course nobody expects that.
My question is: is there any way launch a minimized SwiftUI app when clicking the dock icon?
I'm observing a weird issue with SwiftUI Lists on macOS (they do work as expected on iOS). The problem is that the List calls the init & body of every row, even if those rows are not on screen (and might never be shown).
If I replace the List with a ScrollView + LazyVStack, it does work as expected (only those rows which are going to be rendered get their init & body called). Of course, this is is not an ideal workaround because you loose the built-in benefits of using a List (mainly selection in my case).
I did expect that under the hood, SwiftUI would use the same mechanism as NSTableView (which loads cells on demand). Historically I'm an iOS dev, so I'm used to cellForRowAtIndexPath coming from UITableView.
Here's a quick gist demonstrating the issue:
import SwiftUI
@main
struct SwiftUIListVSLazyVStackApp: App {
let numbers = (0...100).map { $0 }
var body: some Scene {
WindowGroup {
/*
List calls the init & the body of *every* element on the list, even if it's not being displayed.
This is unexpected because a tableView usually only loads the visible cells as needed (cellForRowAtIndexPath)
*/
List(numbers) { number in
RowView(for: number, example: "list")
}
/*
A combination of ScrollView + LazyVStack achieves what's expected from the list. Only calls the init & body of
the element that's going to be displayed.
*/
// ScrollView {
// LazyVStack(alignment: .leading, spacing: 8) {
// ForEach(numbers) { number in
// RowView(for: number, example: "stack")
// }
// }
// }
}
}
}
struct RowView: View {
private let number: Int
private let example: String
init(for number: Int, example: String) {
print("Init \(example): \(number)")
self.number = number
self.example = example
}
var body: some View {
let _ = print("Body \(example): \(number)")
Text("\(number)")
.onAppear{ print("Appear \(example): \(number)") }
}
}
extension Int: Identifiable {
public var id: Int { self }
}
GitHub gist: https://gist.github.com/xmollv/7ecc97d8118c100e85698c5ff09a20dc
And a video to better show the issue if you can't run the code:
https://gist.github.com/xmollv/7ecc97d8118c100e85698c5ff09a20dc?permalink_comment_id=4140623#gistcomment-4140623
Twitter thread: https://twitter.com/xmollv/status/1517158777882955779
Any help is very much appreciated!