Skip to content
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

In the scene:willConnectToSession:options:, accessing connectionOptions.UserActivities throws #16378

Closed
mattleibow opened this issue Oct 18, 2022 · 3 comments · Fixed by #16491
Labels
bug If an issue is a bug or a pull request a bug fix dotnet An issue or pull request related to .NET (6)
Milestone

Comments

@mattleibow
Copy link
Contributor

Steps to Reproduce

  1. Add some Info.plist xml
<key>UIApplicationSceneManifest</key>
<dict>
	<key>UIApplicationSupportsMultipleScenes</key>
	<true/>
	<key>UISceneConfigurations</key>
	<dict>
		<key>UIWindowSceneSessionRoleApplication</key>
		<array>
			<dict>
				<key>UISceneConfigurationName</key>
				<string>__MAUI_DEFAULT_SCENE_CONFIGURATION__</string>
				<key>UISceneDelegateClassName</key>
				<string>SceneDelegate</string>
			</dict>
		</array>
	</dict>
</dict>
  1. Override the Scene Delegate method:
[Export("scene:willConnectToSession:options:")]
[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public virtual void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
{
    var activities = connectionOptions.UserActivities;
}
  1. Observe an exception:
Unable to cast object of type 'Foundation.NSSet`1[[UIKit.UIScene, Microsoft.iOS, Version=16.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065]]' to type 'Foundation.NSSet`1[[Foundation.NSUserActivity, Microsoft.iOS, Version=16.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065]]'.

   at ObjCRuntime.Runtime.GetNSObject[NSSet`1](IntPtr ptr)
   at UIKit.UISceneConnectionOptions.get_UserActivities()
   at Microsoft.Maui.Platform.ApplicationExtensions.CreatePlatformWindow(IUIWindowSceneDelegate sceneDelegate, IApplication application, UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions) in /Users/matthew/Projects/maui/src/Core/src/Platform/iOS/ApplicationExtensions.cs:line 60
   at Microsoft.Maui.MauiUISceneDelegate.WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions) in /Users/matthew/Projects/maui/src/Core/src/Platform/iOS/MauiUISceneDelegate.cs:line 23
   at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName)
   at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)
   at Maui.Controls.Sample.Platform.Application.Main(String[] args) in /Users/matthew/Projects/maui/src/Controls/samples/Controls.Sample.Sandbox/Platforms/iOS/Main.cs:line 8

Expected Behavior

No exception

Actual Behavior

Exception

Environment

Version information

Build Logs

Example Project (If Possible)

@hartez
Copy link

hartez commented Oct 26, 2022

I can reproduce this issue with the Microsoft.Maui.sln at https://github.com/dotnet/maui - build and run the Sample project targeting iOS.

@mattleibow
Copy link
Contributor Author

mattleibow commented Oct 26, 2022

I was also able to repro this now with a small sample project: https://github.com/mattleibow/MauiMultiWindowSample

Just download and run mac catalyst.

System.InvalidCastException: Unable to cast object of type 'Foundation.NSSet`1[[UIKit.UIScene, Microsoft.MacCatalyst, Version=15.4.700.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065]]' to type 'Foundation.NSSet`1[[Foundation.NSUserActivity, Microsoft.MacCatalyst, Version=15.4.700.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065]]'.
   at ObjCRuntime.Runtime.GetNSObject[NSSet`1](IntPtr ptr)
   at UIKit.UISceneConnectionOptions.get_UserActivities()
   at Microsoft.Maui.Platform.ApplicationExtensions.CreatePlatformWindow(IUIWindowSceneDelegate sceneDelegate, IApplication application, UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
   at Microsoft.Maui.MauiUISceneDelegate.WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
   at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName)
   at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)
   at MauiMultiWindowSample.Program.Main(String[] args) in /Users/matthew/Projects/Testing/MauiMultiWindowSample-main/MauiMultiWindowSample/Platforms/MacCatalyst/Program.cs:line 13
% dotnet --info 
.NET SDK:
 Version:   7.0.100
 Commit:    4e41c41027

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  12.5
 OS Platform: Darwin
 RID:         osx.12-x64
 Base Path:   /usr/local/share/dotnet/sdk/7.0.100/

Host:
  Version:      7.0.0
  Architecture: x64
  Commit:       d099f075e4

