UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: How to use UserDefaults.publisher in SwiftUI?

Forums > SwiftUI

UserDefaults.publisher works really well in UIKit, and even Apple's documentation mainly revolves around that. However, I'm unable to get the desired behaviour of continous observing of values using UserDefaults.publisher in SwiftUI.

Example UIKit Code that works perfectly:

import UIKit
import Combine

extension UserDefaults {
    @objc dynamic var test: Int {
        return integer(forKey: "test")
    }
}

class ViewController: UIViewController {
    var subscriber: AnyCancellable?   // Subscriber of preference changes.

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        subscriber = UserDefaults.standard
        .publisher(for: \.test)
            .sink() {
                print($0)
        }

        UserDefaults.standard.set(5, forKey: "test")
        UserDefaults.standard.set(10, forKey: "test")
        UserDefaults.standard.set(100, forKey: "test")
    }
}

Output of above code:
[initial value]
5
10
100

Problematic SwiftUI code:

import SwiftUI
import Combine

extension UserDefaults {
    @objc dynamic var userValue: Int {
        return integer(forKey: "value")
    }
}

struct ContentView: View {
    //    @ObservedObject var auth = AuthModel()
    @State var cancellable: AnyCancellable? = UserDefaults.standard
        .publisher(for: \.userValue)
        .sink() {
            print($0)
    }

    var body: some View {
         Text("hello!") 
    }
}

Output: Prints the value stored once, however, after that, it doesn't reprints the values automatically on changes.

I've tried using a separate Model class, but the issue stays and the core reason remains the same I guess.

Any help would be greatly appreciated, thanks!

Correct Answer:

https://forums.developer.apple.com/message/423512#423512

In the UserDefault extension, the variable name of the @obj dynamic var and the key used in return statement shall be the same. Another point: we can use a normal variable/constant or a property wrapper like @State, all work.

Thanks!

2      

For some reason cancellables don't work with property wrappers (or at least @State). If you remove @State to make the whole declaration be just

private let cancellable = UserDefaults.standard.publisher(for: \.value).sink {
    print($0)
}

it should work.

2      

Thanks a lot for your reply! However, changing @State to a a normal constant/variable is giving me the same behaviour.

2      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.