Posts

Post not yet marked as solved
0 Replies
183 Views
I currently have a production app that uses CloudKit I always struggle with testing the data within the development container and I was wondering if someone could share their current workflow. What is your current workflow when testing apps that use CloudKit, do you use your regular Apple User account for testing, or you use separate account? My concern is because I use my production app on a daily basis using my regular Apple user account, so I would like to keep the production iCloud data intact. In other words, I have my app on my phone with real data and now I need to test the app because there are some CloudKit syncing issues so I have the following questions. Can I connect my phone with production data to Xcode and use my regular Apple account for testing purposes? Will I be able to see the testing data in the CloudKit console? Will the production data merge with the testing data? I actually created a second Apple account thinking that I could use it for testing but logging off and logging back on to iCloud in your iPhone it's a pain, is this really what needs to be done? Any ideas would be greatly appreciated. Thanks
Posted
by fsdolphin.
Last updated
.
Post marked as solved
4 Replies
647 Views
Is there a way to remove or resize the image from the tag in the Picker view? Picker("", selection: $selectedCategory) { ForEach(categorySM.categories, id: \.self) { category in HStack { if let inputImage = UIImage(data: category.image ?? Data()) { Image(uiImage: inputImage) .resizable() .scaledToFit() } Text(category.name ?? "") } .tag(category as CategoryItem?) } } .font(.callout) .pickerStyle(.menu) As you can see in images 1 and 2 below, the image in the tag from the Beverages category is huge and covers almost the entire screen, it also covers the category name (Beverages). Is there a way to remove or resize the image when displaying it on the tag? Basically to make it look like image #3. Image Link: https://i.stack.imgur.com/4XpjI.jpg
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
3 Replies
641 Views
I have a Core Data container with two entities, a Category and an Item. The Item can have one Category assigned and the Category can be assigned to many Items. What I need to do is group the items by category in a list in SwiftUI. The code below doesn't group all items by category, it only shows one item by category. How can I group all items that have the same category assigned under the same category group? Core Data Entities Category Attributes name Relationship items (Type: To Many) Item Attributes name Relationship category (Type: To One) Swiftui struct ItemsView: View { let selectedList:List @EnvironmentObject private var itemSM: ItemServiceModel var body: some View { List { ForEach(itemSM.items) { item in Section(header: Text(item.category?.name ?? "")) { ForEach(itemSM.items.filter { $0.category == item.category }) { filteredItem in Text("\(filteredItem.name ?? "")") } } } } .onAppear{ itemSM.loadItems(forList: selectedList) } } } Service Item Service Model class ItemServiceModel: ObservableObject{ let manager: CoreDataManager @Published var items: [Item] = [] func loadItems(forList list: List){ let request = NSFetchRequest<Item>(entityName: "Item") let sort = NSSortDescriptor(keyPath: \Item.name, ascending: true) request.sortDescriptors = [sort] let filter = NSPredicate(format: "list == %@", list) request.predicate = filter do{ items = try manager.context.fetch(request) }catch let error{ print("Error fetching items. \(error.localizedDescription)") } } } This is what I see, as you can see, only one Fruits & Vegetables section should exist.
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
0 Replies
300 Views
Hi, I'm trying to understand how TestFlight works since a major update of my app is coming soon. I currently have an app in the app store with a few thousand users, the current app was written in UIKit and I'm now rewriting it in SwiftUI and making major updates such as, moving from Realm to Core Data and allowing iCloudSync etc. I don't have users emails, only from the people who have contacted me with questions so, I was wondering if I could somehow invite users to test the new version without having their emails. Can someone please describe the typical process when using TestFlight? Would the following process be considered a good practice? Add a message in the existing app to invite users by asking for their email so they can join TestFlight at a later date. Release a new Beta version in TestFlight. Invite the users who subscribed via the old app. Release to production after users test it. Thanks
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
2 Replies
468 Views
I need some help understanding how the public database works in CloudKit. First of all, let me say that I know how to connect and use the private database. In this question I'm not looking for an answer on how to connect to the database at self, only the concept. Here is my confusion. I have a set of images that all users in my app will be using, right now what I'm doing is adding the images directly to the app (an Image Set in Xcode) and then I am pulling them to Core Data and then syncing them to CloudKit. As you can see all images are technically stored in every device using my app and in Core Data/CloudKit, not very efficient. What I would like is to have the images stored in a single place where all uses can pull the images from, in this case CloudKit. I know I can have them somewhere in a private server, but I feel like I would be adding more complexity to my app, so I think using CloudKit is a better option for me. Here is my question. How do I get the images to CloudKit, do I upload them directly to CloudKit and then read from all devices or do I need to first add them to a device and upload to CloudKit from there? Thanks!
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
0 Replies
657 Views
Can someone please help me understand PassthroughSubject and CurrentValueSubject? What I understand so far is that they are subjects where subscribers can listen to changes made to these subjects, but I'm really straggling to understand the following. I'm I correct by saying that PassthroughSubject or CurrentValueSubject could replace delegation and asynchronous function calls? Is it possible to delare a subject in Class A and subscribe to listen to those subject changes in Class B and in some other classes or are listeners meant to only be used direclty in SwiftUI structs? Thanks
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
2 Replies
1.5k Views
Can someone please shed some light? I have an app that uses Core Data and CloudKit, up until the last version, I was able to sync data between devices but now after I added two new Entities for some reason it stopped syncing between devices. Here is how I did the change: Created a new Core Data container. Added the new Entities and their Attributes Tested the new Entities locally to be able to send the new schema to CloudKit. Went to CloudKit and made sure that the new Entities and Attributes were reflected on the Developent database. Deploy Schema Cahnges. Went to the Production database to make sure the new schema was deployed; and it was, both databases look the same. Testing: Tested in the simulator and with a real device and everything syncs, even the new Entities. If I download the app from the App Store on two different devices they do NOT sync. Based on the procedure I'm describing above, is there any important step I may have missed when doing the migration? I'm not sure if this is related to the syncing issue but after testing a few times, I no longer can turn the iCloud on, I get the following message when I try to turn iCloud Sync On. CoreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate resetAfterError:andKeepContainer:]: <NSCloudKitMirroringDelegate: 0x282c488c0> - resetting internal state after error: Error Domain=NSCocoaErrorDomain Code=134410 "CloudKit setup failed because there is another instance of this persistent store actively syncing with CloudKit in this process." UserInfo={NSURL=file:///var/mobile/Containers/Data/Application/73F19BC7-4538-4098-85C7-484B36192CF3/Library/Application%20Support/CoreDataContainer.sqlite, NSLocalizedFailureReason=CloudKit setup failed because there is another instance of this persistent store actively syncing with CloudKit in this process., NSUnderlyingException=Illegal attempt to register a second handler for activity identifier com.apple.coredata.cloudkit.activity.setup.8D4C04F6-8040-445A-9447-E5646484521} Any idea of what could be wrong and preventing the devices from syncing? Any idea or suggestion is welcome. Thanks
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
0 Replies
474 Views
In the following code, I'm saving and syncing objects in Core Data and CloudKit, everything is working fine, once the user creates some objects, the data starts syncing as soon as the user turns the Toggle switch On in the SettingsView. The issue I'm having is that the data continue syncing even after the switch is turned Off until I kill and relaunch the app. After relaunching the app, the data stops syncing. Any idea what could I do to make sure that the data stops syncing as soon as the toggle switch is turned off? Again, everything would work fine if the user would kill and relaunch the app right after turning it off, the data stops syncing. I thought that by calling carViewModel.updateCloudKitContainer() right after turning it off would do the trick since I'm disabling the CloudKit container by making it nil, description.cloudKitContainerOptions = nil but obviously is not enough. Core Data Manager class CoreDataManager{ // Singleton static let instance = CoreDataManager() @AppStorage(UserDefaults.Keys.iCloudSyncKey) private var iCloudSync = false static var preview: CoreDataManager = { // Create preview objects do { try viewContext.save() } catch { } return result }() lazy var context: NSManagedObjectContext = { return container.viewContext }() lazy var container: NSPersistentContainer = { return setupContainer() }() init(inMemory: Bool = false){ /// for preview purposes only, remove if no previews are needed. if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") } } func setupContainer()->NSPersistentContainer{ print("Assgning persistent container... ") let container = NSPersistentCloudKitContainer(name: "CoreDataContainer") guard let description = container.persistentStoreDescriptions.first else{ fatalError("###\(#function): Failed to retrieve a persistent store description.") } description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) if iCloudSync{ let cloudKitContainerIdentifier = "iCloud.com.sitename.myApp" let options = NSPersistentCloudKitContainerOptions(containerIdentifier: cloudKitContainerIdentifier) description.cloudKitContainerOptions = options }else{ description.cloudKitContainerOptions = nil // turn cloud sync off } container.loadPersistentStores { (description, error) in if let error = error{ print("Error loading Core Data. \(error)") } } container.viewContext.automaticallyMergesChangesFromParent = true container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy return container } func save(){ do{ try context.save() }catch let error{ print("Error saving Core Data. \(error.localizedDescription)") } } } View Model class CarViewModel: ObservableObject{ let manager: CoreDataManager @Published var cars: [Car] = [] init(coreDataManager: CoreDataManager = .instance){ self.manager = coreDataManager loadCars() } func updateCloudKitContainer(){ manager.container = manager.setupContainer() } func addCar(model:String, make:String?){ // create car save() loadCars() } func deleteCar(car: Car){ // delete car save() loadCars() } func loadCars(){ let request = NSFetchRequest<Car>(entityName: "Car") let sort = NSSortDescriptor(keyPath: \Car.model, ascending: true) request.sortDescriptors = [sort] do{ cars = try manager.context.fetch(request) }catch let error{ print("Error fetching businesses. \(error.localizedDescription)") } } func save(){ self.manager.save() } } Settings View to Turn ClouldKit ON and OFF struct SettingsView: View { @ObservedObject var carViewModel:CarViewModel @AppStorage(UserDefaults.Keys.iCloudSyncKey) private var iCloudSync = false var body: some View { VStack{ Toggle(isOn: $iCloudSync){// turns On and Off sync HStack{ Image(systemName: iCloudSync ? "arrow.counterclockwise.icloud" : "lock.icloud") .foregroundColor(Color.fsRed) Text(" iCloud Sync") } } .tint(Color.fsRed) .onChange(of: iCloudSync){ isSwitchOn in if isSwitchOn{ iCloudSync = true carViewModel.updateCloudKitContainer() }else{ iCloudSync = false // turn Off iCloud Sync carViewModel.updateCloudKitContainer() } } } } } Display Cars View struct CarsView: View { @ObservedObject var carViewModel:CarViewModel // Capture NOTIFICATION var didRemoteChange = NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange).receive(on: RunLoop.main) var body: some View { NavigationView{ VStack{ List { ForEach(carViewModel.cars) { car in HStack{ VStack(alignment:.leading){ Text(car.model ?? "") .font(.title2) Text(car.make ?? "") .font(.callout) } } .swipeActions { Button( role: .destructive){ deleteCar = car showDeleteActionSheet = true }label:{ Label("Delete", systemImage: "trash.fill") } } } } .navigationBarTitle("Cars") .onAppear{ carViewModel.loadCars() } // reload cars on NOTIFICATION .onReceive(self.didRemoteChange){ _ in carViewModel.loadCars() } } } } }
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
0 Replies
917 Views
I have the following UIKit animation inside a UIViewRepresentable which works fine, it animates a view in a throwing effect like animation from point A to point B. What I would like to be able to do is, set the start and the end position in ContentView when assigning the animation to a view. Here is the code... Static Position Animation import SwiftUI struct ContentView: View { @State private var isAnimating = false var body: some View { HStack{ Image(systemName: "circle.fill") .font(.system(size: 65)) .foregroundColor(.blue) .throwAnimation(isAnimating: $isAnimating) .onTapGesture { isAnimating.toggle() } } } } struct ThrowAnimationWrapper<Content: View>: UIViewRepresentable{ @ViewBuilder let content: () -> Content @Binding var isAnimating: Bool func makeUIView(context: Context) -> UIView { UIHostingController(rootView: content()).view } func updateUIView(_ uiView: UIView, context: Context) { if isAnimating{ UIView.animateKeyframes(withDuration: 1.5, delay: 0.0, options: [.calculationModeCubic], animations: { UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.2, animations: { uiView.center = CGPoint(x: 250, y: 300) // how can I make this dynamic }) UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.9, animations: { uiView.center = CGPoint(x: 100 + 75, y: 100 - 50 ) uiView.transform = CGAffineTransform(scaleX: 0.75, y: 0.75) }) UIView.addKeyframe(withRelativeStartTime: 0.1, relativeDuration: 0.7, animations: { uiView.center = CGPoint(x: 100, y: 100)// how can I make this dynamic uiView.transform = CGAffineTransform(scaleX: 0.2, y: 0.2) }) }, completion: { _ in uiView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0) }) } } } extension View { func throwAnimation( isAnimating: Binding<Bool>) -> some View { modifier(ThrowAnimationViewModifier(isAnimating: isAnimating)) } } struct ThrowAnimationViewModifier: ViewModifier { @Binding var isAnimating: Bool func body(content: Content) -> some View { ThrowAnimationWrapper(content: { content }, isAnimating: $isAnimating) } } How I would like to be able to call it from ContentView @State private var isAnimating = false var body: some View { HStack{ Image(systemName: "circle.fill") .font(.system(size: 65)) .foregroundColor(.blue) .throwAnimation(isAnimating: $isAnimating, startPos:CGPoint(x: 250, y: 300), endPos:CGPoint(x: 100, y: 100)) .onTapGesture { isAnimating.toggle() } } } } How can I modify this code in a way that I can enter the start and end position when assigning to a view? Thanks!
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
0 Replies
360 Views
Hi, a Service class where I process all Core Data transactions for a single entity/Object and I often find my self needing to access information from other classes and I was wondering if there was an issue by calling these classes in non-UI related classes. In the following code I'm calling the dogs array from the DogService class inside the DogHouseService class, and I was wondering if this could be an issue. Are there any possible issue by calling @Published properties from an ObservableObject class inside other classes? ObservableObject class class DogService: ObservableObject{ let manager: CoreDataManager @Published var dogs: [Dog] = [] init(coreDataManager: CoreDataManager = .instance){ self.manager = coreDataManager loadDogs() } //Adds, Deletes, Updates, etc. func loadDogs(){ let request = NSFetchRequest<Dog>(entityName: "Dog") do{ dogs = try manager.context.fetch(request) }catch let error{ print("Error fetching dogs. \(error.localizedDescription)") } } func save(){ self.manager.save() } } Other Class class DogHouseService{ let dogService = DogService() for dog in dogService.dogs{ // do something } }
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
2 Replies
1.3k Views
Hi, I would like to have a better understanding of Dependency Injection, in general, to start using it. Based on the three examples below, can someone please point out what would be the pros and the cons of using one over the other? 1 - What problem could Example 1 cause if I don't do unitest? This is my current method. 2- What method of Dependency Injection is best to adopt, Example 2 ro Example 3? 3- I noticed that Example 2 enforces to provided the dependency object at instantiation time whereas Example 3 does not. Couldn't Example 3 create confusion for the programmer since if you don't provide the dependency object, the code will still compile without any warning if you call a function that relies on a method inside the injected object? Example 1: Without Dependency Injection class Stereo{ func volume(){ print("Adjusting volume...") } } class Car{ var stereo = Stereo() func adjustVolume(){ stereo.volume() } } let car = Car() car.adjustVolume() Example 2: With Dependency Injection class Stereo{ func volume(){ print("Adjusting volume...") } } class Car{ var stereo: Stereo init(stereo: Stereo){ self.stereo = stereo } func adjustVolume(){ stereo.volume() } } let car = Car(stereo: Stereo()) car.adjustVolume() Example 3: With Optional Dependency Injection class Stereo{ func volume(){ print("Adjusting volume...") } } class Car{ var stereo: Stereo? func adjustVolume(){ stereo?.volume() } // this method can be called without injecting Stereo func someOtherFunction(){ print("Calling some other function...") } } let car = Car() car.stereo = Stereo() car.adjustVolume() Thanks
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
0 Replies
735 Views
In the following code, I have a LocationManager class which provides the city name of the current location via the @Published property wrapper lastSearchedCity. Then I have a SearchManagerViewModel class that should be in charge of presenting the city name on SwiftUI views based on some conditions (not currently shown in the code below) via the @Published property wrapper cityName. It properly shows the city name when I call the searchAndSetCity() method from ContentView.swift inside an onAppear modifier. My issue is that if the user turned Location Services off and turns it back On while he/she is in the ContentView.swift the Text view doesn't update, which is understandable since the searchAndSetCity() method would need to be called again. How can I call the searchAndSetCity() method located inside the SearchManagerViewModel class every time the locationManagerDidChangeAuthorization(_ manager: CLLocationManager) method is called? I believed this method is called every time the authorization status changes. LocationManager Class final class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { private let locationManager = CLLocationManager() @Published var lastSearchedCity = "" var hasFoundOnePlacemark:Bool = false func checkIfLocationServicesIsEnabled(){ DispatchQueue.global().async { if CLLocationManager.locationServicesEnabled(){ self.locationManager.delegate = self self.locationManager.desiredAccuracy = kCLLocationAccuracyBest/// kCLLocationAccuracyBest is the default self.checkLocationAuthorization() }else{ // show message: Services desabled! } } } private func checkLocationAuthorization(){ switch locationManager.authorizationStatus{ case .notDetermined: locationManager.requestWhenInUseAuthorization() case .restricted: // show message case .denied: // show message case .authorizedWhenInUse, .authorizedAlways: /// app is authorized locationManager.startUpdatingLocation() default: break } } func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { checkLocationAuthorization() } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { hasFoundOnePlacemark = false CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)-> Void in if error != nil { self.locationManager.stopUpdatingLocation() // show error message } if placemarks!.count > 0 { if !self.hasFoundOnePlacemark{ self.hasFoundOnePlacemark = true let placemark = placemarks![0] self.lastSearchedCity = placemark.locality ?? "" } self.locationManager.stopUpdatingLocation() }else{ // no places found } }) } } SearchManagerViewModel Class class SearchManagerViewModel: ObservableObject{ @Published var cityName = "" // use this directly in SwifUI views @ObservedObject private var locationManager = LocationManager() // Call this directly fron onAppear in SwiftUI views // This method is more complex than what is shown here. It handles other things like HTTP requests etc. func searchAndSetCity(){ locationManager.checkIfLocationServicesIsEnabled() self.cityName = locationManager.lastSearchedCity } } ContentView.swift struct ContentView: View { @StateObject private var searchManager = SearchManagerViewModel() var body: some View { VStack { Text(searchManager.cityName) .font(.callout) } .onAppear{ searchManager.searchAndSetCity() } } }
Posted
by fsdolphin.
Last updated
.
Post not yet marked as solved
1 Replies
543 Views
Any idea why if I tap on Field 1 and immediately after I tap on Field 5, Field 5 gets hidden by the keyboard? To replicate my issue, copy and paste the code below, run it in the simulator and make sure the Toggle Software Keybaord is checked, then go and tap on Field 1 and then on Field 5. I tried wrapping the fields in a List and I got the same result. It almost feels like a bug. The issue seems to occur when moving from the regular .default keyboard type to the .decimalPad keyboard. import SwiftUI struct TextFieldScrollingIssue: View {   @State private var testInput:String = ""   @State private var decimalInput:String = ""       var body: some View {     VStack{       Form {         TextField("Field 1", text:$testInput)           .id("Field 1")           .keyboardType(.default)         Spacer()         Spacer()         Spacer()         Spacer()         Spacer()         Spacer()         Section(header: Text("Section 2: ")) {           TextField("Field 2", text:$testInput)             .id("Field 2")             .keyboardType(.decimalPad)                       TextField("Field 3", text:$decimalInput)             .id("Field 3")             .keyboardType(.decimalPad)         }                   Section(header: Text("Section 3: ")) {           TextField("Field 4", text:$testInput)             .id("Field 4")             .keyboardType(.default)                       TextField("Field 5", text:$decimalInput)             .id("Field 5")             .keyboardType(.decimalPad)         }       }     }   } } struct TextFieldScrollingIssue_Previews: PreviewProvider {   static var previews: some View {     TextFieldScrollingIssue()   } }
Posted
by fsdolphin.
Last updated
.
Post marked as solved
2 Replies
1.1k Views
I have a SwiftUI app that uses CloudKit and Core data to sync data between devices. Everything works fine when testing on devices in Xcode but not in production in the App Store. Can someone explain the typical process when deploying an app that uses CoreData + CloudKit? Is there anything that needs to be done in code or in the CloudKit Console before the app is uploaded to the App Store? Again, my issue is that data doesn't sync when trying to sync data between multiple devices in production but works fine when testing in Xcode. Thanks
Posted
by fsdolphin.
Last updated
.
Post marked as solved
7 Replies
973 Views
I have a code that needs to be ran about every year to update some files at the app launch and I'm trying to come up with the best way to do that. What I need to be able to basically force the app to run the code whenever I need to update the files. This is what I came up with that I think would work but I'm not sure if that's the best way. Are there any other options to handle this type of logic? App version 1 - INITIAL RELASE. This code would work as long as I don't add an update. // First launch @main struct SwifUIPlayGroundApp: App { @AppStorage("shouldLoad") var shouldLoad = true init(){ if shouldLoad{ print("Loading...") shouldLoad = false }else{ print("No need to relaod...") } } } App version 2 - UPDATE 1. Here I would need to add a second variable to force the update shouldUpdate. I would also need to change the logic to check for the shouldUpdate instead of the shouldLoad and set the shouldLoad to true to be prepared for future updates. // UPDATE 1 @main struct SwifUIPlayGroundApp: App { @AppStorage("shouldUpdate") var shouldUpdate = true // new @AppStorage("shouldLoad") var shouldLoad = true init(){ if shouldUpdate{ print("Loading...") shouldUpdate = false shouldLoad = true // prepare for next update }else{ print("No need to relaod...") } } } App version 3 - UPDATE 2. Here I would need to change the logic back to check for the shouldLoad instead of the shouldUpdate and set the shouldUpdate to true to be prepared for future updates. // UPDATE 2 @main struct SwifUIPlayGroundApp: App { @AppStorage("shouldUpdate") var shouldUpdate = true @AppStorage("shouldLoad") var shouldLoad = true init(){ if shouldLoad{ print("Loading...") shouldUpdate = true // prepare for next update shouldLoad = false }else{ print("No need to relaod...") } } } App version 4 - UPDATE 3. Repeat what I did in UPDATE 1...
Posted
by fsdolphin.
Last updated
.