-
Notifications
You must be signed in to change notification settings - Fork 516
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
No Replacement for deprecated TraitCollectionDidChange #19410
Comments
If you have a using ObjCRuntime;
UIView view = ...;
var observable = Runtime.GetINativeObject<IUITraitChangeObservable> (view.Handle, false);
observable.RegisterForTraitChanges (...); |
Thanks. I tried the following but it crashes with a
I am not sure if I translated the |
Could you create a test project that shows the crash? |
…IWindowScene implement the UITraitChangeObservable protocol. Fixes xamarin#19410. Fixes xamarin#19410.
|
Our bindings are wrong :/ The first argument to |
This might work as a workaround (at least it doesn't crash anymore, although the callback isn't called): IUITraitChangeRegistration RegisterForTraitChanges (UIViewController vc)
{
var traits = new Type [] {
typeof (UITraitVerticalSizeClass),
typeof (UITraitHorizontalSizeClass),
};
return RegisterForTraitChanges (vc, traits);
}
IUITraitChangeRegistration RegisterForTraitChanges (UIViewController vc, params Type[] traits)
{
var classes = new Class [traits.Length];
for (var i = 0; i < classes.Length; i++)
classes [i] = new Class (traits [i]);
using var traitArray = NSArray.FromNSObjects (classes);
var registrationHandle = NativeHandle_objc_msgSend_NativeHandle_NativeHandle_NativeHandle (vc.Handle, Selector.GetHandle ("registerForTraitChanges:withTarget:action:"), traitArray.Handle, this.Handle, Selector.GetHandle ("traitChangeCallback:collection:"));
return Runtime.GetINativeObject<IUITraitChangeRegistration> (registrationHandle, false);
}
[DllImport ("/usr/lib/libobjc.dylib", EntryPoint="objc_msgSend")]
extern static NativeHandle NativeHandle_objc_msgSend_NativeHandle_NativeHandle_NativeHandle (IntPtr receiver, IntPtr selector, NativeHandle arg1, NativeHandle arg2, NativeHandle arg3);
[Export ("traitChangeCallback:collection:")]
void TraitChangeCallback (NSObject sender, UITraitCollection collection)
{
Console.WriteLine ($"TraitChangeCallback");
} Full AppDelegate.cs file: https://gist.github.com/rolfbjarne/042dc7b97e97c458ae08290a80e301df Note that more workarounds are likely needed for other API, any new API that takes a |
Thanks a lot! For me, your workaround code works and the callback is called when a trait changes (e.g. dark/light theme switch when using |
…IWindowScene implement the UITraitChangeObservable protocol. Fixes xamarin#19410. Fixes xamarin#19410.
I'm also affected. Once the bindings are fixed, what would be the proper way to both use We could override |
@marcoburato-ecutek I did something like this (simply not calling the base implementation):
|
@tipa I don't think that's a good idea. We don't know what the base implementation does, not calling it may or may not cause problems. For instance, Apple's documentation says:
I imagine that, if there are nested view controllers (basically always the case with UIKit nav controller, tab controller, etc) the parent could not get notified if it still relies on the deprecated method. I'd rather be safe and always call the base method. |
…IWindowScene implement the UITraitChangeObservable protocol. Fixes xamarin#19410. Fixes xamarin#19410.
There are a few issues with the bindings, because the typedef `UITrait` in the headers is defined like this: ```objective-c typedef Class<UITraitDefinition> UITrait ``` which means: "A Class that implements the UITraitDefinition protocol", and not "The UITraitDefinition" protocol", which is how it was bound. This means the corresponding bindings are incorrect, so fix them. In some cases it's not possible to fix the API, so new ones had to be implemented in order to maintain backwards compatibility. Fixes #19410.
…IWindowScene implement the UITraitChangeObservable protocol. Fixes xamarin#19410. Fixes xamarin#19410.
Hi @rolfbjarne , Thanks for the workaround on registerForTraitChanges , it helped me to solve part of the issue. |
@priyank459 we've already bound |
…#19410. (#19730) There are a few issues with the bindings, because the typedef `UITrait` in the headers is defined like this: ```objective-c typedef Class<UITraitDefinition> UITrait ``` which means: "A Class that implements the UITraitDefinition protocol", and not "The UITraitDefinition" protocol", which is how it was bound. This means the corresponding bindings are incorrect, so fix them. In some cases it's not possible to fix the API, so new ones had to be implemented in order to maintain backwards compatibility. Fixes #19410. Backport of #19411 --------- Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com>
Thank you @rolfbjarne and @dalexsoto. I am able to solve my issue. |
I just updated to the new version and observing a probably unintended behavior. Something like this (written in a Viewcontroller or View) fails to build:
I need to specifically cast to
Probably not obvious to new developers. Wouldn't it be best to just remove the old methods, which were non-functional anyways? It would be a breaking change API-wise but I doubt that any developers used those methods as they were crashing |
Good catch, I think I know how to fix this.
We try very hard to not make breaking changes, because we've run into trouble before removing APIs that were 100% incorrect and never called (because it would crash the process). It turned out third-party libraries had references to said API in code paths that were never executed - and when we removed that API, we suddently got a lot of bug reports about breaking the build for consumers of the third-party library - it turned out the linker will fail if running into a reference to a method that doesn't exist. In any case it doesn't look like removing the old API will fix the problem, because this isn't a failure to find a specific method overload - the problem is that methods on an interface are not directly accessible from types that implement that interface. The fix would be to add proxy implementations on all the types that implement the interface. |
For several reasons this turned out to be cumbersome to implement at this point, but it looks like it'll be much easier once we add support for default interface members in the generator (#13294), so I'm postponing until then. I've filed #20265 to keep track of it. |
…that implement it. This also required fixing a bug in the static registrar where we'd ignore the generic parameters in a method when looking for methods implementing an interface. Ref: xamarin#19410 (comment)
…that implement it. Fixes #20265. This also required fixing: * A bug in the static registrar where we'd ignore the generic parameters in a method when looking for methods implementing an interface. * A bug in the generator where we'd throw You_Should_Not_Call_base_In_This_Method() in some cases where we shouldn't. Also: * Enable nullability and fix any resulting issues. * Clean up some legacy code we don't need anymore. Ref: #19410 (comment) Fixes #20265.
…that implement it. Fixes #20265. (#21676) This also required fixing: * A bug in the static registrar where we'd ignore the generic parameters in a method when looking for methods implementing an interface. * A bug in the generator where we'd throw You_Should_Not_Call_base_In_This_Method() in some cases where we shouldn't. Also: * Enable nullability and fix any resulting issues. * Clean up some legacy code we don't need anymore. Ref: #19410 (comment) Fixes #20265. --------- Co-authored-by: GitHub Actions Autoformatter <github-actions-autoformatter@xamarin.com>
I was using traitcollectiondidchange to detect changes of the dark/light theme. That method has been deprecated with iOS 17
The suggested alternative by Apple is registerfortraitchanges, which can be called on objects that implement
UITraitChangeObservable
(IUITraitChangeObservable
interface in C#).UIView
andUIViewController
seem to implement that interface, but this isn't reflected in the C# bindings - the method RegisterForTraitChanges doesn't exist forUIView
andUIViewController
. How can I use this new API in .NET?Environment
.NET 8 RC2.2
The text was updated successfully, but these errors were encountered: