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()
}
}
Post
Replies
Boosts
Views
Activity
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...
Hi, I need to send a user notification when the user enter a
certain location/region. I noticed that there is a UNLocationNotificationTrigger
class to do just this insed the UserNotification framework. I have a little
experience using User Notifications with time intervals but haven’t used the
trigger by location. I have a couple of questions when using UNLocationNotificationTrigger.
1.
When you set a user notification by location,
does that means that the phone will constantly be searching the user’s location,
or the GPS will automatically trigger the notification when the user enters the
designated location without constant searching?
2.
Does UNLocationNotificationTrigger drain the
phones battery?
Thanks
How can I make the following animation move in a more circular/arc way?
What I need is to be able to animate the red circle in an arc shape, where it goes up and then down forming a curve/arc. Right now the animation looks almost linear with just a little bit of curve, and it doesn't look smooth.
import SwiftUI
struct GeometryEffectTesting: View {
@State private var isOn: Bool = false
var body: some View {
VStack{
ZStack{
Image(systemName: "circle.fill")
.font(.title)
.foregroundColor(.orange)
.animation(.easeOut(duration: 0.3), value: isOn)
Image(systemName: "circle.fill")
.font(.title2)
.foregroundColor(.red)
.modifier(SpecialEffect(isAnimating: isOn))
.animation(.easeOut(duration: 0.3), value: isOn)
.onTapGesture {
self.isOn.toggle()
}
}
}
.padding()
}
}
struct SpecialEffect: GeometryEffect{
private var percentage : CGFloat
private var isAnimating : Bool
init(isAnimating: Bool){
self.percentage = isAnimating ? 1 : 0
self.isAnimating = isAnimating
}
var animatableData: CGFloat{
get{return percentage}
set{percentage = newValue}
}
func effectValue(size: CGSize) -> ProjectionTransform {
let transform: CGAffineTransform
if isAnimating{
transform = Self.transform(forPercent: percentage)
}else{
transform = Self.transform(forPercent: 0)
}
return ProjectionTransform(transform)
}
static func transform(forPercent percent: CGFloat) -> CGAffineTransform {
let xPos: CGFloat = 50
let yPos: CGFloat = 50
let transform: CGAffineTransform
if percent == 0{
transform = .init(translationX: 0, y: 0)
return transform
}else{
if percent < 0.25 {
transform = .init(translationX: percent * xPos, y: -percent * yPos)
} else if percent < 0.5 {
transform = .init(translationX: (percent * xPos) * 2, y: -(percent * yPos) * 2)
} else if percent < 0.75 {
transform = .init(translationX: (percent * xPos) * 3, y: -(percent * yPos) * 2)
} else {
transform = .init(translationX: (percent * xPos) * 4, y: -(percent * yPos) * 2)
}
return transform
}
}
}
Hi,
What would be the best animation method in SwiftUI to reproduce the UIKit animation shown below?
What I need is basically a throwing effect starting from point A and ending at Point B. I don't need any bouncing effects, this is more of an effect to let the user know that something was added from point A to Point B; similar to the effect we get when we add a photo to an album in Photos.
I tried using .rotationEffect() but the animation I get is too circular and with no option to add the point locations. I need a more natural throwing-paper-like animation where you define three points, start, apex and end, see the image below.
Please note that Point A and Point B will be some views on the screen and the throwing object will be a simple SF symbol Image(systemName: "circle.fill").
Any suggestions?
What I have tried in SwiftUI that cannot make it look like a throwing paper animation.
struct KeyframeAnimation: View {
@State private var ascend = false
@State private var ascendDescend = false
@State private var descend = false
var body: some View {
ZStack{
VStack{
ZStack{
Image(systemName: "circle.fill")
.font(.title)
.offset(x: -157)
.foregroundColor(Color.red)
.rotationEffect(.degrees(ascend ? 17: 0))
.rotationEffect(.degrees(ascendDescend ? 145: 0))
.rotationEffect(.degrees(descend ? 18: 0))
.onAppear{
withAnimation(Animation.easeInOut(duration: 0.5)){
self.ascend.toggle()
}
withAnimation(Animation.easeInOut(duration: 1)){
self.ascendDescend.toggle()
}
withAnimation(Animation.easeInOut(duration: 2).delay(8)){
self.descend.toggle()
}
}
}
}
}
}
}
UIKit Animation
This is what I need.
@IBAction func startAnimation(_ sender: Any) {
UIView.animateKeyframes(withDuration: 3.0, delay: 0.0, options: [.calculationModeCubic], animations: {
// start
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1.0/5.0, animations: {
self.myView.center = CGPoint(x: self.pointA.center.x, y: self.pointA.center.y)
})
// apex
UIView.addKeyframe(withRelativeStartTime: 1.0/5.0, relativeDuration: 1.0/5.0, animations: {
self.myView.center = CGPoint(x: self.pointB.center.x - 100, y: self.pointB.center.y - 100)
})
// end
UIView.addKeyframe(withRelativeStartTime: 2.0/5.0, relativeDuration: 1.0/5.0, animations: {
self.myView.center = CGPoint(x: self.pointB.center.x, y: self.pointB.center.y)
})
}
)
}
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 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 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!
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!
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)
}
}
}
}
How can I reload the NSPersistentCloudKitContainer from a SwiftUI View?
I have a SwiftUI + MVVM + CloudKit app that successfully syncs to CloudKit but what I would like to be able to do is reload the NSPersistentCloudKitContainer from some View in the app to be able to evaluate if the app should sync to CloudKit or not by setting the cloudKitContainerOptions to nil (description.cloudKitContainerOptions = nil) if the user doesn't want to sync.
In other words, I need to reload the code inside the init() method in the CoreDataManager file when a method in the View Model is called. See the code and comments below.
Here is the code...
Core Data Manager
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)
/// This is the code that I would like to control from other view in the app
/// if iCloudSync is off, do nothing otherwise set it to nil
if !iCloudSync{
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)")
}
}
}
View Model
Somehow I would like to be able to have a way to control the reload process in the 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()
}
}
SwiftUI View
Then from a view, I would like to control the reload process through the View Model by calling a method.
struct ContentView: View {
@State private var isSync = false
@StateObject var viewModel = CarViewModel()
var body: some View {
VStack {
Toggle("iCloud Sync", isOn: $isSync)
.toggleStyle(SwitchToggleStyle(tint: .red))
if isSync {
// RELOAD the container, something like this
viewModel.reloadContainer(withSync: true)
}
}
}
}
Any help would be appreciated.
Thanks
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 where I would like to enable NSPersistentCloudKitContainer to start using CloudKit and be able to sync the content of the app between multiple devices, but I'm not sure how to handle the user experience. Should this be a feature that the user turns On and Off in the app settings screen or does the user expects the syncing mechanism to work by default without having to do anything, can someone please share your experience on how you implemented CloudKit/Sync in your app.
Do I need to offer a login mechanism so the user logs in?
Should I include an On/Off option so the user decides if they want the sync option or not?
In general, can someone be so kind and explain what the user experience should be when an app provides ClouldKit/sync?
FYI - I'm not asking how to implement CloudKit sync I already know what it is and how it works. I just need to know what the expedition is from an app the provides that feature.
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 recently tried to submit an update to an app that I have been constantly updating; the last update was done two months ago using Xcode 11 and I had no issues back then. This time when I Distributed the App using Xcode 12, everything went smoothly without any errors but after a few minutes, I got the following email from Apple.
Dear Developer, We identified one or more issues with a recent delivery for your app, “My App” 6.2 (6.2). Please correct the following issues, then upload again. ITMS-90561: Invalid Swift Support - The watchOS application has Swift libraries at both /Payload/My App.app/My App Watch App.app/My App Watch App Extension.appex/Frameworks/ and /Payload/My App.app/My App Watch App.app/Frameworks/. Remove all of the Swift libraries from one of the locations and resubmit your app. Best regards,
The App Store Team
Any idea what should I be removing?