.NET SDKs installed:
  6.0.402 [/usr/local/share/dotnet/sdk]
  7.0.100 [/usr/local/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.10 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.10 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  Not set

global.json file:
  Not found
% dotnet workload list

Installed Workload Id      Manifest Version       Installation Source
---------------------------------------------------------------------
macos                      12.3.2366/7.0.100      SDK 7.0.100        
ios                        16.0.1470/7.0.100      SDK 7.0.100        
maccatalyst                15.4.2366/7.0.100      SDK 7.0.100        
maui                       7.0.1/7.0.100          SDK 7.0.100        
tvos                       16.0.1470/7.0.100      SDK 7.0.100        
android                    33.0.4/7.0.100         SDK 7.0.100        

@rolfbjarne
Copy link
Member

rolfbjarne commented Oct 27, 2022

I can reproduce.

It looks like it's a duplicate/variation of #13704.

@rolfbjarne rolfbjarne added bug If an issue is a bug or a pull request a bug fix dotnet An issue or pull request related to .NET (6) labels Oct 27, 2022
@rolfbjarne rolfbjarne added this to the .NET 7 milestone Oct 27, 2022
rolfbjarne added a commit to rolfbjarne/xamarin-macios that referenced this issue Oct 27, 2022
…if the existing one is of the wrong type. Fixes xamarin#13704.

Objective-C has an optimization where creating an empty dictionary would
return the same instance every time (probably to a constant empty dictionary).

This causes a problem with how we've bound generic dictionaries, because all
empty dictionaries would have the same native handle, even if we'd bound them
with different managed types.

This surfaces in unfortunate ways when we try to look up a managed instance
given a native handle, we find that we already have a managed instance, but
the managed instance is of the wrong type.

Example code:

    var a = new NSDictionary ();
    var b = new NSDictionary<NSString, NSString> ();
    var c = new NSDictionary<NSString, NSObject> ();
    Console.WriteLine ($"a: 0x{a.Handle:X}");
    Console.WriteLine ($"b: 0x{b.Handle:X}");
    Console.WriteLine ($"c: 0x{c.Handle:X}");

would produce something like:

    a: 0x0x7fff80821080
    b: 0x0x7fff80821080
    c: 0x0x7fff80821080

now for this code:

    Runtime.GetNSObject<NSDictionary<NSString, NSString>> (b.Handle)

it would throw an exception like this:

    Unable to cast object of type 'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSObject]]' to type 'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSString]]'

because we'll have the 'c' object (with type `NSDictionary<NSString, Object>`)
in our dictionary of native handles -> managed instances, and that's not
compatible with the desired return type from GetNSObject
(`NSDictionary<NSString, NSString>`)

This likely happens with all the non-mutable collection types we have a
generic version of (NSArray, NSDictionary, NSOrderedSet, NSSet).

Fixes xamarin#16378.
Fixes xamarin#13704.
@rolfbjarne rolfbjarne modified the milestones: .NET 7, xcode14.1 Oct 27, 2022
rolfbjarne added a commit that referenced this issue Oct 28, 2022
…if the existing one is of the wrong type. Fixes #13704. (#16491)

Objective-C has an optimization where creating an empty dictionary would
return the same instance every time (probably to a constant empty dictionary).

This causes a problem with how we've bound generic dictionaries, because all
empty dictionaries would have the same native handle, even if we'd bound them
with different managed types.

This surfaces in unfortunate ways when we try to look up a managed instance
given a native handle, we find that we already have a managed instance, but
the managed instance is of the wrong type.

Example code:

    var a = new NSDictionary ();
    var b = new NSDictionary<NSString, NSString> ();
    var c = new NSDictionary<NSString, NSObject> ();
    Console.WriteLine ($"a: 0x{a.Handle:X}");
    Console.WriteLine ($"b: 0x{b.Handle:X}");
    Console.WriteLine ($"c: 0x{c.Handle:X}");

would produce something like:

    a: 0x0x7fff80821080
    b: 0x0x7fff80821080
    c: 0x0x7fff80821080

now for this code:

    Runtime.GetNSObject<NSDictionary<NSString, NSString>> (b.Handle)

it would throw an exception like this:

    Unable to cast object of type 'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSObject]]' to type 'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSString]]'

because we'll have the 'c' object (with type `NSDictionary<NSString, Object>`)
in our dictionary of native handles -> managed instances, and that's not
compatible with the desired return type from GetNSObject
(`NSDictionary<NSString, NSString>`)

This likely happens with all the non-mutable collection types we have a
generic version of (NSArray, NSDictionary, NSOrderedSet, NSSet).

Fixes #16378.
Fixes #13704.
vs-mobiletools-engineering-service2 pushed a commit to vs-mobiletools-engineering-service2/xamarin-macios that referenced this issue Oct 28, 2022
…if the existing one is of the wrong type. Fixes xamarin#13704.

Objective-C has an optimization where creating an empty dictionary would
return the same instance every time (probably to a constant empty dictionary).

This causes a problem with how we've bound generic dictionaries, because all
empty dictionaries would have the same native handle, even if we'd bound them
with different managed types.

This surfaces in unfortunate ways when we try to look up a managed instance
given a native handle, we find that we already have a managed instance, but
the managed instance is of the wrong type.

Example code:

    var a = new NSDictionary ();
    var b = new NSDictionary<NSString, NSString> ();
    var c = new NSDictionary<NSString, NSObject> ();
    Console.WriteLine ($"a: 0x{a.Handle:X}");
    Console.WriteLine ($"b: 0x{b.Handle:X}");
    Console.WriteLine ($"c: 0x{c.Handle:X}");

would produce something like:

    a: 0x0x7fff80821080
    b: 0x0x7fff80821080
    c: 0x0x7fff80821080

now for this code:

    Runtime.GetNSObject<NSDictionary<NSString, NSString>> (b.Handle)

it would throw an exception like this:

    Unable to cast object of type 'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSObject]]' to type 'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSString]]'

because we'll have the 'c' object (with type `NSDictionary<NSString, Object>`)
in our dictionary of native handles -> managed instances, and that's not
compatible with the desired return type from GetNSObject
(`NSDictionary<NSString, NSString>`)

This likely happens with all the non-mutable collection types we have a
generic version of (NSArray, NSDictionary, NSOrderedSet, NSSet).

Fixes xamarin#16378.
Fixes xamarin#13704.
dalexsoto pushed a commit that referenced this issue Oct 28, 2022
…ew instance if the existing one is of the wrong type. Fixes #13704. (#16502)

Objective-C has an optimization where creating an empty dictionary would
return the same instance every time (probably to a constant empty
dictionary).

This causes a problem with how we've bound generic dictionaries, because
all
empty dictionaries would have the same native handle, even if we'd bound
them
with different managed types.

This surfaces in unfortunate ways when we try to look up a managed
instance
given a native handle, we find that we already have a managed instance,
but
the managed instance is of the wrong type.

Example code:

    var a = new NSDictionary ();
    var b = new NSDictionary<NSString, NSString> ();
    var c = new NSDictionary<NSString, NSObject> ();
    Console.WriteLine ($"a: 0x{a.Handle:X}");
    Console.WriteLine ($"b: 0x{b.Handle:X}");
    Console.WriteLine ($"c: 0x{c.Handle:X}");

would produce something like:

    a: 0x0x7fff80821080
    b: 0x0x7fff80821080
    c: 0x0x7fff80821080

now for this code:

    Runtime.GetNSObject<NSDictionary<NSString, NSString>> (b.Handle)

it would throw an exception like this:

Unable to cast object of type
'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSObject]]'
to type
'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSString]]'

because we'll have the 'c' object (with type `NSDictionary<NSString,
Object>`)
in our dictionary of native handles -> managed instances, and that's not
compatible with the desired return type from GetNSObject
(`NSDictionary<NSString, NSString>`)

This likely happens with all the non-mutable collection types we have a
generic version of (NSArray, NSDictionary, NSOrderedSet, NSSet).

Fixes #16378.
Fixes #13704.

This PR is somewhat simpler to review by ignoring whitespace:
https://github.com/xamarin/xamarin-macios/pull/16491/files?w=1


Backport of #16491

Co-authored-by: Rolf Bjarne Kvinge <[email protected]>
@ghost ghost locked as resolved and limited conversation to collaborators Nov 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug If an issue is a bug or a pull request a bug fix dotnet An issue or pull request related to .NET (6)
Projects
None yet
3 participants