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()
}
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I'm currently syncing core data with the CloudKit private and public databases, as you can see in the code below, I'm saving the private database in the default configuration in Core Data and the public in a configuration called Public everything works fine when NSPersistentCloudKitContainer syncs, what I'm having an issue with is trying to save to the public data store PublicStore, for instance when I try to save with func createIconImage(imageName: String) it saves the image to the "default" store, not the PublicStore(Public configuration).
What could I do to make the createIconImage() function save to the PublicStore sqlite database?
class CoreDataManager: ObservableObject{
static let instance = CoreDataManager()
private let queue = DispatchQueue(label: "CoreDataManagerQueue")
@AppStorage(UserDefaults.Keys.iCloudSyncKey) private var iCloudSync = false
lazy var context: NSManagedObjectContext = {
return container.viewContext
}()
lazy var container: NSPersistentContainer = {
return setupContainer()
}()
init(inMemory: Bool = false){
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
}
func updateCloudKitContainer() {
queue.sync {
container = setupContainer()
}
}
private func getDocumentsDirectory() -> URL {
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
}
private func getStoreURL(for storeName: String) -> URL {
return getDocumentsDirectory().appendingPathComponent("\(storeName).sqlite")
}
func setupContainer()->NSPersistentContainer{
let container = NSPersistentCloudKitContainer(name: "CoreDataContainer")
let cloudKitContainerIdentifier = "iCloud.com.example.MyAppName"
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{
if description.cloudKitContainerOptions == nil {
let options = NSPersistentCloudKitContainerOptions(containerIdentifier: cloudKitContainerIdentifier)
description.cloudKitContainerOptions = options
}
}else{
print("Turning iCloud Sync OFF... ")
description.cloudKitContainerOptions = nil
}
// Setup public database
let publicDescription = NSPersistentStoreDescription(url: getStoreURL(for: "PublicStore"))
publicDescription.configuration = "Public" // this is the configuration name
if publicDescription.cloudKitContainerOptions == nil {
let publicOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: cloudKitContainerIdentifier)
publicOptions.databaseScope = .public
publicDescription.cloudKitContainerOptions = publicOptions
}
container.persistentStoreDescriptions.append(publicDescription)
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()
//print("Saved successfully!")
}catch let error{
print("Error saving Core Data. \(error.localizedDescription)")
}
}
}
class PublicViewModel: ObservableObject {
let manager: CoreDataManager
@Published var publicIcons: [PublicServiceIconImage] = []
init(coreDataManager: CoreDataManager = .instance) {
self.manager = coreDataManager
}
func createIconImage(imageName: String) {
let newImage = PublicServiceIconImage(context: manager.context)
newImage.imageName = imageName
newImage.id = UUID()
save()
}
func save() {
self.manager.save()
}
}
Hi,I reciently rewrote on of my apps in Swift and the way I did it is I started from scratch creating a brand new project and what I'm trying to do is to upload this new project as a new version of an existing app in the Appstore.Is this possible to do? If yes, what is the process?Thanks
Can someone please explain why the first time I tap on an item from the list, the selectedItem?.name becomes nil? The second time it shows the right item name correctly but not the first time, why?. I was expecting that to have a value even the first time since I'm setting it in the onTapGesture method selectedItem = item.
// model
struct Item: Identifiable{
var id = UUID()
var name:String
}
// SwiftUI
struct UpdateStateProperty: View {
var items:[Item] = [Item(name: "Oranges"),
Item(name: "Apples"),
Item(name: "Cookies") ]
@State private var presentView = false
@State private var selectedItem: Item?
var body: some View {
List{
ForEach(items){ item in
HStack{
Text(item.name)
}.onTapGesture {
selectedItem = item
presentView.toggle()
}
}
}
.sheet(isPresented: $presentView){
Text("\(selectedItem?.name)" as String)
}
}
}
I'm trying to give the user the ability to decide whether they want to sync to CloudKit or not by turning On or Off a Switch located somewhere in the app settings screen but I'm not sure how to do it in SwiftUI.
The following code successfully stops the sync to CloudKit by setting the cloud kit container options to nil description.cloudKitContainerOptions = nil.
class CoreDataManager{
static let instance = CoreDataManager()
let container: NSPersistentCloudKitContainer
let context: NSManagedObjectContext
init(){
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)
description.cloudKitContainerOptions = nil
container.loadPersistentStores { (description, error) in
if let error = error{
print("Error loading Core Data. \(error)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
context = container.viewContext
}
func save(){
do{
try context.save()
print("Saved successfully!")
}catch let error{
print("Error saving Core Data. \(error.localizedDescription)")
}
}
}
What I ultimately want is to be able to control the syncing process with an @AppStore property or some sort of property, something like this...
class CoreDataManager{
@AppStorage("iCloudSync") private var iCloudSync = false
//missing code...
init(){
if !iCloudSync{
description.cloudKitContainerOptions = nil
}
}
//missing code...
}
But I'm facing a couple of issues, one, I'm getting an error when using the iCloudSync wrapper variable and the second one and the most difficult for me to solve is
the fact that I need to make the persistent storage reload when the switch changes from On to Off of vise-versa.
Any idea how can I structure my code so I can control the syncing process and be able to reload the persistent storage when the switch changes?
By the way and just for reference, here is how I'm using the CoreDataManager class in my view model.
class CarViewModel: ObservableObject{
let manager = CoreDataManager.instance
@Published var cars: [Car] = []
init(){
getCars()
}
func addCar(){}
func getCars(){}
func deleteCar(){}
func save(){
self.manager.save()
}
}
I have a SwiftUI app with 3 Core Data entities, Car, CarService and ServiceRecord where Car has many carServices and each CarService has many serviceRecords. Everything is working fine but I'm not sure what's the most common MVVM practice.
As you can see in the following example I'm using CoreDataViewModel to fetch data from Core Data and then I pass it around all SwiftUI views, at the moment I don't have a ViewModel for the view's logic (the logic is currently inside of each view) but that's something I would like to incorporate, but I'm not sure what would be the best way to do that. I'm thinking about the two following option...
Create a view model for each view (CarViewModel, ServicesViewModel and RecordsViewModel) to handle ONLY the view's logic and leave the existing CoreDataViewModel as is.
Create a view model for each view, CarViewModel, ServicesViewModel and RecordsViewModel to handle the logic for each view and move the CoreData quests to each of the view models respectably and basically delete CoreDataViewModel altogether since now the core data related will live inside each view model.
Which of the two options above makes more sense for an MVVM app?
In general, can someone please share how you usually structure your code when using MVVM + CoreData + SwiftUI?
CoreDataManager
class CoreDataManager{
static let instance = CoreDataManager()
lazy var context: NSManagedObjectContext = {
return container.viewContext
}()
lazy var container: NSPersistentContainer = {
return setupContainer()
}()
func setupContainer()->NSPersistentContainer{
// code to setup container...
return container
}
func save(){
do{
try context.save()
}catch let error{
print("Error saving Core Data. \(error.localizedDescription)")
}
}
}
CoreDataViewModel
class CoreDataViewModel: ObservableObject{
let manager: CoreDataManager
@Published var cars: [Car] = []
@Published var carServices: [CarService] = []
@Published var serviceRecords: [ServiceRecord] = []
init(coreDataManager: CoreDataManager = .instance){
self.manager = coreDataManager
// getCars() etc.
}
// CREATIONS
func addCar(name:String){}
func addService(name:String, cost: Double){}
func createRecord(name:String, cost: Double){}
// DELETES
func deleteCar(){}
func deleteCarService(){}
func deleteServiceRecord(){}
// UPDATES
func updateCar(){}
func updateService(){}
// GETS
func getCars(){}
func getServices(){}
func getRecords(){}
func save(){
self.manager.save()
}
}
SwiftUI Views
CarsView
struct CarsView: View {
@StateObject var coreDataViewModel = CoreDataViewModel()
var body: some View {
NavigationView{
VStack{
List {
ForEach(coreDataViewModel.cars) { car in
}
}
}
}
}
}
ServicesView
struct ServicesView: View {
@ObservedObject var coreDataViewModel:CoreDataViewModel
var body: some View {
NavigationView{
VStack{
List {
ForEach(coreDataViewModel.carServices) { service in
}
}
}
}
}
}
RecordsView
struct RecordsView: View {
@ObservedObject var coreDataViewModel: CoreDataViewModel
var body: some View {
NavigationView{
VStack{
List {
ForEach(coreDataViewModel.serviceRecords) { record in
}
}
}
}
}
}
Thanks!
Hi, I recently had an issue with one of my production apps that use Core Data and CloudKit where data wasn't syncing between devices, after a little bit of research I found out that the schema in the private CloudKit container needed to be initialized; which I never did.
The part I'm still not 100% sure is when to run the initializeCloudKitSchema method after the app has been released to the AppStore. I see that Apple recommends running it when testing by using #if DEBUG, but... do you really want to run it every time you compile in Xcode?
Here is how I understand it at this point...
App release, call initializeCloudKitSchema() to match schemas between Core Data and CloudKit.
Added or deleted an attribute, call initializeCloudKitSchema() to update the CloudKit schema.
Renamed an attribute, call initializeCloudKitSchema() to update the CloudKit schema.
Etc.
If my assumption above is correct, calling the initializeCloudKitSchema() method during development would update the schema in CloudKit before the new app version is released in the AppStore, therefore creating an issue for existing users with previous versions of the app since they will not have the latest code but will be using the latest schema which contains the new attributes.
Can someone please share their method of handling schema updates in CloudKit after the app has been released to the AppStore?
Code:
do {
try container.initializeCloudKitSchema()
} catch {
print(error)
}
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
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!
Now with Dark Mode I have been creating color assets to manage dark mode colors, but sometimes I think of a more semantic name for a certain color after I have used it in multiple places and I was wondering if there is a way to find where a color has been used even if I have to go and manually changed them, I'm not really looking for an automatic solution.Is there a way to rename or find all of the instances where a custom color asset has been used in Xcode?Thanks!
Hi all,I know this is may not be the right forum to post questions about Realm but my issue has to do with the nature of how SwiftUI works.Has anyone been able to successfully integrate Realm with SwiftUI, especially deleting records/rows from a SwiftUI List? I have tried a few different things but no matter what I do I get the same error. After reading some related threads I found out that other people have the same issue but I refuse to think that there is no current solution to integrate Realm with SwiftUI.The following code successfully presents all of the items from Realm in a SwiftUI List, I can create new ones and they show up in the List as expected, my issues is when I try to delete records from the List by either manually pressing a button or by left-swiping to delete the selected row, I get an Index is out of bounds error.Here is my code.Realm Model:class Dog: Object {
@objc dynamic var name = ""
@objc dynamic var age = 0
@objc dynamic var createdAt = NSDate()
@objc dynamic var userID = UUID().uuidString
override static func primaryKey() -> String? {
return "userID"
}
}SwiftUI Code:class BindableResults: ObservableObject where Element: RealmSwift.RealmCollectionValue {
var results: Results
private var token: NotificationToken!
init(results: Results) {
self.results = results
lateInit()
}
func lateInit() {
token = results.observe { [weak self] _ in
self?.objectWillChange.send()
}
}
deinit {
token.invalidate()
}
}
struct DogRow: View {
var dog = Dog()
var body: some View {
HStack {
Text(dog.name)
Text("\(dog.age)")
}
}
}
struct ContentView : View {
@ObservedObject var dogs = BindableResults(results: try! Realm().objects(Dog.self))
var body: some View {
VStack{
List{
ForEach(dogs.results, id: \.name) { dog in
DogRow(dog: dog)
}.onDelete(perform: deleteRow )
}
Button(action: {
try! realm.write {
realm.delete(self.dogs.results[0])
}
}){
Text("Delete User")
}
}
}
private func deleteRow(with indexSet: IndexSet){
indexSet.forEach ({ index in
try! realm.write {
realm.delete(self.dogs.results[index])
}
})
}
}ERRORTerminating app due to uncaught exception ‘RLMException’, reason: ‘Index 23 is out of bounds (must be less than 23).’Of course, the 23 changes depending on how many items are in the Realm database, in this case, I had 24 records when I swiped and tapped the delete button.
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
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
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.
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