-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Fix swift KVO when keyPath having a optional value #24356
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@lilyball Do you have time checking this fix? You have fixed several Swift KVO issues before, I think you can help me with this : ) |
It's not clear to me how this is supposed to do anything at all. All uses of There's also no attempt here to distinguish "value present but Of course, when handling that, there's the unfortunate edge case of something like |
For comparison's sake here's the implementation in PMKVObserver. This handles |
You are right. I just updated the commit and add the explicit |
1bbdc9b
to
a5573a1
Compare
@@ -251,6 +251,36 @@ extension _KeyValueCodingAndObserving { | |||
} | |||
} | |||
|
|||
/// Overload for keyPath having a optional target value. | |||
/// Solve https://bugs.swift.org/browse/SR-6066 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look like it should be a doc comment
if unwrappedValue is NSNull { | ||
return .some(nil) | ||
} else { | ||
return .some(unwrappedValue as? Value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless Value == NSNull.self
, the expression .some(unwrappedValue as? Value)
will already evaluate to .some(nil)
for the case where unwrappedValue is NSNull
.
In the case where Value == NSNull.self
there's no way to distinguish between the property actually containing NSNull
or containing nil
so either behavior works.
Given that, we can just remove this if
and the special handling of NSNull
entirely and just use return .some(unwrappedValue as? Value)
. Though we should probably keep the comment to explain why we're even unwrapping this at all instead of just using return unwrappedValue as? Value?
.
I just updated the comment format and unwrapping logic according to review. |
The logic looks fine to me, but this still needs tests. |
I just added corresponding tests and verified in my local environment. By the way, is there any documentation about |
Anything that adds API surface needs to go through additional internal review. |
(Also I don’t think we can take it as-is without availability.) |
I'm uncertain which Swift version should the availability requires (e.g. 5.1, 5.2 or 6). So the version will be discussed after the PR passes the internal review, right? |
@zetasq please add the following availability to the new method in your patch:
|
After I added the availability annotation, there was an error when I run the tests saying This also reminds me that if people are using a new SDK shipped with this new overloaded method and observe a keyPath with optional value, but with their deployment target set to iOS 11, will they also come across the error, or just resolve to the old |
I find that it's really hard (maybe impossible) to explicitly use the old
But this seems needing more discussion and review I think. |
You need to use
If the old method has incorrect behavior wrt optionals, isn't this a desirable outcome? |
@millenomi do I understand correctly that
essentially disables this PR for undetermined time, and Apple will later decide a version to include this change, if any. So then it would be logical to do the same @available for the tests in this PR as well. From my viewpoint this PR is a fix to a bug in observe (i.e. correctly handling optional observation), it's not a new feature as such. Ideally one should be able to use one function syntax for both non-optional and optional cases, and overloads would take care of doing the right thing. |
After I add availability annotation to the new overloaded method, the other observations (old testing code) in So I assume this would happen if we put this in a new iOS SDK. The compiler would give similar error (like The scenario is like this
|
I guess it’s possible that availability doesn’t work the way we’d like it to work when doing overloads like this PR. In that case we can’t use availability, but instead could use
Which is effectively what the availability is doing anyway in this PR |
But we need availability anyway, because if you write code against this new overload, and then deploy to an OS that doesn't provide it in the stdlib, that wouldn't work. |
@lilyball I understand, but in this overload case, the availability isn't working right:
AFTER:
|
I'm not worried that the existing code would not compile with the new SDK, as long as we could use availability checking to fix it. But when the availability checking is applied, I find that there is another problem we need to solve:
So we need to reference the old |
@zetasq I think client code using new compiler, but old SDK should not need any changes. And this availability error affects all code. This needs to be worked in the library side, not by asking everyone add ”if #available” in client code. |
So one way to workaround this is adding overload to old API, although that might be also undesirable. AFTER:
|
We don't change the old SDK. The overloading method will only exist in the new SDK.
If availability checking works (we have a problem in the |
We cannot add any code to the shipped SDK. I'm not sure what you means. |
@zetasq You raise a very correct (and obvious once explained; whoops) point re: the |
Can we reimplement this as a dynamic type-check inside the existing method? |
@lilyball dynamic type-check is possible at least by using mirror or with ExpressibleByNilLiteral. It would be nice to use single existing function rather than introduce an overload.
|
Dynamic type-checking is a viable option. But to identify an optional type in the runtime, I have to introduce a private protocol |
I can take these with no internal review. Thanks :) |
@swift-ci please smoke test and merge |
1 similar comment
@swift-ci please smoke test and merge |
I cannot see the reason for the failed tests. Maybe I should rebase my branch onto the latest |
@millenomi Can you help to see why the smoke test fails? The stdlib related tests succeed on my laptop (OSX environment). |
@millenomi I just resolved the merge conflicts. Can you help to rerun the smoke test? |
@swift-ci please smoke test |
Will this fix come into Swift 5.1 branch? So I can add version check for my own app code : ) |
@millenomi Could this pull request be merged now? Or there's something I can do to help? |
@jrose-apple Can you help to check if this pull request can be merged? It seems to be over a month since the CI tests passed. |
@swift-ci please smoke test and merge |
Fix a long standing issue https://bugs.swift.org/browse/SR-6066.
When keyPath has an optional value, we provide an overloaded method on
_KeyValueCodingAndObserving
to handle the special case.Resolves SR-6066.