[uikit] Simplify and fix (NRE) in `UIApplication` (#11964)

* `#enable nullable`

and add null-check for potentially `null` `args` parameter on `Main`
methods(s).

* Avoiding calls chaining

There were 4 `Main` overloads, 3 of them needed for the most simple app.
There's now only one needed.

* Obsolete the overload with `string` parameters

It's not type safe. It also makes it harder for the linker to mark the
app delegate type.

* Avoid creating `NSString` instances inside `Main` methods

`CFString` are cheaper, no initialization, simpler calling convention.
This also remove any trace of `NSString` in very simple apps, see below:

```diff
--- a.cs	2021-06-16 21:41:04.000000000 -0400
+++ b.cs	2021-06-16 21:41:06.000000000 -0400
@@ -3025,9 +3025,6 @@
 		public static extern nuint nuint_objc_msgSendSuper(IntPtr P_0, IntPtr P_1);

 		[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
-		public static extern IntPtr IntPtr_objc_msgSend_IntPtr_IntPtr(IntPtr P_0, IntPtr P_1, IntPtr P_2, IntPtr P_3);
-
-		[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
 		[return: MarshalAs(UnmanagedType.I1)]
 		public static extern bool bool_objc_msgSend_IntPtr(IntPtr P_0, IntPtr P_1, IntPtr P_2);

@@ -3045,9 +3042,6 @@
 		public static extern IntPtr IntPtr_objc_msgSend_nuint(IntPtr P_0, IntPtr P_1, nuint P_2);

 		[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
-		public static extern long Int64_objc_msgSend_IntPtr(IntPtr P_0, IntPtr P_1, IntPtr P_2);
-
-		[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
 		public static extern CGRect CGRect_objc_msgSend(IntPtr P_0, IntPtr P_1);

 		[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSendSuper")]
@@ -3129,30 +3123,14 @@
 			}
 		}

-		public static void Main(string[] P_0, string P_1, string P_2)
-		{
-			IntPtr intPtr = NSString.CreateNative(P_1);
-			IntPtr intPtr2 = NSString.CreateNative(P_2);
-			try
-			{
-				Main(P_0, intPtr, intPtr2);
-			}
-			finally
-			{
-				NSString.ReleaseNative(intPtr2);
-				NSString.ReleaseNative(intPtr);
-			}
-		}
-
 		public static void Main(string[] P_0, Type P_1, Type P_2)
 		{
-			Main(P_0, (P_1 == null) ? null : new Class(P_1).Name, (P_2 == null) ? null : new Class(P_2).Name);
-		}
-
-		private static void Main(string[] P_0, IntPtr P_1, IntPtr P_2)
-		{
+			IntPtr intPtr = (P_1 == null) ? IntPtr.Zero : CFString.CreateNative(new Class(P_1).Name);
+			IntPtr intPtr2 = (P_2 == null) ? IntPtr.Zero : CFString.CreateNative(new Class(P_2).Name);
 			Initialize();
-			UIApplicationMain(P_0.Length, P_0, P_1, P_2);
+			UIApplicationMain((P_0 != null) ? P_0.Length : 0, P_0, intPtr, intPtr2);
+			CFString.ReleaseNative(intPtr2);
+			CFString.ReleaseNative(intPtr);
 		}

 		protected internal UIApplication(IntPtr P_0)
@@ -3731,161 +3709,6 @@
 		{
 		}
 	}
-	[DefaultMember("Item")]
-	[Register("NSString", true)]
-	public class NSString : NSObject, IComparable<NSString>, INativeObject, IDisposable
-	{
-		public static readonly NSString Empty = new NSString(string.Empty);
-
-		private static readonly IntPtr class_ptr = Class.GetHandle("NSString");
-
-		public override IntPtr ClassHandle => class_ptr;
-
-		public int CompareTo(NSString P_0)
-		{
-			return (int)Compare(P_0);
-		}
-
-		private unsafe static IntPtr CreateWithCharacters(IntPtr P_0, string P_1, int P_2, int P_3, bool P_4 = false)
-		{
-			IntPtr intPtr;
-			if (P_1 == null)
-			{
-				intPtr = (IntPtr)(void*)null;
-			}
-			else
-			{
-				pinnableReference = ref P_1.GetPinnableReference();
-				intPtr = (IntPtr)(&pinnableReference);
-			}
-			IntPtr intPtr2 = (IntPtr)(void*)((long)intPtr + (long)(IntPtr)(void*)((long)P_2 * 2L));
-			P_0 = Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr(P_0, Selector.GetHandle("initWithCharacters:length:"), intPtr2, (IntPtr)P_3);
-			if (P_4)
-			{
-				NSObject.DangerousAutorelease(P_0);
-			}
-			return P_0;
-		}
-
-		public static IntPtr CreateNative(string P_0)
-		{
-			return CreateNative(P_0, false);
-		}
-
-		public static IntPtr CreateNative(string P_0, bool P_1)
-		{
-			if (P_0 == null)
-			{
-				return IntPtr.Zero;
-			}
-			return CreateNative(P_0, 0, P_0.Length, P_1);
-		}
-
-		public static IntPtr CreateNative(string P_0, int P_1, int P_2, bool P_3)
-		{
-			if (P_0 == null)
-			{
-				return IntPtr.Zero;
-			}
-			if (P_1 < 0 || P_1 > P_0.Length)
-			{
-				throw new ArgumentOutOfRangeException("start");
-			}
-			if (P_2 < 0 || P_1 > P_0.Length - P_2)
-			{
-				throw new ArgumentOutOfRangeException("length");
-			}
-			return CreateWithCharacters(Messaging.IntPtr_objc_msgSend(class_ptr, Selector.GetHandle("alloc")), P_0, P_1, P_2, P_3);
-		}
-
-		public static void ReleaseNative(IntPtr P_0)
-		{
-			NSObject.DangerousRelease(P_0);
-		}
-
-		public NSString(string P_0)
-		{
-			if (P_0 == null)
-			{
-				throw new ArgumentNullException("str");
-			}
-			base.Handle = CreateWithCharacters(base.Handle, P_0, 0, P_0.Length);
-		}
-
-		public override string ToString()
-		{
-			return FromHandle(base.Handle);
-		}
-
-		public static string FromHandle(IntPtr P_0)
-		{
-			return FromHandle(P_0, false);
-		}
-
-		public static string FromHandle(IntPtr P_0, bool P_1)
-		{
-			if (P_0 == IntPtr.Zero)
-			{
-				return null;
-			}
-			try
-			{
-				return Marshal.PtrToStringAuto(Messaging.IntPtr_objc_msgSend(P_0, Selector.GetHandle("UTF8String")));
-			}
-			finally
-			{
-				if (P_1)
-				{
-					NSObject.DangerousRelease(P_0);
-				}
-			}
-		}
-
-		public static bool Equals(NSString P_0, NSString P_1)
-		{
-			if (P_0 == P_1)
-			{
-				return true;
-			}
-			if (P_0 == null || P_1 == null)
-			{
-				return false;
-			}
-			if (P_0.Handle == P_1.Handle)
-			{
-				return true;
-			}
-			return P_0.IsEqualTo(P_1.Handle);
-		}
-
-		public override bool Equals(object P_0)
-		{
-			return Equals(this, P_0 as NSString);
-		}
-
-		public override int GetHashCode()
-		{
-			return base.GetHashCode();
-		}
-
-		protected internal NSString(IntPtr P_0)
-			: base(P_0)
-		{
-		}
-
-		[Export("compare:")]
-		public virtual NSComparisonResult Compare(NSString P_0)
-		{
-			IntPtr nonNullHandle = NativeObjectExtensions.GetNonNullHandle(P_0, "aString");
-			_ = 8;
-			return (NSComparisonResult)Messaging.Int64_objc_msgSend_IntPtr(base.Handle, Selector.GetHandle("compare:"), nonNullHandle);
-		}
-
-		public bool IsEqualTo(IntPtr P_0)
-		{
-			return Messaging.bool_objc_msgSend_IntPtr(base.Handle, Selector.GetHandle("isEqualToString:"), P_0);
-		}
-	}
 	[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property)]
 	public class ExportAttribute : Attribute
 	{
@@ -4388,19 +4211,6 @@
 			return false;
 		}

-		internal static void DangerousRelease(IntPtr P_0)
-		{
-			if (!(P_0 == IntPtr.Zero))
-			{
-				Messaging.void_objc_msgSend(P_0, Selector.GetHandle("release"));
-			}
-		}
-
-		internal static void DangerousAutorelease(IntPtr P_0)
-		{
-			Messaging.void_objc_msgSend(P_0, Selector.GetHandle("autorelease"));
-		}
-
 		public NSObject DangerousRetain()
 		{
 			Messaging.void_objc_msgSend(handle, Selector.GetHandle("retain"));
@@ -4647,13 +4457,6 @@
 			is_wrapper = P_1;
 		}
 	}
-	[Native]
-	public enum NSComparisonResult : long
-	{
-		Ascending = -1L,
-		Same,
-		Descending
-	}
 	[Register("NSException", true)]
 	public class NSException : NSObject, INativeObject, IDisposable
 	{
```
This commit is contained in:
Sebastien Pouliot 2021-06-17 17:13:06 -04:00 коммит произвёл GitHub
Родитель 85ce924296
Коммит abca8f1aec
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 23 добавлений и 22 удалений

Просмотреть файл

@ -13,8 +13,11 @@ using System;
using System.Threading;
using ObjCRuntime;
using System.Runtime.InteropServices;
using CoreFoundation;
using Foundation;
#nullable enable
namespace UIKit {
public class UIKitThreadAccessException : Exception {
public UIKitThreadAccessException () : base ("UIKit Consistency error: you are calling a UIKit method that can only be invoked from the UI thread.")
@ -34,7 +37,7 @@ namespace UIKit {
: UIResponder
#endif
{
static Thread mainThread;
static Thread? mainThread;
public static bool CheckForIllegalCrossThreadCalls = true;
public static bool CheckForEventAndDelegateMismatches = true;
@ -42,7 +45,7 @@ namespace UIKit {
// We link with __Internal here so that this function is interposable from third-party native libraries.
// See: https://github.com/xamarin/MicrosoftInTune/issues/3 for an example.
[DllImport (/*Constants.UIKitLibrary*/ "__Internal")]
extern static int UIApplicationMain (int argc, /* char[]* */ string [] argv, /* NSString* */ IntPtr principalClassName, /* NSString* */ IntPtr delegateClassName);
extern static int UIApplicationMain (int argc, /* char[]* */ string []? argv, /* NSString* */ IntPtr principalClassName, /* NSString* */ IntPtr delegateClassName);
#endif
// called from NSExtension.Initialize (so other, future stuff, can be added if needed)
@ -57,33 +60,31 @@ namespace UIKit {
}
#if !WATCH
public static void Main (string [] args, string principalClassName, string delegateClassName)
[Obsolete ("Use the overload with 'Type' instead of 'String' parameters for type safety.")]
public static void Main (string []? args, string? principalClassName, string? delegateClassName)
{
var p = NSString.CreateNative (principalClassName);
var d = NSString.CreateNative (delegateClassName);
try {
Main (args, p, d);
} finally {
// it just looks nicer to release them
NSString.ReleaseNative (d);
NSString.ReleaseNative (p);
}
var p = CFString.CreateNative (principalClassName);
var d = CFString.CreateNative (delegateClassName);
Initialize ();
UIApplicationMain (args?.Length ?? 0, args, p, d);
CFString.ReleaseNative (d);
CFString.ReleaseNative (p);
}
public static void Main (string [] args, Type principalClass, Type delegateClass)
public static void Main (string []? args, Type? principalClass, Type? delegateClass)
{
Main (args, principalClass == null ? null : new Class (principalClass).Name, delegateClass == null ? null : new Class (delegateClass).Name);
var p = principalClass == null ? IntPtr.Zero : CFString.CreateNative (new Class (principalClass).Name);
var d = delegateClass == null ? IntPtr.Zero : CFString.CreateNative (new Class (delegateClass).Name);
Initialize ();
UIApplicationMain (args?.Length ?? 0, args, p, d);
CFString.ReleaseNative (d);
CFString.ReleaseNative (p);
}
public static void Main (string [] args)
{
Main (args, IntPtr.Zero, IntPtr.Zero);
}
static void Main (string [] args, IntPtr principal, IntPtr @delegate)
public static void Main (string []? args)
{
Initialize ();
UIApplicationMain (args.Length, args, principal, @delegate);
UIApplicationMain (args?.Length ?? 0, args, IntPtr.Zero, IntPtr.Zero);
}
#endif
@ -101,7 +102,7 @@ namespace UIKit {
throw new InvalidOperationException (string.Format("Event registration is overwriting existing delegate. Either just use events or your own delegate: {0} {1}", del.GetType (), expectedType));
}
internal static void EnsureDelegateAssignIsNotOverwritingInternalDelegate (object currentDelegateValue, object newDelegateValue, Type internalDelegateType)
internal static void EnsureDelegateAssignIsNotOverwritingInternalDelegate (object? currentDelegateValue, object? newDelegateValue, Type internalDelegateType)
{
if (UIApplication.CheckForEventAndDelegateMismatches && currentDelegateValue != null && newDelegateValue != null
&& currentDelegateValue.GetType().IsAssignableFrom (internalDelegateType)