Defaults icon indicating copy to clipboard operation
Defaults copied to clipboard

Handle key with a dot

Open kmalyshev opened this issue 3 years ago • 9 comments

Hello, I am not sure if it's a bug or I am doing something wrong. I have a setting window that users can change settings in. It uses property wrapper '@Default(.key)' for textfields.

However in other piece of code (ViewModel) I am subscribed to changes

            Defaults.observe(
                keys: .key1, .key2,
                options: [] // Initial value is not needed.
            ) { [weak self] in
                guard let self = self else { return }
                self.updateValues(array: &self.items)
            }
            .tieToLifetime(of: self)

It never gets called even though values are properly saved. I have to manually call update viewModel method after each change. Is it a bug or I'm using the API in a wrong way?

kmalyshev avatar Jan 10 '21 20:01 kmalyshev

I'm using @Default without problems in multiple apps.

Are you using @Default in a SwiftUI view or a view model? Because it cannot be used in a view model.

I cannot really help much without more info and code.

sindresorhus avatar Jan 19 '21 13:01 sindresorhus

I use @Default in SwiftUI view.

@Default(.isOn) var isOn

and then i have a toggle Toggle("Pro mode", isOn: $isOn)

switching it back and forth doesn't trigger the observation closure.

I also tried observing using publisher and '.sink'. Closure after '.sink' never gets triggered. Defaults.publisher(keys: .isOn) This observation code is in AppDelegate.

If this information is not enough and it doesn't seem that I'm doing something completely wrong - i can make a tiny project showing what's not working.

kmalyshev avatar Jan 23 '21 00:01 kmalyshev

I'm using both Defaults.observe and Defaults.publisher in my apps without any problems. It would be helpful if you could provide something I could run so I can debug the issue.

sindresorhus avatar Jan 27 '21 18:01 sindresorhus

I also tried observing using publisher and '.sink'. Closure after '.sink' never gets triggered.

Maybe try Defaults.publisher(.isOn)? (No keys parameter) Just to rule out that method being the problem.

sindresorhus avatar Jan 27 '21 18:01 sindresorhus

Found the problem.

static let proMode = Key<Bool>("name", default: false) works well

static let proMode = Key<Bool>("some.name", default: false) doesn't work. If there is a period in the name - observation doesn't happen.

https://github.com/kmalyshev/DefaultsLibTest/

if you remove "." from the name in this file the UI starts working again. https://github.com/kmalyshev/DefaultsLibTest/blob/main/DefaultsTest/DefaultsSettings.swift

kmalyshev avatar Jan 27 '21 21:01 kmalyshev

That is super weird. I cannot imagine what would cause this to fail.


// @hank121314 In case you have any ideas.

sindresorhus avatar Jan 28 '21 20:01 sindresorhus

I went to docs of KVO, this is not an issue with your code, it's their design which i didn't know about. Dot notation is used to observe subproperties.

object?.addObserver(self, forKeyPath: key, options: options.toNSKeyValueObservingOptions, context: nil) https://stackoverflow.com/a/14172860/605013

I'll close the bug. Sorry for the time spent on that.

kmalyshev avatar Jan 28 '21 20:01 kmalyshev

This is a bug in Defaults. We should correctly escape any dot in the observation code path.

sindresorhus avatar Jan 29 '21 06:01 sindresorhus

This is a bug in Defaults. We should correctly escape any dot in the observation code path.

Thanks for mentioning this issue! FWIW, it'll be great if this bug can be fixed in the future releases. 🥰

RoyRao2333 avatar May 14 '22 06:05 RoyRao2333

Seems like there is no way to escape special characters for an Objective-C key path, so there is really no way to fix this.

sindresorhus avatar Nov 08 '22 17:11 sindresorhus