[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:
Родитель
85ce924296
Коммит
abca8f1aec
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче