Swift Class-Property Update

How to update custom classes properties properly?

First you create a singleton class to hold all your "global" variables. Then add a didSet to the fadedTextColor property to post a notification when its value changes. Next add an observer and a selector at your custom class to change the buttons border color using the color from your singleton class:

class Shared {
private init() {}
static let instance = Shared()
var fadedTextColor: UIColor = .red {
didSet {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "fadedTextColorChanged"), object: nil)
}
}
var textHeaderColor: UIColor = .blue
}

class PopupButton: UIButton {
override func awakeFromNib() {
super.awakeFromNib()
layer.borderWidth = 1.3
layer.borderColor = Shared.instance.fadedTextColor.cgColor
layer.cornerRadius = 10
layer.backgroundColor = UIColor.white.cgColor
setTitleColor(Shared.instance.textHeaderColor, for: .normal)
NotificationCenter.default.addObserver(self, selector: #selector(colorChanged), name: NSNotification.Name(rawValue: "fadedTextColorChanged"), object: nil)
}
@objc func colorChanged(notification: Notification) {
layer.borderColor = Shared.instance.fadedTextColor.cgColor
}
}

Swift class-property update

You can use mutableCopy() with your object but for that your custom class need to extends from NSObject and its return type is Any so you need to explicitly type cast its result to your CustomClass.

targetVC.reservation = self.reservation!.mutableCopy() as! YourCustomClass

swiftui text view does not update when the property of class changes

For Objects use @StateObject property wrapper and for String, Int, etc use @State property wrapper.

@State: We use this property wrapper when we observe a property that is exists inside our ContentView.

@StateObject: We use this property wrapper when we are observing properties that exists outside of our ContentView like in our Object, we can observe that property changes by firstly conforming that class to ObservableObject Protocol and marking that property as @Published inside our Object.

struct ContentView: View {
@StateObject private var client : Client = Client()

var body: some View {
VStack{
Text(client.message)

Button( action: {
print("\(client.message)")
}){
Text("Mess")
}
}
}
}

class Client : ObservableObject{
private var mqtt: CocoaMQTT!
@Published var message : String = "Empty"

func get_message(mess : String){
self.message = mess
}
}

How to update a property in a separate class from a child view and have the parent view update

do not use Data as it is already a standard swift name. Then try the following:

class Datax: ObservableObject {
@Published var title = "Title"
}

struct ContentView: View {
@StateObject var data = Datax()
var body: some View {
VStack {
Text(data.title).padding()
ButtonView(data: data) // <-- here
}
}
}

struct ButtonView: View {
@ObservedObject var data: Datax // <-- here

var body: some View {
VStack {
Button(action: {
data.title = "Hello"
}, label: {
Text("Button")
})
}
}
}

Update property without running combine pipeline

On further inspection, the answer came to me.
This is the case for class PassthroughSubject.

class ObserveableTest: ObservableObject {

private var cancellables: Set<AnyCancellable> = []

/// private(set) to restrict all changes to go through class functions
@Published private(set) var items: [Int] = []

/// A subject we can pass data into, when we wanna publish changes
private let listener = PassthroughSubject<[Int], Never>()

init() {
listener
.debounce(for: 0.6, scheduler: RunLoop.main)
.sink {
print($0)
}
.store(in: &cancellables)
}


func thisFunctionIsCalledByUserAndTriggersPipeline() {
items.append((0...1000000).randomElement()!)
listener.send(items) // publish to pipeline
}

func thisFunctionIsCalledByServerAndDoesNotTriggerPipeline() {
items.append((0...1000000).randomElement()!)
}

}

How to prod a SwiftUI view to update when a model class sub-property changes?

When MyObject is a class type the results contains references, so when you change property of any instance inside results the reference of that instance is not changed, so results is not changed, so nothing published and UI is not updated.

In such case the solution is to force publish explicitly when you perform any change of internal model

class DataSource: ObservableObject
{
@Published var results = [MyObject](repeating: MyObject(label: "test"), count: 5)

func change()
{
print("I've changed")
results[3].label = "sooner"
self.objectWillChange.send() // << here !!

_ = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) {[weak self] _ in
self?.results[1].label = "Or later"
self?.objectWillChange.send() // << here !!
}
}
}

Update UI on Singleton property change without sharing dependency between Views

The ObservableObject updates view only via ObservedObject/StateObject/EnvironmentObject (which are actually have same nature). That wrapper (one of them) actually observers changes in published properties and refreshes view.

So your case can be solved like

struct ParentView: View {
@StateObject private var networkNanager = NetworkManager.shared // << observer !!

var body: some View {
SOME_VIEW.disabled(!networkNanager.isConnected) // injects dependency !!
}
}

Swift - update object in place

Here is the explanation for both of your queries,

1. parent child array contains the reference to the person1 object, i.e. person1 and parent child array store the reference to same object.

var person1 = Person(name: "John", surname: "Doe")
parent.child.append(person1)

Now, you're assigning a new object to person1 instead of making changes to the same object, i.e.

person1 = Person(name: "Jack", surname: "Doe")

This won't reflect in the parent child array. It will still contain the reference to the previous Person object.

This is the reason you are getting different values of name in person1 and parent child array

print(person1.name) //Jack
print(parent.child.first!.name) //John

2. Instead of adding a separate method for updating the object - update(name:surname:age:), you can simply update the values individually using the . operator on object's properties, i.e

var person2 = Person(name: "Tom", surname: "Cruise")
parent.child.append(person2)

person2.name = "Jim"

Since in the above code, instead of assigning a new Person object to person2, we're just updating its values.

So, person2 and parent child array's object will still reference the same object and hence will print the same name values.

print(person2.name) //Tom
print(parent.child.last!.name) //Tom


Related Topics



Leave a reply



Submit