I am trying to extend my PersistedModels like so:
@Versioned(3)
@Model
class MyType {
var name: String
init() { name = "hello" }
}
but it seems that SwiftData's@Model macro is unable to read the properties added by my @Versioned macro. I have tried changing the order and it ignores them regardless. version is not added to schemaMetadata and version needs to be persisted. I was planning on using this approach to add multiple capabilities to my model types. Is this possible to do with macros?
VersionedMacro
/// A macro that automatically implements VersionedModel protocol
public struct VersionedMacro: MemberMacro, ExtensionMacro {
// Member macro to add the stored property directly to the type
public static func expansion(
of node: AttributeSyntax,
providingMembersOf declaration: some DeclGroupSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
guard let argumentList = node.arguments?.as(LabeledExprListSyntax.self),
let firstArgument = argumentList.first?.expression else {
throw MacroExpansionErrorMessage("@Versioned requires a version number, e.g. @Versioned(3)")
}
let versionValue = firstArgument.description.trimmingCharacters(in: .whitespaces)
// Add the stored property with the version value
return [
"public private(set) var version: Int = \(raw: versionValue)"
]
}
// Extension macro to add static property
public static func expansion(
of node: SwiftSyntax.AttributeSyntax,
attachedTo declaration: some SwiftSyntax.DeclGroupSyntax,
providingExtensionsOf type: some SwiftSyntax.TypeSyntaxProtocol,
conformingTo protocols: [SwiftSyntax.TypeSyntax],
in context: some SwiftSyntaxMacros.MacroExpansionContext
) throws -> [SwiftSyntax.ExtensionDeclSyntax] {
guard let argumentList = node.arguments?.as(LabeledExprListSyntax.self),
let firstArgument = argumentList.first?.expression else {
throw MacroExpansionErrorMessage("@Versioned requires a version number, e.g. @Versioned(3)")
}
let versionValue = firstArgument.description.trimmingCharacters(in: .whitespaces)
// We need to explicitly add the conformance in the extension
let ext = try ExtensionDeclSyntax("extension \(type): VersionedModel {}")
.with(\.memberBlock.members, MemberBlockItemListSyntax {
MemberBlockItemSyntax(decl: DeclSyntax(
"public static var version: Int { \(raw: versionValue) }"
))
})
return [ext]
}
}
VersionedModel
public protocol VersionedModel: PersistentModel {
/// The version of this particular instance
var version: Int { get }
/// The type's current version
static var version: Int { get }
}
Macro Expansion:
iCloud & Data
RSS for tagLearn how to integrate your app with iCloud and data frameworks for effective data storage
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
CloudKit CKRecordZone Deletion Issue
Problem: CloudKit record zones deleted via CKDatabase.modifyRecordZones(deleting:) or CKModifyRecordZonesOperation are successfully
removed but then reappear. I suspect they are automatically reinstated by CloudKit sync, despite successful deletion confirmation.
Environment:
SwiftData with CloudKit integration
Custom CloudKit zones created for legacy zone-based sharing
Observed Behavior:
Create custom zone (e.g., "TestZone1") via CKDatabase.modifyRecordZones(saving:)
Copy records to zone for sharing purposes
Delete zone using any CloudKit deletion API - returns success, no errors
Immediate verification: Zone is gone from database.allRecordZones()
After SwiftData/CloudKit sync or app restart: Zone reappears
Reproduction:
Tested with three different deletion methods - all exhibit same behaviour:
modifyRecordZones(deleting:) async API
CKModifyRecordZonesOperation (fire-and-forget)
CKModifyRecordZonesOperation with result callbacks
Zone deletion succeeds, change tokens (used to track updates to shared records) cleaned up
But zones are restored presumably by CloudKit background sync
Expected: Deleted zones should remain deleted
Actual: Zones are reinstated, creating orphaned zones
I have an app which uses ubiquitous containers and files in them to share data between devices. It's a bit unusual in that it indexes files in directories the user grants access to, which may or may not exist on a second device - those files are identified by SHA-1 hash. So a second device scanning before iCloud data has fully sync'd can create duplicate references which lead to an unpleasant user experience.
To solve this, I store a small binary index in the root of the ubiquitous file container of the shared data, containing all of the known hashes, and as the user proceeds through the onboarding process, a background thread is attempting to "prime" the ubiquitous container by calling FileManager.default.startDownloadingUbiquitousItemAt() for each expected folder and file in a sane order.
This likely creates a situation not anticipated by the iOS/iCloud integration's design, as it means my app has a sort of precognition of files it should not yet know about.
In the common case, it works, but there is a corner case where iCloud sync has just begun, and very, very little metadata is available (the common case, however, in an emulator), in which two issues come up:
I/O may hang indefinitely, trying to read a file as it is arriving. This one I can work around by running the I/O in a thread created with the POSIX pthread_create and using pthread_cancel to kill it after a timeout.
Attempts to call FileManager.default.startDownloadingUbiquitousItemAt() fails with an error Error Domain=NSCocoaErrorDomain Code=257 "The file couldn’t be opened because you don’t have permission to view it.". The permissions aspect of it is nonsense, but I can believe there's no applicable "sort of exists, sort of doesn't" error code to use and someone punted. The problem is that this same error will be thrown on any attempt to access that file for the life of the application - a restart is required to make it usable.
Clearly, the error or the hallucinated permission failure is cached somewhere in the bowels of iOS's FileManager. I was hoping startAccessingSecurityScopedResource() would allow me to bypass such a cache, as it does with URL.resourceValues() returning stale file sizes and last modified times. But it does not.
Is there some way to clear this state without popping up a UI with an Exit button (not exactly the desired iOS user experience)?
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
Foundation
Files and Storage
iOS
iCloud Drive
I am trying to save to cloud kit shared database. The shared database does not allow zones to be set up.
How do I save to sharedCloudDatabase without a zone?
private func addItem(recordType: String, name: String) {
let record = CKRecord(recordType: recordType)
record[Constances.field.name] = name as CKRecordValue
record[Constances.field.done] = false as CKRecordValue
record[Constances.field.priority] = 0 as CKRecordValue
CKContainer.default().sharedCloudDatabase.save(record) { [weak self] returnRecord, error in
if let error = error {
print("Error saving record: \(record[Constances.field.name] as? String ?? "No Name"): \n \(error)")
return
}
}
}
The following error message prints out:
Error saving record: Milk:
<CKError 0x15af87900: "Server Rejected Request" (15/2027); server message = "Default zone is not accessible in shared DB"; op = B085F7BA703D4A08; uuid = 87AEFB09-4386-4E43-81D7-971AAE8BA9E0; container ID = "iCloud.com.sfw-consulting.Family-List">
Hi everyone,
I am experiencing an iCloud provisioning problem I cannot resolve, and Developer Support has not been able to help.
My App ID:
com.exaqservices.ArkyvTiles
Symptoms:
1. In Xcode (v16.2), enabling iCloud in Signing & Capabilities repeatedly fails with:
The app ID does not include the iCloud container. Click Try Again.
Clicking Try Again does nothing. The error persists forever.
2. In Certificates, Identifiers & Profiles:
• The iCloud capability is enabled for this App ID.
• The CloudKit container is selected.
• But the portal no longer shows the “iCloud Documents” checkbox, which used to be required for ubiquitous document support.
3. Xcode cannot regenerate provisioning profiles because it claims the App ID is missing the iCloud container — even though the container is attached.
4. Provisioning profiles on the Apple Developer site all appear expired, and new ones do not generate correctly.
5. The App Store Connect interface also does not show an iCloud Services section under App Information → Capabilities as older guides describe.
Expected Behavior:
Since iCloud and the CloudKit container are enabled on the App ID, Xcode should successfully enable:
• com.apple.developer.icloud-services
• com.apple.developer.icloud-container-identifiers
• com.apple.developer.ubiquity-container-identifiers (if needed)
• com.apple.developer.ubiquity-kvstore-identifier
Instead, the entitlements never propagate.
What I suspect:
This seems like an App ID metadata mismatch or a stale backend entry where:
• the CloudKit container is attached but the entitlement isn’t linked,
• the “iCloud Documents” flag is missing due to a UI transition,
• provisioning profiles cannot be regenerated because the App ID is not updating correctly.
What I need help with:
Can someone from Apple engineering confirm:
• Whether my App ID metadata is corrupted,
• If entitlements need to be manually refreshed,
• Or if the “iCloud Documents” toggle has moved or is no longer exposed?
This is blocking development completely — I cannot build, sign, or deploy the app with iCloud.
Thank you!
Alan Metzger
Hi,
I am implementing a premium feature in my app where CloudKit syncing is available only for "Pro" users.
The Workflow:
Free Users: I initialize the ModelContainer with cloudKitDatabase: .none so their data stays local.
Pro Upgrade: When a user purchases a subscription, I restart the container with cloudKitDatabase: .automatic to enable syncing.
The Problem:
If a user starts as "Free" (creates local data) and later upgrades to "Pro", the app crashes immediately upon launch with the following error:
Fatal error: Failed to create ModelContainer: SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer, _explanation: nil)
It seems that SwiftData fails to load the existing data once the configuration changes to expect a CloudKit-backed store.
My Question:
Is there a supported way to "toggle" CloudKit on for an existing local dataset without causing this crash? I want the user's existing local data to start syncing once they pay, but currently, it just crashes.
My code:
import Foundation
import SwiftData
public enum DataModelEnum: String {
case task, calendar
public static let container: ModelContainer = {
let isSyncEnabled = UserDefaults.isProUser
let config = ModelConfiguration(
groupContainer: .identifier("group.com.yourcompany.myApp"),
cloudKitDatabase: isSyncEnabled ? .automatic : .none
)
do {
return try ModelContainer(for: TaskModel.self, CalendarModel.self, configurations: config)
} catch {
fatalError("Failed to create ModelContainer: \(error)")
}
}()
}
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
CloudKit
Cloud and Local Storage
SwiftData
I have some code which handles doing some computation on a background thread before updating Core Data NSManagedObjects by using the NSManagedObjectContext.perform functions.
This code is covered in Sendable warnings in Xcode 26 (beta 6) because my NSManagedObject subclasses (autogenerated) are non-Sendable and NSManagedObjectContext.perform function takes a Sendable closure.
But I can't really figure out what I should be doing. I realize this pattern is non-ideal for Swift concurrency, but it's what Core Data demands AFAIK. How do I deal with this?
let moc = object.managedObjectContext!
try await moc.perform {
object.completed = true // Capture of 'object' with non-Sendable type 'MySpecialObject' in a '@Sendable' closure
try moc.save()
}
Thanks in advance for your help!
Hi,
I'm considering using the new SwiftData class inheritance for a new app I'm building. I have a few questions:
Is it working well enough for production?
I have a number of different object types in my app. Some of them are very similar, and there's always a balance to be struck when it comes to splitting them into different types using class inheritance. Are there some good advice on when to use multiple classes instead of squeezing my object types into a single class?
Is there advice against using class inheritance in multiple levels (3-4)?
Claes
I have tried to set up iCloud sync. Despite fully isolating and resetting my development environment, the app fails with:
NSCocoaErrorDomain Code=134060 (PersistentStoreIncompatibleVersionHashError)
What I’ve done:
Created a brand new CloudKit container
Created a new bundle ID and app target
Renamed the Core Data model file itself
Set a new model version
Used a new .sqlite store path
Created a new .entitlements file with the correct container ID
Verified that the CloudKit dashboard shows no records
Deleted and reinstalled the app on a real device
Also tested with “Automatically manage signing” and without
Despite this, the error persists. I am very inexperienced and am not sure what my next step is to even attempt to fix this. Any guidance is apprecitated.
Running Tahoe 26.1 in a virtual machine, I can't sign into my Apple account. There is an error message saying "Could not communicate with the server." Internet access otherwise seems to be working in the VM. I tried both UTM and VirtualBuddy. Is this supposed to work?
I have an app that I signed and distribute between some internal testflight users. Potentially I want to invite some 'Public' beta testers which don't need to validate (_World have read rights in the public database)
Question: Do I need to have a working public CloudKit , when users are invited through TestFlight, or are they going to test on the development container?
I understand that when I invite beta-tester without authorization (external testers) they cannot access the developer container, so therefore I need to have the production CloudKit container up and running.
I have tried to populate the public production container, but for whatever reason my upload app still goes to the development container. I have archived the app, and tried, but no luck. I let xcode manage my certificates/profiles. but what do I need to change to be able to use my upload file to upload the production container, instead of the development.
I tried:
init() {
container = CKContainer(identifier: "iCloud.com.xxxx.xxxx")
publicDB = container.publicCloudDatabase
I got no error in the console, but data is always populated to the development database, instead the production.
I tried to create a provisioning profile, but for some reason Xcode doesn't like it. Tried to create one a different provisioning profile manual through the developer portal, for the app. but xcode doesn't want to use that, and mentions that the requirement are already in place.
What can I check/do to solve this.
If Cloudkit is enabled, SwiftData @Query operation hangs when the View scenePhase becomes active.
Seems like the more @Query calls you have, the more it hangs.
This has been first documented some time ago, but in typical Apple style, it has not been addressed or even commented on.
https://developer.apple.com/forums/thread/761434
What is the best way to switch between Core Data Persistent Stores?
My use case is that I have a multi-user app that stores thousands of data items unique to each user. To me, having Persistent Stores for each user seems like the best design to keep their data separate and private. (If anyone believes that storing the data for all users in one Persistent Store is a better design, I'd appreciate hearing from them.)
Customers might switch users 5 to 10 times a day. Switching users must be fast, say a second or two at most.
Is there a way to move user data from UserDefaults to SwiftData when the app is in production so that people don’t lose their data. Currently my audio journals in my journal app has everything in the UserDefaults. Now this is bad for obvious reasons but I was thinking if there was a way. It’s only been 1 week since published and I have already had17 people download it.
If an app is using top-level models, meaning they exist outside the VersionedSchema enum, is it safe to keep them outside of the VersionedSchema enum and use a migration plan for simple migrations. Moving the models within the VersionedSchema enum I believe would change the identity of the models and result in data being lost, although correct me if I'm wrong in that statement.
The need presently is just to add another variable to the model and then set that variable within the init function:
var updateId = UUID()
The app is presently in TestFlight although I'd like to preserve data for users that are currently using the app.
The data within SwiftData is synchronized with CloudKit and so I'd also like to avoid any impact to synchronization.
Any thoughts on this would be greatly appreciated.
I need to know the current date to query CloudKit data with it, like:
let predicate = NSPredicate(format: "publishedAt <= %@", currentDateAndTime)
I don't need high precision, even +/- a few minutes is fine, but I can't rely on device's time since the user can manually change it.
Researching this myself I see that the most reliable method is to get the date from the server.
There are NTP servers, but accessing them requires additional libraries which adds complexity. TrueTime (last updated 6 years ago) and Kronos (updated like once a year) seem outdated, given how much Swift has changed in the past years.
I can make an HTTP request to a website like Google or Apple and read the current time from its headers. But I don't know if this method is reliable.
I know I can create a dummy record in CloudKit, update it, and read its modificationDate. But it feels hacky.
Maybe there is another way to fetch the current date directly from CloudKit?
It feels like it should be easy and there is a straightforward solution, but I just can't find it.
I am an individual developer, and I want to create a demo. Do I need to develop an app for both iOS and Android to accomplish this?
Has Apple provided a simple demo or not?
Topic:
App & System Services
SubTopic:
iCloud & Data
I've been seeing something that I find odd when using two SwiftData models where if I have one model (book, in this case) that has an optional array of another model (page, in this case), the optional array starts out as set to nil, but after about 20 seconds it updates to being an empty array.
I see it in Previews and after building.
Is this expected behavior? Should I just assume that if there is an optional array in my model it will eventually be initialized to an empty array?
Code is below.
import SwiftUI
import SwiftData
@Model
final class Book {
var title: String = "New Book"
@Relationship var pages: [Page]? = nil
init(title: String) {
self.title = title
}
}
@Model
final class Page {
var content: String = "Page Content"
var book: Book? = nil
init() {
}
}
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var books: [Book]
var body: some View {
NavigationSplitView {
List {
ForEach(books) { book in
NavigationLink {
Text("\(book.title)")
Text(book.pages?.debugDescription ?? "pages is nil")
} label: {
Text("\(book.title)")
Spacer()
Text("\(book.pages?.count.description ?? "pages is nil" )")
}
}
}
HStack {
Button("Clear Data") {
clearData()
}
Button("Add Book") {
addBook()
}
}
.navigationSplitViewColumnWidth(min: 180, ideal: 200)
} detail: {
Text("Select an item")
}
}
private func clearData() {
for book in books {
modelContext.delete(book)
}
try? modelContext.save()
}
private func addBook() {
let newBook = Book(title: "A New Book")
modelContext.insert(newBook)
}
}
@main
struct BookPageApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([Book.self, Page.self])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
#Preview {
ContentView()
.modelContainer(for: Book.self, inMemory: true)
}
Hey guys, I'm developing a Swift app, using iCloud to store some data in Containers, and the new Containers I created are iCloud.com.xxx.dev . Therefore, there is a storage called dev in Settings -> icloud -> Manage Account Storage. Currently, the app is still under development and has not been released to the Appstore.
My question: Settings -> icloud -> Manage Account Storage does not display my app name and icon, but only the suffix of the Containers id. Will this change after it is released to the Appstore? Are there any other control methods? Thank you
Hi everyone,
I am a beginner in iOS/Swift programming. I'm trying to develop a mobile application that allows to mount a network drive in the iphone Files application via the WebDav protocol.
I saw on the internet that WebDav is no longer implemented in iOS because considered deprecated by apple.
To accomplish this task, I decided to separate responsibilities as follows:
Framework:
WebDav (responsible for communication with the WebDav server)
FileProviderExtension:
FileBridge (Responsible for bridging the gap between the WebDav Framework and the iOS Files app)
Main App
I also have an AppGroup that includes the main application and the fileproviderextension
Initially, to measure the feasibility and complexity of this task, I'd like to make a simplistic version that simply displays the files on my drive in the Files app, without necessarily being able to interact with them.
FileProviderExtension.swift:
import FileProvider
import WebDav
class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension {
private var webDavService: WebDavService?
required init(domain: NSFileProviderDomain)
{
super.init()
self.webDavService = WebDavService(baseURL: URL(string: "https://www.mydrive.com/drive")!)
}
func invalidate() {
// TODO: cleanup any resources
}
func item(for identifier: NSFileProviderItemIdentifier,
request: NSFileProviderRequest,
completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) -> Progress {
let progress = Progress(totalUnitCount: 1)
Task {
do {
if let items = try await webDavService?.propfind(path: identifier.rawValue, depth: 1),
let item = items.first(where: { $0.itemIdentifier == identifier }) {
completionHandler(item, nil)
} else {
completionHandler(nil, NSError(domain: NSCocoaErrorDomain,
code: NSFileNoSuchFileError,
userInfo: nil))
}
} catch {
completionHandler(nil, error)
}
}
return progress
}
func fetchContents(for itemIdentifier: NSFileProviderItemIdentifier,
version requestedVersion: NSFileProviderItemVersion?,
request: NSFileProviderRequest,
completionHandler: @escaping (URL?, NSFileProviderItem?, Error?) -> Void) -> Progress {
let progress = Progress(totalUnitCount: 1)
Task {
do {
guard let service = webDavService else {
throw WebDavError.invalidResponse
}
let data = try await service.get(fileAt: itemIdentifier.rawValue)
let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent(itemIdentifier.rawValue)
try data.write(to: tempURL)
completionHandler(tempURL, nil, nil)
} catch {
completionHandler(nil, nil, error)
}
}
return progress
}
func createItem(basedOn itemTemplate: NSFileProviderItem, fields: NSFileProviderItemFields, contents url: URL?, options: NSFileProviderCreateItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, NSFileProviderItemFields, Bool, Error?) -> Void) -> Progress {
// TODO: a new item was created on disk, process the item's creation
completionHandler(itemTemplate, [], false, nil)
return Progress()
}
func modifyItem(_ item: NSFileProviderItem, baseVersion version: NSFileProviderItemVersion, changedFields: NSFileProviderItemFields, contents newContents: URL?, options: NSFileProviderModifyItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, NSFileProviderItemFields, Bool, Error?) -> Void) -> Progress {
// TODO: an item was modified on disk, process the item's modification
completionHandler(nil, [], false, NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError, userInfo:[:]))
return Progress()
}
func deleteItem(identifier: NSFileProviderItemIdentifier, baseVersion version: NSFileProviderItemVersion, options: NSFileProviderDeleteItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (Error?) -> Void) -> Progress {
// TODO: an item was deleted on disk, process the item's deletion
completionHandler(NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError, userInfo:[:]))
return Progress()
}
func enumerator(for containerItemIdentifier: NSFileProviderItemIdentifier,
request: NSFileProviderRequest) throws -> NSFileProviderEnumerator {
return FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier,
service: webDavService)
}
}
Here's the code I use to initialize my domain in the main app files:
fileprivate func registerFileProviderDomain() {
let domainIdentifier = NSFileProviderDomainIdentifier("FileProviderExtension Bundle Identifier")
let domain = NSFileProviderDomain(identifier: domainIdentifier,
displayName: "My Drive")
NSFileProviderManager.add(domain) { error in
NSFileProviderManager.add(domain) { error in
if let error = error {
print("Error cannot add domain file provider : \(error.localizedDescription)")
} else {
print("Success domain file provider added")
}
}
}
I can't get rid of the Error :
Error cannot add domain file provider : The operation couldn’t be completed. Invalid argument.
I don't know what I'm missing
Please help me understand