Swiftui: Forcing an Update

SwiftUI: Forcing an Update

Setting currentPage, as it is a @State, will reload the whole body.

SwiftUI: View does not update when state variable changes

The cause of this is using @State for your CNMutableContact.

@State works best with value types -- whenever a new value is assigned to the property, it tells the View to re-render. In your case, though, CNMutableContact is a reference type. So, you're not setting a truly new value, you're modifying an already existing value. In this case, the View only updates when name changes, which then triggers your onChange, so there's no update after the contact changes and you're always left one step behind.

But, you need something like @State because otherwise you can't mutate the contact.

There are a couple of solutions to this. I think the simplest one is to wrap your CNMutableContact in an ObservableObject and call objectWillChange.send() explicitly when you change a property on it. That way, the View will be re-rendered (even though there aren't any @Published properties on it).

class ContactViewModel : ObservableObject {
var contact = CNMutableContact()

func changeGivenName(_ newValue : String) {
contact.givenName = newValue
self.objectWillChange.send()
}
}

struct ContentView: View {
@State var name: String = ""
@StateObject private var contactVM = ContactViewModel()

var body: some View {
TextField("name", text: $name)
.onChange(of: name) { newValue in
contactVM.changeGivenName(newValue)
print("contact.givenName = \(contactVM.contact.givenName)")
}
Text("contact.givenName = \(contactVM.contact.givenName)")
}
}

Another option is moving name to the view model and using Combine to observe the changes. This works without objectWillChange because the sink updates contact on the same run loop as name gets changed, so the @Published property wrapper signals the View to update after the change to contact has been made.

import Combine
import SwiftUI
import Contacts

class ContactViewModel : ObservableObject {
@Published var name: String = ""
var contact = CNMutableContact()

private var cancellable : AnyCancellable?

init() {
cancellable = $name.sink {
self.contact.givenName = $0
}
}
}

struct ContentView: View {
@StateObject private var contactVM = ContactViewModel()

var body: some View {
TextField("name", text: $contactVM.name)
Text("contact.givenName = \(contactVM.contact.givenName)")
}
}

SwiftUI ForEach force UI update when updating the contents of a core data relationship

I’m not sure if this is the ONLY solution as @malhal gave quite an extensive and seemingly useful response.

But I came across a much easier and immediate fix, within my original solution. The inverse relationships must be specified. Doing this resolved all issues.

How to force view updates from changes in value of published array item

without all relevent the code, I can only guess. Try something like this:

struct SecondView: View {
@ObservedObject var viewModel: MyViewModel
...
var body: some View {
...
ForEach ($viewModel.itemsArray, id: \.self) { $item in // <-- here
HStack {
Button(action: {
if item.quantity < 2 { // <-- here
item.quantity = 1
} else {
item.quantity -= 1
}
}) {
Image(systemName: "minus.circle").foregroundColor(Color.gray)
}
Text("\(item.quantity)")
Button(action: { item.quantity += 1 }) { // <-- here
Image(systemName: "plus.circle").foregroundColor(Color.black)
}
}
}
}
}

and no need for your increaseCount and decreaseCount code in your MyViewModel.

EDIT-1: here is my test code that shows the UI is updated when the buttons are tapped/clicked.

struct Item: Identifiable, Hashable {
let id = UUID()
var quantity = 0
}

class MyViewModel: ObservableObject {
@Published var itemsArray = [Item(),Item(),Item()] // for testing some Items in the array
}

struct ContentView: View {
@StateObject var viewModel = MyViewModel() // <-- here, or let

var body: some View {
SecondView(viewModel: viewModel)
}
}

struct SecondView: View {
@ObservedObject var viewModel: MyViewModel

var body: some View {
VStack(spacing: 33) {
ForEach ($viewModel.itemsArray, id: \.self) { $item in // <-- here
HStack {
Button(action: {
if item.quantity < 1 { // <-- here
item.quantity = 0
} else {
item.quantity -= 1
}
}) {
Image(systemName: "minus.circle").foregroundColor(Color.gray)
}

Text("\(item.quantity)")

Button(action: { item.quantity += 1 }) { // <-- here
Image(systemName: "plus.circle").foregroundColor(Color.black)
}
}
}
}
}
}

SwiftUI view does not update for Published objects with subclasses

ObservableObject requires that its fields are structs, not classes.

I changed your code slightly and it worked:

protocol SuperMankind {
associatedtype PlayerType
var people: [PlayerType] { get set }
}

struct Mankind: SuperMankind {
var people: [Men] = []
}

Screenshot here

Re your solution (since I can't comment):

Array<Men> is a struct, despite the array holding class references. This is why your code works now, as before you were directly holding a reference to a class in your ObservableObject (which therefore did not update the view).

SwiftUI is it possible to update ObservedObject in the current view without redrawing current view?

SwiftUI is designed so that the code in your views is run multiple times so that it knows what to display, and it reruns any time a piece of state – whether it's @State, @StateObject, @ObservedObject, etc. – changes. That's why you're seeing multiple print statements – it's expected behaviour.

Here, your View2 and View3 are referencing the same data source, so of course if that data source changes in one, it's going to change in the other.

So when you have a one-element array and remove that element in one view, your other view is going to be re-evaluated because it's looking at exactly the same array. If you don't want that to happen, then you should not share state between views.

The key with successfully using SwiftUI is to ensure that your views' body code can be run, and rerun, as many times as the system wants to without introducing side-effects (the throwing of an error when calling let text = dataSource.listOfThings[0] with an empty array is one such side effect). If you try and fight against that, you'll have a devil of a time creating beautiful and performant user interfaces with SwiftUI.

Force reload Image when url changes SwiftUI

This is jnpdx Answer !
I dont know the reason , if it was too close from displaying, but view wouldn t update with the firebase request onAppear, using id foreced the refresh.

struct Test4: View {

@State private var mProfilePhotoUrl: URL = URL(string:"0")!
*@State private var ID = 0*

var body: some View {

VStack(alignment: .center,spacing : 0){

KFImage(mProfilePhotoUrl)*.id(ID)*

}.onAppear(){
setUpProfileElements()
}

}

private func setUpProfileElements(){

// FirebaseRequest -> mProfilePhotoUrl = URL(string: User.profilePhoto)
// *-> self.ID += 1*
}

}


Related Topics



Leave a reply



Submit