Hello,
I have an iOS app that is still in development, and I am also making a website for it with asp.net core. I am trying to use a server to server key, but it isn't working. The response is:
{
"uuid" : "some_uuid",
"serverErrorCode" : "AUTHENTICATION_FAILED",
"reason" : "Authentication failed"
}
I am using a library called EllipticCurve. You can find it here. My code is:
var requestData = new {
zoneID = new {},
query = new {
recordType = "CD_Person",
filterBy = new [] {
new {
comparator = "EQUALS",
fieldName = "CD_email",
fieldValue = new {
value = email,
type = "String"
}
}
},
sortBy = new [] {
new {
fieldName = "CD_email"
}
}
},
zoneWide = "true",
numbersAsStrings = "true"
};
string request = JsonSerializer.Serialize(requestData);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Apple-CloudKit-Request-KeyID", "my_key_id");
DateTime date = DateTime.Now;
string iso8601Date = date.ToUniversalTime().ToString("u").Replace(" ", "T");
client.DefaultRequestHeaders.Add("X-Apple-CloudKit-Request-ISO8601Date", iso8601Date);
byte[] bytes = Encoding.UTF8.GetBytes(request);
SHA256 hashstring = SHA256.Create();
byte[] hash = hashstring.ComputeHash(bytes);
string base64Request = Convert.ToBase64String(hash);
string paramsToSign = $"{iso8601Date}:{base64Request}:my url";
PrivateKey privateKey = PrivateKey.fromPem("-----BEGIN EC PRIVATE KEY-----\nprivate_key\n-----END EC PRIVATE KEY-----");
Signature signature = Ecdsa.sign(paramsToSign, privateKey);
client.DefaultRequestHeaders.Add("X-Apple-CloudKit-Request-SignatureV1", signature.toBase64());
var content = new StringContent(request, Encoding.UTF8, "application/json");
var response = client.PostAsync("https://api.apple-cloudkit.com/database/1/my_container/development/public/records/query", content);
string responseString = response.Result.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseString);
return View();
Any help would be appreciated.
iCloud & Data
RSS for tagLearn how to integrate your app with iCloud and data frameworks for effective data storage
Post
Replies
Boosts
Views
Activity
I'm trying to do a mass conversion of images to data so it can be stored in core data.
The conversion part works fine, and if I do it without updating core data it shows memory usage at less that 100MB
If I update the core data object, it just keeps consuming memory until the app crashes.
func updateLocalImages() {
let fetchRequest: NSFetchRequest<Picture> = Picture.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "pictureName != \"\"")
do {
let pictures = try moc.fetch(fetchRequest)
print("Picture Update Count: \(pictures.count)")
for picture in pictures {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let path = paths[0]
if let picName = picture.pictureName {
let imagePath = path.appendingPathComponent(picName)
if let uiImage = UIImage(contentsOfFile: imagePath.path) {
if let imageData = uiImage.jpegData(compressionQuality: 1.0) {
autoreleasepool {
picture.pictureData = imageData
print("Picture Updated")
saveContext()
}
}
}
}
}
} catch {
print("Fetching Failed")
}
}
If I comment out the picture.pictureData = imageData line I don't get the memory issues.
What's the correct way of going about this? There is an unknown number of images (mine current sits at about 5.5GB worth, 800+)
I'm building two apps. They both share a CloudKit container. One application is designed to edit the contents of the public database regardless of who a record's creator is. The other should only be allowed to read from the public database.
Since CloudKit is largely a client-side framework it's easy enough to enforce this client side.
Are there any additional guarantees that iCloud provides to enforce what the clients are signed to do? Or is there a risk of having some actor tamper with the public database that isn't using the editing application?
Hello Developer Support,
Let's say I have the following models. Is there a way to have dataSet pre-sorted by swiftData?
@Model
Struct Capture {
let someInfo: String
@Relationship(.unique, deleteRule: .cascade) // some way of sorting by CoolPoint.date
let dataSet: [CoolPoint]
}
@Model
struct CoolPoint {
let point: Int
let date: Date
}
I use SwiftData, CloudKit, and App Groups. An error occurs on the first run, but it works on the second run.
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate tearDown:]_block_invoke(792): <NSCloudKitMirroringDelegate: 0x12df73750>: Told to tear down with reason: Store Removed
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _performSetupRequest:]_block_invoke(1192): <NSCloudKitMirroringDelegate: 0x12df73750>: Failed to set up CloudKit integration for store: (null)
Error Domain=NSCocoaErrorDomain Code=134060 "" UserInfo={NSLocalizedFailureReason=The mirroring delegate could not initialize because it's store was removed from the coordinator.}
I don't know why store path is null in error message.
I passed the store url and CloudKit database name in ModelConfiguration.
static var release: ModelContainer = {
do {
let schema = Schema(versionedSchema: ModelSchema.self)
let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group-identifier")
let databaseURL = appGroupURL?.appending(path: "Database.sqlite")
let databaseName = "Database"
let configuration = ModelConfiguration(schema: schema,
url: databaseURL!,
cloudKitDatabase: .private("iCloud.database.name"))
return try ModelContainer(for: schema,
migrationPlan: ModelMigrationPlan.self,
configurations: [configuration])
} catch {
fatalError(error.localizedDescription)
}
}()
I'm a bit lost because of a problem I never experienced before, however, I have a suspicion. I use Core Data for data storage and DB Browser for SQLite for inspecting the database running in the Simulator.
Here's the relevant function where all Core Data handling happens:
/**
Creates a new ComposedFoodItem from the ComposedFoodItemViewModel.
Creates the related FoodItem and the Ingredients.
Creates all relationships.
- Parameter composedFoodItemVM: The source view model.
- Returns: A Core Data ComposedFoodItem; nil if there are no Ingredients.
*/
static func create(from composedFoodItemVM: ComposedFoodItemViewModel, generateTypicalAmounts: Bool) -> ComposedFoodItem? {
debugPrint(AppDelegate.persistentContainer.persistentStoreDescriptions) // The location of the .sqlite file
let moc = AppDelegate.viewContext
// Create new ComposedFoodItem (1)
let cdComposedFoodItem = ComposedFoodItem(context: moc)
// No existing composed food item, therefore create a new UUID
cdComposedFoodItem.id = UUID()
// Fill data
cdComposedFoodItem.amount = Int64(composedFoodItemVM.amount)
cdComposedFoodItem.numberOfPortions = Int16(composedFoodItemVM.numberOfPortions)
// Create the related FoodItem (2)
let cdFoodItem = FoodItem.create(from: composedFoodItemVM, generateTypicalAmounts: generateTypicalAmounts)
// Relate both (3)
cdComposedFoodItem.foodItem = cdFoodItem
// Add cdComposedFoodItem to composedFoodItemVM
composedFoodItemVM.cdComposedFoodItem = cdComposedFoodItem
// Save before adding Ingredients, otherwise this could lead to an NSInvalidArgumentException (4)
try? moc.save()
// Add new ingredients (5)
if let cdIngredients = Ingredient.create(from: composedFoodItemVM) {
cdComposedFoodItem.addToIngredients(NSSet(array: cdIngredients))
// Save new composed food item
try? moc.save()
// Return the ComposedFoodItem
return cdComposedFoodItem
} else {
// There are no ingredients, therefore we delete it again and return nil
moc.delete(cdComposedFoodItem)
try? moc.save()
return nil
}
}
What the function does:
Creates a new entry in table ComposedFoodItem
Creates another new entry in another table FoodItem
Relates both entries
Saves the modifications (and as of here I can see both new entries in the DB with all relations created correctly)
Creates another 1..n entries in a third table Ingredient and links these to the entry created in step 1
All this works fine, I can see all relations and entries in the database.
Then I quit and restart the app. The entry created in step 2 is still there, but the entries created in steps 1 and 5 are gone, as well as the relationships (of course).
My suspicion: I recently implemented a Core Data migration from Data Model version 1 ("EasyFPU") to version 2 ("EasyFPU 2"). In this migration, I have two custom migration policies for exactly the two tables, which are not stored. The migration policies are pretty simple (and identical for both tables):
/**
No Ingredient is created in the destination model, i.e., there will be no Ingredients
*/
override func createDestinationInstances(forSource sourceIngredient: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
// Do nothing on purpose
debugPrint("Not migrating Ingredient with ID: \((sourceIngredient as? Ingredient)?.id.uuidString ?? "unknown")")
}
And what I suspect is, that this migration policies are somehow called when restarting the app, but I have no idea why, because the migration has already happened before. If I set a breakpoint in the debugPrint line of the code snippet above, I actually never reach this breakpoint - as expected. Nevertheless are the two tables Ingredient and ComposedFoodItem empty after restart.
My AppDelegate Core Data persistentContainer variable looks like this:
lazy var persistentContainer: NSPersistentCloudKitContainer = {
let container = NSPersistentCloudKitContainer(name: "EasyFPU")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
I tried to replace "EasyFPU" with "EasyFPU 2", but this apparently is not the version, but the container name.
Any idea? Thanks in advance!
Our service is 100% on token-based authentication with APNs. Each pod generates a new token to use every 30 mins. We have hundreds of pods.
We implemented this way because in Refresh your token regularly section it says
Refresh your token no more than once every 20 minutes and no less than once every 60 minutes.
APNs report an error if you use a new token more than once every 20 minutes on the same connection.
However, we saw TooManyProviderTokensUpdates sporadically. What is even stranger is, the trigger of the error does not correlate to the number of pods as we scaled up or down, nor does it correlate to the QPS. To me, it looks like It triggers randomly. Can someone from Apple shed some light on this?
It works fine if I take either model out, but it doesn't work with both I have tried multiple variations
import SwiftData
import Foundation
@main
struct blendTravelfourApp: App {
@Environment(\.modelContext) var context
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(for: PlanTripData.self)
.modelContainer(for: PastTripData.self)
}
}
}
import SwiftData
@main
struct blendTravelfourApp: App {
var container: ModelContainer
init() {
do {
let config1 = ModelConfiguration(for: PlanTripData.self)
let config2 = ModelConfiguration(for: PastTripData.self)
container = try ModelContainer(for: PlanTripData.self, PastTripData.self, configurations: config1, config2)
} catch {
fatalError("Failed to configure SwiftData container.")
}
}
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(container)
}
}
}
my question is how to filter in search text for city.name in Concert ? i tried to reach city name using nested compact map but couldn't handle it.
class Concert {
var kindOf : String
var city : [City]
}
class City {
var name : String
@Relationship(inverse: \Concert.city) var concert : [Concert]
}
@Query var concerts : [Concert]
@State var searchQuery : String = ""
var filteredConcert : [Concert] {
if searchQuery.isEmpty {
return concerts
}
let filteredConcerts = concerts.compactMap { concert in
let kindOfContainsSearch = concert.kindOf.range(of: searchQuery) != nil
return (kindOfContainsSearch ) ? concert : nil
}
return filteredConcerts
}
Hi! I'm experimenting with SwiftData and looking for a situation where one persistentModelID might result in more than one registered model object reference delivered from a fetch from a single context. Here is an example of what I have to experiment:
import Foundation
import SwiftData
@Model class Person {
var name: String
init(name: String) {
self.name = name
}
}
func main() {
let configuration = ModelConfiguration(
isStoredInMemoryOnly: true,
allowsSave: true
)
do {
let container = try ModelContainer(
for: Person.self,
configurations: configuration
)
let context = ModelContext(container)
let person = Person(name: "John Appleseed")
context.insert(person)
let persistentModelID = person.persistentModelID
if let left: Person = context.registeredModel(for: persistentModelID),
let right: Person = context.registeredModel(for: persistentModelID) {
print(left === right) // true
}
let descriptor = FetchDescriptor<Person>(
predicate: #Predicate { person in
person.persistentModelID == persistentModelID
}
)
if let left = try context.fetch(descriptor).last,
let right = try context.fetch(descriptor).last {
print(left === right) // true
}
} catch {
print(error)
}
}
main()
This is a very simple command line app that attempts to fetch "two different" registered models… but both approaches (querying directly for persistentModelID and wrapping persistentModelID with FetchDescriptor) seem to consistently deliver objects equal by reference.
Is there any situation where I could set this code up to deliver two registered models different by reference (but equal by value)? Is this anything I have to think about or manage at an "app" level? Is this behavior documented anywhere? Thanks!
My app has been in the App Store a few months. In that time I've added a few updates to my SwiftData schema using a MigrationPlan, and things were seemingly going ok. But then I decided to add CloudKit syncing. I needed to modify my models to be compatible. So, I added another migration stage for it, changed the properties as needed (making things optional or adding default values, etc.). In my tests, everything seemed to work smoothly updating from the previous version to the new version with CloudKit. So I released it to my users. But, that's when I started to see the crashes and error reports come in. I think I've narrowed it down to when users update from older versions of the app. I was finally able to reproduce this on my end, and Core Data is throwing an error when loading the ModelContainer saying "CloudKit integration requires that all attributes be optional, or have a default value set." Even though I did this in the latest schema. It’s like it’s trying to load CloudKit before performing the schema migration, and since it can’t, it just fails and won’t load anything. I’m kinda at a loss how to recover from this for these users other than tell them to delete their app and restart, but obviously they’ll lose their data that way. The only other idea I have is to setup some older builds on TestFlight and direct them to update to those first, then update to the newest production version and hope that solves it. Any other ideas? And what can I do to prevent this for future users who maybe reinstall the app from an older version too? There's nothing special about my code for loading the ModelContainer. Just a basic:
let container = try ModelContainer(
for: Foo.self, Bar.self,
migrationPlan: SchemaMigration.self,
configurations: ModelConfiguration(cloudKitDatabase: .automatic)
)
Hi,
I have recently noticed that it's taking my app a long time between the CKModifyOperations being 'completed' in the app, and for the record to actual show up through either looking at the CloudKit dashboard, or by using CKQueryOperations. The whole upload can take 10-15 minutes or more, from the time the CKOperation has completed to the time I can see all the records on the dashboard. The 'upload' seems to be happening in chunks ... for e.g. if I uploaded a 100 records, if I check after 2 minutes the query will show 20 records, and then 35-40 a bit later, and after 10+ minutes will show all 100 records (exact numbers vary of course). This was never an issue before, but has recently been reported by a couple of users of my app, and I need to know what's going on before it balloons into a big thing. And it's highly problematic, because it leads to users not being able to download the records that they uploaded on the first device.
Is there something in CloudKit servers that have changed recently? Can someone in the CloudKit team take a look? I filed a Feedback, along with CloudKit profile logs: FB13537245
I can also reproduce the issue in production as well as development environments.
Hi,
Is there some limit for how many recordIDs we can fetch in CKFetchRecordsOperation? There doesn't seem to be any batching or cursor support built in to the API. So if I pass in 5000 recordIDs, it'll work fine?
Would love to get some confirmation either ways so I can better plan for it.
Thanks!
the Model Code
import Foundation
import SwiftData
@Model
class TestItemTotal {
var id = UUID()
var name: String
var describe: String
init(name: String = "", describe: String = "") {
self.name = name
self.describe = describe
}
}
the contentView code
import SwiftUI
class ShareData: ObservableObject {
@Published var path: NavigationPath = NavigationPath()
@Published var selectedTestItemTotal = TestItemTotal()
}
struct ContentView: View {
@StateObject var shareData = ShareData()
var body: some View {
NavigationStack(path: $shareData.path) {
List{
Text("The Main Project List")
Text("The Detail List")
}
}
}
}
#Preview {
ContentView()
}
Crash
it will crash ,when #preview use Xcode ,
but it will not crash when run in Simulator .
fix Crash
Remove @Model string , it will not crash , when #preview use Xcode ,
but i can't remove @Model String , because i will to processing data by SwiftData
/var/mobile/Containers/Data/Application/9DBD5CCD-36A9-4496-93FB-B8EBD679E934/Documents/godai_2024-01-16_09-34-11-445/photo_2024-01-16_09-34-11-452.json..in this debug console folder name "godai_2024-01-16_09-34-11-445" is shown but in iCloud Drive folder name change into example ..how can to fix this issue ??
I got a @Model class with a property of a codable "Options" struct.
import SwiftData
@Model
final class Project {
var options: Options
}
In this struct I have another property called "resolution" of type Size3D.
import Spatial
struct Options: Codable {
var resolution: Size3D
}
I can initially launch the app and save a project with a custom resolution. Tho when I try to re-launch the app it crashes:
Could not cast value of type 'Swift.Optional<Any>' (0x1fa251d80) to '__C.SPSize3D' (0x1047dcbc0).
Size3D is codable, tho it does not seem to currently be supported by SwiftData.
My current solution is to have a middle type that I store in my options struct like this:
struct Options: Codable {
private struct CodableResolution: Codable {
let width: Double
let height: Double
let depth: Double
var size: Size3D {
Size3D(width: width, height: height, depth: depth)
}
init(_ size: Size3D) {
self.width = size.width
self.height = size.height
self.depth = size.depth
}
}
private var codableResolution: CodableResolution
var resolution: Size3D {
get {
codableResolution.size
}
set {
codableResolution = CodableResolution(newValue)
}
}
}
Note that I'm testing this on the visionOS simulator with Xcode 15.2 on macOS 14.0
Feedback: FB13543953
I am doing a full transition of an app from CoreData to SwiftData. I was able to follow the online guides and extract SwiftData objects from the CoreData model. Everything seems to work except for my Transformable String Arrays. This app is storing CoreData in iCloud.
In my SwiftData model, I have a variable...
@Attribute(.transformable(by: "NSSecureUnarchiveFromData"))
var arrayofStrings: [String]?
The app is able to read the array of strings, however, the debugger gives me this error eventually crashing due to memory.
'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
I don't understand, the transformed variable already is 'NSSecureUnarchiveFromData' not 'NSKeyedUnarchiveFromData'. That's the reason why I used NSSecureUnarchiveFromData in my CoreData model because NSKeyedUnarchiveFromData is being phased out. I don't get why the debugger thinks otherwise.
Any thoughts?
My App uses Core Data + CloudKit and requires use of CloudKit to store persistent data, that will be shared between Users. I’d like to establish the User’s identity - like so they can augment their Core Data ‘Player’ entity w/ App specific info. Certain interfaces have been deprecated (‘user discoverability’). I’ve taken to creating a ‘dummy shared zone’ and extracting the ‘owner.userIdentity':
public func establishUser () async -> User? {
let container = cloudKitContainer
// If we store the userUUID then the implication is that the `user` can
// never be deleted; that is fair enough.
let userUUIDKey = "userUUID"
var userIdentity = Optional<CKUserIdentity>.none
do {
//
// We'll store the UUID of the CoreData `User` in the CloudKit `User` record. If there
// is no UUID in CloudKit, then this will be the first time the User has ever started
// the App. We'll create a user and update the CloudKit `User` record
//
let userID = try await container.userRecordID ()
let userRecord = try await container.publicCloudDatabase.record (for: userID)
// If the `userRecord` does not have a `userUUIDKey` then we must create a new `User`.
if nil == userRecord[userUUIDKey] {
// See if the user has the required iCloud account.
let userStatus = try await container.accountStatus()
guard userStatus == .available
else {
print ("JKP: \(#function) accountStatus: \(userStatus)")
return nil
}
//
// Create a `dummyShare` (in a 'dummyZone') so we can access the share's owner
// That owner will have our `userIdentity`
//
do {
let dummyZone = CKRecordZone (zoneName: UUID().uuidString)
let dummyShare = CKShare (recordZoneID: dummyZone.zoneID)
print ("JKP: User: Establish Zone: \(dummyZone.zoneID.zoneName)")
// Save the dummyZone and then the dummyShare (for/in the dummyZone)
let _ = try await container.privateCloudDatabase.save (dummyZone)
let _ = try await container.privateCloudDatabase.save (dummyShare)
// Extract the dummyShare's owner's identity - which is 'us/me'
userIdentity = dummyShare.owner.userIdentity
// Cleanup by deleting the 'dummyShare' and then the 'dummyZone'
let _ = try await container.privateCloudDatabase.deleteRecord (withID: dummyShare.recordID)
let _ = try await container.privateCloudDatabase.deleteRecordZone (withID: dummyZone.zoneID)
}
catch {
print ("JKP: User Establish Error: \(error.localizedDescription)")
}
// Create `newUser` with the `userRecordId`. We'll use this to lookup the
// Core Data User when players appear in a League.
let newUser = User.create (context,
scope: Player.Scope.owner,
name: (userIdentity?.nameComponents ?? PersistenceController.nameDefault),
identification: userIdentity?.lookupInfo
.map { PlayerIdentification.create (lookupInfo: $0) } ?? PlayerIdentification())
… }
Is this how getting the userIdentity is meant to be done (w/o using the deprecated interfaces)? The deprecated interfaces, when warned in Xcode, reference a sample project; that project doesn’t actually use/get the userIdentity.
Also the deleteRecord and deleteRecordZone don’t appear to remove the dummy zone in CloudKit; why?
How does one know when the CloudKit data in a CoreData+CloudKit (NSPersistentCloudKitContainer) has been fully synchronized. UseCase would be a user starts the App on a second device, user deletes then reinstalls the App, another User accepts a share and the share needs to sync.
Is the containerEventChanged Notification for 'import success' the definitive event?
CoreData: CloudKit: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _finishedRequest:withResult:](3403): Finished request: <NSCloudKitMirroringImportRequest: 0x600002345d10> 729A742A-7F3B-42F1-B04C-72705D41FFEF with result: <NSCloudKitMirroringResult: 0x600000c4edc0> storeIdentifier: 79FA5848-A135-41B1-A36A-09F2F914D23D success: 1 madeChanges: 0 error: (null)
As the sync could be time-consuming, is there a way to identify a single CloudKit record?
Hi fellow Swifties,
Been pulling my hair out for 8+ hours and need your help :(
Tried creating 3 models that are cloudkit compatible, but the app crashes every time I try to add an Object to the modelContext.
Error:
Thread 1: EXC_BREAKPOINT (code=1, subcode=0x18ec49d2c)
My guess:
I think it is trying to force unwrap a nil...
Can do:
Insert Item() and Location() into modelContext + syncronizing to cloudkit without any errors.
modelContext.insert(Item())
modelContext.insert(Location())
Can not do:
Insert Object() into modelContext.
modelContext.insert(Object())
Am I not initialising them correctly? Is this approach bad? Or am I experiencing a bug?
Help is much appreciated <3
My 3 models:
@Model
class Item: Identifiable {
var id: UUID = UUID.init()
var name: String = String()
var barcode: String = String()
@Relationship(deleteRule: .cascade, inverse: \Object.item)
var objects: [Object]?
@Attribute(.externalStorage)
var photo: Data?
init(name: String = String(), barcode: String = String(), photo: Data? = nil) {
self.name = name
self.barcode = barcode
self.photo = photo
}
}
@Model
class Location: Identifiable {
var id: UUID = UUID.init()
var name: String = String()
@Relationship(deleteRule: .cascade, inverse: \Object.location)
var objects: [Object]?
var isFavorite: Bool = Bool(false)
var unwrappedObjects: [Object] {
objects ?? []
}
init(name: String = String(), isFavorite: Bool = Bool(false)) {
self.name = name
self.isFavorite = isFavorite
}
}
@Model
class Object: Identifiable {
var id: UUID = UUID.init()
var amount: Int = Int()
var expiryDate: Date? = nil
var location: Location?
var item: Item?
init(amount: Int = Int(), expiryDate: Date? = nil) {
self.amount = amount
self.expiryDate = expiryDate
}
}