iCloud & Data

RSS for tag

Learn how to integrate your app with iCloud and data frameworks for effective data storage

CloudKit Documentation

Post

Replies

Boosts

Views

Activity

SwiftData `context.fetch()` possible bug on WidgetKit EntityQuery
I'm developing an app with dynamic intents fetched from a SwiftData container with data that is configured inside the app. However, the following happens when .fetch() is run during widget configuration. When creating a new instance of the model and inserting it into the container, it disappears when the app is relaunched. When creating a new instance of the model and inserting it into the container, and then attempting to delete that instance, the app crashes. This error shows up Could not cast value of type 'Swift.Optional<Any>' (0x2003ddfc0) to 'Foundation.UUID' (0x200442af8). This is a snippet of the query code. func entities(for identifiers: [ExampleEntity.ID]) async throws -> [ExampleEntity] { let modelContext = ModelContext(Self.container) let examples = try? modelContext.fetch(FetchDescriptor<ExampleModel>()) return examples?.map { ExampleEntity(example: $0) } ?? [] } SwiftData works as expected as long as the .fetch() is not called in the EntityQuery.
3
1
927
Dec ’23
UIDocumentPickerViewController with type .folder won't give access to files inside selected folder
Hi, I followed the instructions here: https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories but when trying to get access to each file inside the selected folder (tried iCloud and iPhone) it always fails. Instead, if I specify a type of file on the Controller (say .audio) I can read the file fine... Did anything change which is not documented in that page? Do I have to set any other permission or capability? (I have iCloud Documents) Thanks!!
2
0
711
Dec ’23
SwiftData+Cloudkit Migration Failed
I have v3 models in coredata (model: Event, Lecture), and make new model in v4 with swiftdata but model name, property is different (model: EventModel, LectureModel). For migration, I add V3Schema, V4Schema and MigrationPlan. enum V4Schema: VersionedSchema { static var models: [any PersistentModel.Type] = [LectureModel.self, EventModel.self ] static var versionIdentifier = Schema.Version(4, 0, 0) } enum V3Schema: VersionedSchema { static var models: [any PersistentModel.Type] = [Event.self, Lecture.self] static var versionIdentifier = Schema.Version(3, 5, 2) } enum ModelMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] = [V3Schema.self, V4Schema.self] static var stages: [MigrationStage] = [migrateV3ToV4] } extension ModelMigrationPlan { static let migrateV3ToV4 = MigrationStage.custom(fromVersion: V3Schema.self, toVersion: V4Schema.self, willMigrate: willMigrate, didMigrate: { _ in Log.debug(message: "Migration Complete") }) } private func willMigrate(context: ModelContext) throws { try migrateLectures(context: context) try migrateEvents(context: context) try context.save() } private func migrateEventTypes(context: ModelContext) throws { // create new v4 event model using v3 event model. } private func migrateLectures(context: ModelContext) throws { // create new v4 lecture model using v3 lecture model. } static let release: ModelContainer = { let v4Schema = Schema(V4Schema.models) let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "app group id") let databaseURL = containerURL?.appending(path: "**.sqlite") let configuration = ModelConfiguration("**", schema: v4Schema, url: databaseURL!, cloudKitDatabase: .private("**")) #if DEBUG do { try autoreleasepool { let desc = NSPersistentStoreDescription(url: configuration.url) let opts = NSPersistentCloudKitContainerOptions(containerIdentifier: configuration.cloudKitContainerIdentifier!) desc.cloudKitContainerOptions = opts desc.shouldAddStoreAsynchronously = false if let model = NSManagedObjectModel.makeManagedObjectModel(for: V4Schema.models) { let container = NSPersistentCloudKitContainer(name: "**", managedObjectModel: model) container.persistentStoreDescriptions = [desc] container.loadPersistentStores(completionHandler: { _, err in if let err { Log.error(message: "Store open failed: \(err.localizedDescription)") } }) try container.initializeCloudKitSchema() Log.debug(message: "Initialize Cloudkit Schema") if let store = container.persistentStoreCoordinator.persistentStores.first { try container.persistentStoreCoordinator.remove(store) } } } } catch { Log.error(message: "Failed: \(error.localizedDescription)") } #endif return try! ModelContainer(for: v4Schema, migrationPlan: ModelMigrationPlan.self, configurations: configuration) }() But when I run, I got error message. CoreData: CloudKit: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _scheduleAutomatedExportWithLabel:activity:completionHandler:]_block_invoke(3508): <NSCloudKitMirroringDelegate: 0x1036b1540> - Finished automatic export - ExportActivity - with result: <NSCloudKitMirroringResult: 0x1035da810> storeIdentifier: ***** success: 0 madeChanges: 0 error: Error Domain=NSCocoaErrorDomain Code=134407 "Request '*****' was cancelled because the store was removed from the coordinator." UserInfo={NSLocalizedFailureReason=Request '****' was cancelled because the store was removed from the coordinator.} I don't know why store was removed from the coordinator. Any have solutions?
2
0
741
Dec ’23
I'm having trouble applying the SwiftData MigrationPlan.
I'm currently using Swiftdata to store data for an app I've deployed to the app store. The problem is that the app does not build when I add a case of the Enum type to the model, so I decided to apply a MigrationPlan. I also decided that it is not a good idea to store the Enum type itself because of future side effects. The app is deployed in the app store with a model without a VersionedSchema, so the implementation is complete until we modify it to a model with a VersionedSchema. This is Version1. public enum TeamSchemaV1: VersionedSchema { public static var versionIdentifier: Schema.Version = .init(1, 0, 0) public static var models: [any PersistentModel.Type] { [TeamSchemaV1.Team.self, TeamSchemaV1.Lineup.self, TeamSchemaV1.Player.self, TeamSchemaV1.Human.self] } @Model public final class Lineup { ... public var uniform: Uniform ... } And you're having trouble migrating to Version2. The change is to rename the Uniform to DeprecatedUniform (the reason for the following change is to migrate even if it's just a property name) public enum TeamSchemaV2: VersionedSchema { public static var versionIdentifier: Schema.Version = .init(1, 0, 1) public static var models: [any PersistentModel.Type] { [TeamSchemaV2.Team.self, TeamSchemaV2.Lineup.self, TeamSchemaV2.Player.self, TeamSchemaV2.Human.self] } @Model public final class Lineup { ... @Attribute(originalName: "uniform") public var deprecatedUniform: Uniform ... When you apply this plan and build the app, EXC_BAD_ACCESS occurs. public enum TeamMigrationPlan: SchemaMigrationPlan { public static var schemas: [VersionedSchema.Type] { [TeamSchemaV1.self, TeamSchemaV2.self] } public static var stages: [MigrationStage] { [migrateV1toV2] } public static let migrateV1toV2 = MigrationStage.lightweight(fromVersion: TeamSchemaV1.self, toVersion: TeamSchemaV2.self) } I'm currently unable to migrate the data, which is preventing me from updating and promoting the app. If anyone knows of this issue, I would really appreciate your help.
2
0
636
Dec ’23
How to change from non-versioned to versioned schema in swiftdata?
My app is using SwiftData, but I deployed it to the app store with no VersionedSchema applied without thinking about migrating the model. Now I need to migrate the data and I need help from someone who has experience moving from non-versioned to versioned. Assuming I currently have a version1, version2 schema, it works fine for the initial install situation, but when I migrate to version1, version2 in an app that is listed on the app store, I run into problems. I don't have any logs to show for it. Thread 1: EXC_BAD_ACCESS (code=2, address=0x16a6578f0) If anyone has had the same experience as above, please respond, thanks! Let me know what kind of logs you need and I'll add them as a comment.
2
1
682
Dec ’23
SwiftData schema version not match
I have two versionedSchema V1VersionedSchema, V2VersionedSchema. When i create schema with versionedSchema like code below and check version using breakpoint, V1, V2 Schema encodingVersion is same. let v3Schema = Schema(versionedSchema: V1VersionedSchema.self) // encodingVersion: 1.0.0 // schemaEncodingVersion: 1.0.0 let v2Schema = Schema(versionedSchema: V2VersionedSchema.self) // encodingVersion: 1.0.0 // schemaEncodingVersion: 2.0.0 Why encoding version is same? (I think migration plan v1 to v2 isn't work becaus of that)
1
0
415
Dec ’23
.transformable with ValueTransformer failing after Xcode 15.1 update
In Xcode 15.0.1, I created a new project to start working with SwiftData. I did this by creating a default App project and checking the Use SwiftData checkbox. The resulting project contains just three files: an app entry point file, a ContentView SwiftUI view file, and an Item model file. The only change I made was to annotate the default Item timestamp property with a .transformable attribute. Here is the resulting model: @Model final class Item { @Attribute(.transformable(by: TestVT.self)) var timestamp: Date // Only updated this line init(timestamp: Date) { self.timestamp = timestamp } } And here is the definition of TestVT. It is a basic ValueTransformer that simply tries to store the Date as a NSNumber: // Added this class TestVT: ValueTransformer { static let name = NSValueTransformerName("TestVT") override class func transformedValueClass() -> AnyClass { NSNumber.self } override class func allowsReverseTransformation() -> Bool { true } override func transformedValue(_ value: Any?) -> Any? { guard let date = value as? Date else { return nil } let ti = date.timeIntervalSince1970 return NSNumber(value: ti) } override func reverseTransformedValue(_ value: Any?) -> Any? { guard let num = value as? NSNumber else { return nil } let ti = num.doubleValue as TimeInterval return Date(timeIntervalSince1970: ti) } } And finally, I made sure to register my ValueTransformer but updating the sharedModelContainer definition in the App: var sharedModelContainer: ModelContainer = { ValueTransformer.setValueTransformer(TestVT(), forName: TestVT.name) // Only added this line let schema = Schema([ Item.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() Prior to Xcode 15.1, this was working fine. However, now when I try to create an item when running the app I get the following error: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "timestamp"; desired type = NSNumber; given type = __NSTaggedDate; value = 2023-12-14 01:47:11 +0000.' I'm unsure of why this stopped working. The error seems to be complaining about the input being of type Date when NSNumber was expected, but I thought that's what the ValueTransformer was supposed to be doing. Important note: prior to Xcode 15.1, I did not originally override the transformedValueClass() and everything was working but in the new Xcode when launching the app I was getting a Thread 1: EXC_BAD_ACCESS (code=1, address=0x0) on the return try ModelContainer(...) line. Removing the .transformable property from my model fixed the issue. That's why I added the override here, because I think the docs indicate overriding it as well and I missed that the first time. This being said, I think the code I have is what a correct ValueTransformer would look like. If anyone has experienced this issue, or has a working ValueTransformer for SwiftData in Xcode 15.1, please let me know. Appreciate any help with this issue. Thanks so much!
4
3
1.3k
Dec ’23
SwiftData query filter on an @State var
Hey, I might have a super dumb question but I am very new to SwiftData and Swift in general. So I have the following code in a View: @State private var selectedMonth: String = "" @State private var selectedYear: String = "" @Query( filter: #Predicate<Transaction> { transaction in transaction.date.monthString == selectedMonth && transaction.date.yearString == selectedYear }, sort: \Transaction.date ) var transactions: [Transaction] My @State vars selectedMonth and selectedYear get changed whenever the user selects options from a menu. I've had trouble getting this query/filter to work, does anyone know if filtering on dynamic (@State) variables is supported in SwiftData? If so, am I missing something here? I've also tried the pattern of having the transactions array live elsewhere in a regular swift file with the @Published macro and calling an update function whenever the @State vars selectedMonth or selectedYear get updated using .onChange(of:) . Unfortunately, I've not been able to find any documentation or examples about setting up a regular swift file (not SwiftUI) to work with SwiftData (e.g. querying from it, accessing the context/container, etc) Would appreciate anyone giving tips or pointing me in the right direction. Sorry if its a noob questions, thanks so much for any help
2
4
3.1k
Dec ’23
How to handle predicate with optionals in SwiftData
Xcode: 15.1 I've got (simplified) model with relationship many-to-many defined as follows @Model final class Item { var title: String @Relationship(inverse: \Tag.items) var tags: [Tag]? init(_ title: String) { self.title = title } } @Model final class Tag { var name: String var items: [Item]? init(_ name: String) { self.name = name } } and a view with a query struct ItemsView: View { @Query var items: [Item] var body: some View { List {...} } init(searchText: String) { _items = Query(filter: #Predicate<Item> { item in if (searchText.isEmpty) { return true } else { return item.tags!.contains{$0.name.localizedStandardContains(searchText)} } }) } } This code compiles but fails at runtime with an error: Query encountered an error: SwiftData.SwiftDataError(_error: SwiftData.SwiftDataError._Error.unsupportedPredicate) It looks like Predicate does not like optionals cause after changing tags and items to non optionals and the predicate line to item.tags.contains{$0.name.localizedStandardContains(searchText)} everything works perfectly fine. So, my question is, does anybody know how to make it work with optionals? Full code: https://github.com/m4rqs/PredicateWithOptionals.git
4
1
1.6k
Dec ’23
Preventing ioError with ArchiveStream.process
I am trying to use ArchiveStream.process on MacOS as outlined in the documentation here: https://developer.apple.com/documentation/accelerate/decompressing_and_extracting_an_archived_directory I have been able to successfully do the following: Take objects and create Data objects Create a UIDocument that is FileWrapper based Compress the UIDocument as an .aar archive Upload it to iCloud as a CKRecord Download it as an .aar and decode it back to a directory Decode the directory as individual data items and back to objects The problem is that I sometimes can only download from iCloud once and have the decompression function - other times it may work two or three times but ultimately fails when trying to call ArchiveStream.process The error reported by ArchiveStream.process is simply 'ioError' but on the console I see the following: [0xa5063c00] Truncated block header (8/16 bytes read) [0xa503d000] NOP received [0xa5080400] processStream [0xa7019000] decoder failed [0xbd008c00] istream read error [0xbd031c00] refill buffer [0x90008000] archive stream read error (header) [0xc8173800] stream cancelled The test data I am using does not change so it does not appear to be related to what I am compressing. But I am at a loss how to prevent the error. This is IOS 17 running on MacOS (as iPad) and on IOS 17 devices.
2
0
493
Dec ’23
Swift Data Merge Contexts Publish and SwiftUI Dependency
Expected behaviour: When I press the button I expect the label change from "Original" to "Edited" Obtained behaviour: This only happens in scenario A) and B) not C), the desired. Scenario A: action: update2(item:) and both labels Scenario B: action: update(itemID:container:) and label: Text(item.name) Scenario C: action: update(itemID:container:) and label: ItemRow(item:) import SwiftUI import SwiftData struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var items: [Item] var body: some View { NavigationSplitView { List { ForEach(items) { item in Button(action: { update(itemID: item.id, container: modelContext.container) // update2(item: item) }, label: { ItemRow(item: item) // Text(item.name) }) } .onDelete(perform: deleteItems) } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } detail: { Text("Select an item") } } private func addItem() { withAnimation { let newItem = Item(name: "Original") modelContext.insert(newItem) //modelContext.save() } } private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(items[index]) } } } } struct ItemRow: View { let item: Item var body: some View { Text(item.name) } } @Model final class Item { var name: String init(name: String) { self.name = name } } func update(itemID: PersistentIdentifier, container: ModelContainer){ let editModelContext = ModelContext(container) editModelContext.autosaveEnabled = false let editModel = editModelContext.model(for: itemID) as! Item editModel.name = "Edited" try! editModelContext.save() } func update2(item: Item){ item.name = "Edited" }
0
1
385
Dec ’23
Private database: failed to access iCloud data please signin again.
When I logged into my cloudkit console to inspect the database for some debugging work I couldn't access the private database. It keeps saying "failed to access iCloud data, please signi n again". No matter how many times I sign in again, whether with password or passwordless key it keeps saying the same thing. It says that message when I click on Public database, and private and shared databases are below it. I only noticed this a couple of days ago. It's done this in the past, but I eventually got back into the database but I don't know what changed to make it work.
7
5
1.3k
Dec ’23
SwiftData Custom Migration with no change in schema?
I'll preface by saying I'm a new Swift developer, having a go at my first app. Just a simple memory tracker. I'm building it using SwiftData + iCloud Syncing. I had set up my model like this: @Model final class Memory { var content: String = "" var dateCreated: Date = Date.now var dateUpdated: Date = Date.now var tags: [Tag]? = [Tag]() @Attribute(.externalStorage) var images: [Data] = [Data]() init( content: String = "", dateCreated: Date = .now, dateUpdated: Date = .now, tags: [Tag] = [Tag](), images: [Data] = [Data]() ) { self.content = content self.dateCreated = dateCreated self.dateUpdated = dateUpdated self.tags = tags self.images = images } } But I discovered that led to a massive performance issue as soon as someone added a few images to a Memory. Maybe SwiftData isn't correctly putting an ARRAY of Data into external storage? My memory usage would just balloon with each photo added. All the examples I've seen just use a singular Data type for external storage, so not sure. Anyway, I played around with different options and figured out that a new MemoryPhoto struct was probably best, so I put the old model in a V1 schema and my NEW V2 model looks like this... enum DataSchemaV2: VersionedSchema { static var versionIdentifier = Schema.Version(2, 0, 0) static var models: [any PersistentModel.Type] { [Memory.self, Tag.self, MemoryPhoto.self] } @Model final class Memory { var content: String = "" var dateCreated: Date = Date.now var dateUpdated: Date = Date.now var tags: [Tag]? = [Tag]() @Relationship(deleteRule: .cascade) var photos: [MemoryPhoto]? = [MemoryPhoto]() @Attribute(.externalStorage) var images: [Data] = [Data]() init( content: String = "", dateCreated: Date = .now, dateUpdated: Date = .now, tags: [Tag] = [Tag](), images: [Data] = [Data](), photos: [MemoryPhoto] = [MemoryPhoto]() ) { self.content = content self.dateCreated = dateCreated self.dateUpdated = dateUpdated self.tags = tags self.images = images self.photos = photos } } @Model final class MemoryPhoto { @Attribute(.externalStorage) var originalData: Data? @Relationship(inverse: \Memory.photos) var memory: Memory? init(originalData: Data? = nil, memory: Memory? = nil) { self.originalData = originalData self.memory = memory } } Here's my migration, currently, which does work, because as best I can tell this is a lightweight migration... enum DataMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] { [DataSchemaV1.self, DataSchemaV2.self] } static var stages: [MigrationStage] { [migrateV1toV2] } static let migrateV1toV2 = MigrationStage.lightweight(fromVersion: DataSchemaV1.self, toVersion: DataSchemaV2.self) } But what I'm trying to figure out now is to migrate the former memory.images of type [Data] to the new memory.photos of type [MemoryPhoto], and been struggling. Any type of custom migration I do fails, sometimes inconsistently. I can try to get the exact errors if helpful but at this point not even a simple fetch to existing memories and updating their content as a part of the migration works. Is there a way to write a hypothetical V2 to V3 migration that just takes the images and puts them in the photos "slot"? For instance, what I do have working is this function that basically runs a "migration" or sorts when a given memory appears and it has the former images property. .... .onAppear { convertImagesToPhotos() } } private func convertImagesToPhotos() { guard !memory.images.isEmpty && memory.unwrappedPhotos.isEmpty else { return } let convertedPhotos = memory.images.map { imageData in MemoryPhoto(originalData: imageData) } memory.photos?.append(contentsOf: convertedPhotos) memory.images.removeAll() } Any help or pointers appreciated for this newbie swift developer. If helpful, here's the main App struct too... @main struct YesterdaysApp: App { @Environment(\.scenePhase) var scenePhase @AppStorage("writingRemindersEnabled") var writingRemindersEnabled: Bool = false let container: ModelContainer init() { do { container = try ModelContainer( for: Memory.self, migrationPlan: DataMigrationPlan.self ) } catch { fatalError("Failed to initialize model container.") } } var body: some Scene { WindowGroup { OuterMemoryListView() .yesterdaysPremium() } .modelContainer(container) } }
0
0
516
Dec ’23
iCloud Key-Value storage does not work for users with full iCloud
I have a flutter app I developed and some of the users cannot use our backup system which uses iCloud Key-Value storage. These users all have one thing in common. Full iCloud. If they turn off the app from iCloud from backup details page in iCloud settings then it works. But if their iCloud is 100% full and they can't even access the page then it does not work. Can someone tell me why this is happening? My app is made in flutter. It uses this package: https://pub.dev/packages/cloud_kit. Thanks.
0
0
262
Dec ’23
Cloudkit Error: "Invalid bundle ID for container"
I get the "Permission Failure" error ("Invalid bundle ID for container") below only when running my app from my iOS Target, and not my watchkit target. The watch app is able to sync/create/delete items, but my iOS target is unable to even read the data from the cloud. The cloudkit Container ID matches my iOS Target Bundle ID, which is the apps Bundle ID. Looking at the output of CKContainer, the container matches the iOS Bundle ID. I have tried reseting multiple times, creating different cloud containers, reseting the Signing and Capabilites online. It always results in the same issue... What am I missing here? <CKError 0x281b69590: "Partial Failure" (2/1011); "Failed to modify some record zones"; uuid = D57676F8-455E-4039-9DF4-824E3BAD42BE; container ID = "iCloud.companyName.AppName"; partial errors: { com.apple.coredata.cloudkit.zone:__defaultOwner__ = <CKError 0x281b771e0: "Permission Failure" (10/2007); server message = "Invalid bundle ID for container"; op = 8CCAD43B495AADC0; uuid = D57676F8-455E-4039-9DF4-824E3BAD42BE> }>
1
0
705
Dec ’23
CKModifyRecordsOperation records limit?
I'm trying to delete many records with one CKModifyRecordsOperation and getting this error: <CKError 0x600000dbe4f0: "Limit Exceeded" (27/1020); "Your request contains 552 items which is more than the maximum number of items in a single request (400)"> This obviously means, that Modify Operation has record limit of 400 which is equal to CKQueryOperation.maximumResults. The good solution here would be to chunk the array of records into subarrays with length less than 400 and add multiple delete operations to the database. The only problem is that the limit for CKModifyRecordsOperation is neither documented nor provided with a constant, so it's basically a magic number. In hope that my prayers would be heard I want to ask to add maximumResults constant to CKModifyRecordsOperation.
3
0
699
Dec ’23
SwiftData Unexpected type for CompositeAttribute
I'm getting SwiftData/SchemaProperty.swift:369: Fatal error: Unexpected type for CompositeAttribute CLLocationCoordinate2D in the following situation - this is simplified, but demonstrates the issue. There are a lot of posts discussing Measurements running into the same issue, and the recommended fix is to turn the Measurement (or CLLocationCoordinate2D in this example) into a computed property and generate it on the fly. I'm trying to cache instances of CLLocationCoordinate2D, rather than creating new ones every time a View renders, so those work arounds don't work around. The SwiftData docs seem to indicate that this should be possible. Can anyone recommend a fix? Thanks in advance. import SwiftData import MapKit @Model final class foo : Codable { var bar: SomeStruct init( bar: SomeStruct ) { self.bar = bar } enum CodingKeys : CodingKey { case bar } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.bar = try container.decode(SomeStruct.self, forKey: .bar) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(bar, forKey: .bar) } } struct SomeStruct : Codable { var latitude: Double var longitude: Double @Transient var clLocation: CLLocationCoordinate2D init(latitude: Double, longitude: Double) { self.latitude = latitude self.longitude = longitude self.clLocation = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) } enum CodingKeys : CodingKey { case latitude, longitude } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.latitude = try container.decode(Double.self, forKey: .latitude) self.longitude = try container.decode(Double.self, forKey: .longitude) self.clLocation = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(latitude, forKey: .latitude) try container.encode(longitude, forKey: .longitude) } }
4
0
1.1k
Dec ’23