Hi, I have a SwiftUI ProgressBar View that displays the percentage progress based on a percentage-value you enter as a Bindable parameter. The progress percentage-value is calculated by a ReminderHelper class, which takes two Ints as its parameters, totalDays and daysLeft, the values input to the ReminderHelper class come from a Reminder object saved in Core Data.
I'm very confused as to how to structure my code to accomplish such of thing due to the poor understanding of how the SwiftUI/Combine, @Binding, @Published, @State, etc. work.
Based on the code below, what I'm expecting to see is two reminders, Cut the Grass at 20% and Power Wash Siding at 50%. Again, the two Ints that determine the total percentage progress come from the Reminder object saved in Core Data and the actual total percentage result comes from the RemindersHelper class.
Any idea how to accomplish what I describe above?
Model:
This is saved in Core Data.
class Reminder:Identifiable{
var name = ""
var totalDays = 0
var daysLeft = 0
init(name:String, totalDays:Int, daysLeft:Int){
self.name = name
self.totalDays = totalDays
self.daysLeft = daysLeft
}
}
Helper class
This needs to be in charge of calculating the total percentage that will be passed to the ProgressBar View with the values coming
from the Reminder object saved in Core Data.
class ReminderHelper:ObservableObject{
@Published var percentageLeft: Float = 0.80
func calculatePerentageLeft(daysLeft: Int, totalDays:Int)->Float{
percentageLeft = Float(daysLeft / totalDays)
return percentageLeft
}
}
Content View:
Here I'm calling the calculatePerentageLeft method to prepare the percentageLeft property before presenting the ProgressBar. Which of course is not working.
I see an error:
Static method 'buildBlock' requires that 'Float' conform to 'View'
struct ContentView: View {
var reminders = [Reminder(name: "Cut the Grass", totalDays: 50, daysLeft: 10),
Reminder(name: "Power Wash Siding", totalDays: 30, daysLeft: 15)]
@StateObject var reminderModel = ReminderHelper()
var body: some View {
List {
ForEach(reminders) { reminder in
HStack{
Text(reminder.name)
reminderModel.calculatePerentageLeft(daysLeft: reminder.daysLeft, totalDays: reminder.totalDays)
ProgressBar(progress: reminderModel.percentageLeft)
}
}
}
}
}
ProgressBar View
This is the view in charge of drawing and displaying the percentage value.
struct ProgressBar: View {
@Binding var progress: Float
var body: some View {
ZStack {
Circle()
.stroke(lineWidth:5.0)
.opacity(0.3)
.foregroundColor(Color.orange)
Circle()
.trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
.stroke(style: StrokeStyle(lineWidth: 5.0, lineCap: .round, lineJoin: .round))
.foregroundColor(Color.orange)
.rotationEffect(Angle(degrees: 270.0))
.animation(.linear, value: progress)
VStack{
Text(String(format: "%.0f %%", min(self.progress, 1.0)*100.0))
.font(.caption2)
}
}
}
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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)
}
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...
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()
}
}
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
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
I'm currently syncing Core Data with the CloudKit public database using NSPersistentCloudKitContainer. The app starts with an empty Core Data store locally and at the app launch it downloads the data from CloudKit public database to the Core Data store, but this can only be accomplished if the user is logged in, if the user is not logged, no data gets downloaded and I get the error below.
Can the NSPersistentCloudKitContainer mirror the data from the CloudKit public database to the local Core Data even if the user is not logged in? Can someone please confirm this is possible?
The reason for my question is because I was under the impression that the users didn't need to be logged to read data from the public database in CloudKit but I'm not sure this applies to NSPersistentCloudKitContainer when mirroring data. I know I can fetch data directly with CloudKit APIs without the user beign logged but I need to understand if NSPersistentCloudKitContainer should in theory work without the user being logged.
I hope someone from Apple sees this question since I have spent too much time researching without any luck.
Error
Error fetching user record ID: <CKError 0x600000cb1b00: "Not Authenticated" (9); "No iCloud account is configured">
CoreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _performSetupRequest:]_block_invoke(1192): <NSCloudKitMirroringDelegate: 0x600003b00460>: Failed to set up CloudKit integration for store: <NSSQLCore: 0x10700f0d0> (URL: file:///Users/UserName/...
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 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
I have an app that uses local notifications and everything is working fine but I'm debating how to handle pending notifications after the user turned off and turned back on notifications for your app. In other words, let's say that a notification is created and it's meant to be triggered on a certain day but the user turns notifications off the day before the trigger date, then he/she deletes the notification from the app (UI) while notifications for your app were turned off and then after a few days later the user turns on notifications for your app again, at that point there may be notifications that the user no longer wants (since he/she deleted them from the UI) and some that have been expired already.
How to find pending notifications that were deleted from the UI but not from the notification center in the event described above?
FYI - I know how to delete pending notifications and how to compare notifications in the UI vs notifications in the notifications center. What I'm not sure about is when to do the comparison. Is there a way to get notified when the user turned back on notifications for your app so a method can be triggered to find orphan notifications?
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!