using CPF.Mac.CoreGraphics; using CPF.Mac.ObjCRuntime; using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; namespace CPF.Mac.Foundation { [StructLayout(LayoutKind.Sequential)] [Register("NSObject", true)] public class NSObject : INativeObject, IDisposable { private struct objc_super { public IntPtr receiver; public IntPtr super; } [Register("__NSObject_Disposer")] [Preserve(AllMembers = true)] internal class NSObject_Disposer : NSObject { private static readonly List drainList1 = new List(); private static readonly List drainList2 = new List(); private static List handles = drainList1; private new static readonly IntPtr class_ptr = Class.GetHandle("__NSObject_Disposer"); private static readonly IntPtr drainHandle = Selector.GetHandle("drain:"); private new static readonly object lock_obj = new object(); private NSObject_Disposer() { } internal static void Add(NSObject handle) { bool flag; lock (lock_obj) { handles.Add(handle); flag = (handles.Count == 1); } if (flag) { Messaging.void_objc_msgSend_intptr_intptr_bool(class_ptr, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle, drainHandle, IntPtr.Zero, arg3: false); } } [Export("drain:")] private static void Drain(NSObject ctx) { List list; lock (lock_obj) { list = handles; if (handles == drainList1) { handles = drainList2; } else { handles = drainList1; } } foreach (NSObject item in list) { item.ReleaseManagedRef(); } list.Clear(); } } private delegate IntPtr RetainTrampolineDelegate(IntPtr @this, IntPtr sel); private delegate void ReleaseTrampolineDelegate(IntPtr @this, IntPtr sel); private const string selConformsToProtocol = "conformsToProtocol:"; private const string selEncodeWithCoder = "encodeWithCoder:"; private const string selAwakeFromNib = "awakeFromNib"; private const string selRespondsToSelector = "respondsToSelector:"; private static IntPtr selConformsToProtocolHandle = Selector.GetHandle("conformsToProtocol:"); private static IntPtr selEncodeWithCoderHandle = Selector.GetHandle("encodeWithCoder:"); private static IntPtr selAwakeFromNibHandle = Selector.GetHandle("awakeFromNib"); private static IntPtr selRespondsToSelectorHandle = Selector.GetHandle("respondsToSelector:"); private IntPtr handle; private IntPtr super; private bool disposed; protected bool IsDirectBinding; public static readonly Assembly MonoMacAssembly = typeof(NSObject).Assembly; private IntPtr gchandle; private bool has_managed_ref; private static object lock_obj = new object(); private static IntPtr RetainTrampolineFunctionPointer; private static IntPtr ReleaseTrampolineFunctionPointer; private static RetainTrampolineDelegate retainTrampoline; private static ReleaseTrampolineDelegate releaseTrampoline; private static readonly IntPtr selDescriptionHandle = Selector.GetHandle("description"); private static readonly IntPtr selDebugDescriptionHandle = Selector.GetHandle("debugDescription"); private static readonly IntPtr selObserveValueForKeyPathOfObjectChangeContext_Handle = Selector.GetHandle("observeValueForKeyPath:ofObject:change:context:"); private static readonly IntPtr selAddObserverForKeyPathOptionsContext_Handle = Selector.GetHandle("addObserver:forKeyPath:options:context:"); private static readonly IntPtr selRemoveObserverForKeyPath_Handle = Selector.GetHandle("removeObserver:forKeyPath:"); private static readonly IntPtr selWillChangeValueForKey_Handle = Selector.GetHandle("willChangeValueForKey:"); private static readonly IntPtr selDidChangeValueForKey_Handle = Selector.GetHandle("didChangeValueForKey:"); private static readonly IntPtr selWillChangeValuesAtIndexesForKey_Handle = Selector.GetHandle("willChange:valuesAtIndexes:forKey:"); private static readonly IntPtr selDidChangeValuesAtIndexesForKey_Handle = Selector.GetHandle("didChange:valuesAtIndexes:forKey:"); private static readonly IntPtr selWillChangeValueForKeyWithSetMutationUsingObjects_Handle = Selector.GetHandle("willChangeValueForKey:withSetMutation:usingObjects:"); private static readonly IntPtr selDidChangeValueForKeyWithSetMutationUsingObjects_Handle = Selector.GetHandle("didChangeValueForKey:withSetMutation:usingObjects:"); private static readonly IntPtr selKeyPathsForValuesAffectingValueForKey_Handle = Selector.GetHandle("keyPathsForValuesAffectingValueForKey:"); private static readonly IntPtr selAutomaticallyNotifiesObserversForKey_Handle = Selector.GetHandle("automaticallyNotifiesObserversForKey:"); private static readonly IntPtr selValueForKey_Handle = Selector.GetHandle("valueForKey:"); private static readonly IntPtr selSetValueForKey_Handle = Selector.GetHandle("setValue:forKey:"); private static readonly IntPtr selValueForKeyPath_Handle = Selector.GetHandle("valueForKeyPath:"); private static readonly IntPtr selSetValueForKeyPath_Handle = Selector.GetHandle("setValue:forKeyPath:"); private static readonly IntPtr selValueForUndefinedKey_Handle = Selector.GetHandle("valueForUndefinedKey:"); private static readonly IntPtr selSetValueForUndefinedKey_Handle = Selector.GetHandle("setValue:forUndefinedKey:"); private static readonly IntPtr selSetNilValueForKey_Handle = Selector.GetHandle("setNilValueForKey:"); private static readonly IntPtr selDictionaryWithValuesForKeys_Handle = Selector.GetHandle("dictionaryWithValuesForKeys:"); private static readonly IntPtr selSetValuesForKeysWithDictionary_Handle = Selector.GetHandle("setValuesForKeysWithDictionary:"); private static readonly IntPtr selExposedBindingsHandle = Selector.GetHandle("exposedBindings"); private static readonly IntPtr selValueClassForBinding_Handle = Selector.GetHandle("valueClassForBinding:"); private static readonly IntPtr selBindToObjectWithKeyPathOptions_Handle = Selector.GetHandle("bind:toObject:withKeyPath:options:"); private static readonly IntPtr selUnbind_Handle = Selector.GetHandle("unbind:"); private static readonly IntPtr selInfoForBinding_Handle = Selector.GetHandle("infoForBinding:"); private static readonly IntPtr selOptionDescriptionsForBinding_Handle = Selector.GetHandle("optionDescriptionsForBinding:"); private static readonly IntPtr selDefaultPlaceholderForMarkerWithBinding_Handle = Selector.GetHandle("defaultPlaceholderForMarker:withBinding:"); private static readonly IntPtr selSetDefaultPlaceholderForMarkerWithBinding_Handle = Selector.GetHandle("setDefaultPlaceholder:forMarker:withBinding:"); private static readonly IntPtr selObjectDidEndEditing_Handle = Selector.GetHandle("objectDidEndEditing:"); private static readonly IntPtr selCommitEditingHandle = Selector.GetHandle("commitEditing"); private static readonly IntPtr selCommitEditingWithDelegateDidCommitSelectorContextInfo_Handle = Selector.GetHandle("commitEditingWithDelegate:didCommitSelector:contextInfo:"); private static readonly IntPtr selCopyHandle = Selector.GetHandle("copy"); private static readonly IntPtr selMutableCopyHandle = Selector.GetHandle("mutableCopy"); private static readonly IntPtr selPerformSelectorWithObjectAfterDelayInModes_Handle = Selector.GetHandle("performSelector:withObject:afterDelay:inModes:"); private static readonly IntPtr selPerformSelectorOnThreadWithObjectWaitUntilDone_Handle = Selector.GetHandle("performSelector:onThread:withObject:waitUntilDone:"); private static readonly IntPtr selPerformSelectorOnThreadWithObjectWaitUntilDoneModes_Handle = Selector.GetHandle("performSelector:onThread:withObject:waitUntilDone:modes:"); private static readonly IntPtr selCancelPreviousPerformRequestsWithTarget_Handle = Selector.GetHandle("cancelPreviousPerformRequestsWithTarget:"); private static readonly IntPtr selCancelPreviousPerformRequestsWithTargetSelectorObject_Handle = Selector.GetHandle("cancelPreviousPerformRequestsWithTarget:selector:object:"); private static readonly IntPtr class_ptr = Class.GetHandle("NSObject"); private static NSString _ChangeKindKey; private static NSString _ChangeNewKey; private static NSString _ChangeOldKey; private static NSString _ChangeIndexesKey; private static NSString _ChangeNotificationIsPriorKey; private static IntPtr fl = Dlfcn.dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", 1); private static IntPtr al = Dlfcn.dlopen("/System/Library/Frameworks/AppKit.framework/AppKit", 1); private static IntPtr ab = Dlfcn.dlopen("/System/Library/Frameworks/AddressBook.framework/AddressBook", 1); private static IntPtr ct = Dlfcn.dlopen("/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreText.framework/CoreText", 1); private static IntPtr wl = Dlfcn.dlopen("/System/Library/Frameworks/WebKit.framework/WebKit", 1); private static IntPtr zl = Dlfcn.dlopen("/System/Library/Frameworks/QuartzCore.framework/QuartzCore", 1); private static IntPtr ql = Dlfcn.dlopen("/System/Library/Frameworks/QTKit.framework/QTKit", 1); private static IntPtr cl = Dlfcn.dlopen("/System/Library/Frameworks/CoreLocation.framework/CoreLocation", 1); private static IntPtr ll = Dlfcn.dlopen("/System/Library/Frameworks/Security.framework/Security", 1); private static IntPtr zc = Dlfcn.dlopen("/System/Library/Frameworks/Quartz.framework/Frameworks/QuartzComposer.framework/QuartzComposer", 1); private static IntPtr cw = Dlfcn.dlopen("/System/Library/Frameworks/CoreWLAN.framework/CoreWLAN", 1); private static IntPtr pk = Dlfcn.dlopen("/System/Library/Frameworks/Quartz.framework/Frameworks/PDFKit.framework/PDFKit", 1); private static IntPtr ik = Dlfcn.dlopen("/System/Library/Frameworks/Quartz.framework/Frameworks/ImageKit.framework/ImageKit", 1); private static IntPtr sb = Dlfcn.dlopen("/System/Library/Frameworks/ScriptingBridge.framework/ScriptingBridge", 1); private static IntPtr av = Dlfcn.dlopen("/System/Library/Frameworks/AVFoundation.framework/AVFoundation", 1); public unsafe IntPtr SuperHandle { get { if (super == IntPtr.Zero) { super = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(objc_super))); objc_super* ptr = (objc_super*)(void*)super; ptr->receiver = handle; ptr->super = ClassHandle; } return super; } } public IntPtr Handle { get { return handle; } set { if (!(handle == value)) { if (handle != IntPtr.Zero) { Runtime.UnregisterNSObject(handle); } handle = value; if (handle != IntPtr.Zero) { Runtime.RegisterNSObject(this, handle); } } } } [Export("retainCount")] public virtual int RetainCount { get { if (IsDirectBinding) { return Messaging.int_objc_msgSend(Handle, Selector.RetainCount); } return Messaging.int_objc_msgSendSuper(SuperHandle, Selector.RetainCount); } } public virtual IntPtr ClassHandle => class_ptr; public virtual string Description { [Export("description")] get { if (IsDirectBinding) { return NSString.FromHandle(Messaging.IntPtr_objc_msgSend(Handle, selDescriptionHandle)); } return NSString.FromHandle(Messaging.IntPtr_objc_msgSendSuper(SuperHandle, selDescriptionHandle)); } } public virtual string DebugDescription { [Export("debugDescription")] get { if (IsDirectBinding) { return NSString.FromHandle(Messaging.IntPtr_objc_msgSend(Handle, selDebugDescriptionHandle)); } return NSString.FromHandle(Messaging.IntPtr_objc_msgSendSuper(SuperHandle, selDebugDescriptionHandle)); } } [Field("NSKeyValueChangeKindKey", "Foundation")] public static NSString ChangeKindKey { get { if (_ChangeKindKey == null) { _ChangeKindKey = Dlfcn.GetStringConstant(Libraries.Foundation.Handle, "NSKeyValueChangeKindKey"); } return _ChangeKindKey; } } [Field("NSKeyValueChangeNewKey", "Foundation")] public static NSString ChangeNewKey { get { if (_ChangeNewKey == null) { _ChangeNewKey = Dlfcn.GetStringConstant(Libraries.Foundation.Handle, "NSKeyValueChangeNewKey"); } return _ChangeNewKey; } } [Field("NSKeyValueChangeOldKey", "Foundation")] public static NSString ChangeOldKey { get { if (_ChangeOldKey == null) { _ChangeOldKey = Dlfcn.GetStringConstant(Libraries.Foundation.Handle, "NSKeyValueChangeOldKey"); } return _ChangeOldKey; } } [Field("NSKeyValueChangeIndexesKey", "Foundation")] public static NSString ChangeIndexesKey { get { if (_ChangeIndexesKey == null) { _ChangeIndexesKey = Dlfcn.GetStringConstant(Libraries.Foundation.Handle, "NSKeyValueChangeIndexesKey"); } return _ChangeIndexesKey; } } [Field("NSKeyValueChangeNotificationIsPriorKey", "Foundation")] public static NSString ChangeNotificationIsPriorKey { get { if (_ChangeNotificationIsPriorKey == null) { _ChangeNotificationIsPriorKey = Dlfcn.GetStringConstant(Libraries.Foundation.Handle, "NSKeyValueChangeNotificationIsPriorKey"); } return _ChangeNotificationIsPriorKey; } } [Export("init")] public NSObject() { bool alloced = AllocIfNeeded(); InitializeObject(alloced); } public NSObject(NSObjectFlag x) { bool alloced = AllocIfNeeded(); InitializeObject(alloced); } public NSObject(IntPtr handle) : this(handle, alloced: false) { } public NSObject(IntPtr handle, bool alloced) { this.handle = handle; InitializeObject(alloced); } ~NSObject() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } [Export("encodeWithCoder:")] public virtual void EncodeTo(NSCoder coder) { if (coder == null) { throw new ArgumentNullException("coder"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_intptr(Handle, selEncodeWithCoderHandle, coder.Handle); } else { Messaging.void_objc_msgSendSuper_intptr(SuperHandle, selEncodeWithCoderHandle, coder.Handle); } } [Export("conformsToProtocol:")] [Preserve] public virtual bool ConformsToProtocol(IntPtr protocol) { if ((!IsDirectBinding) ? Messaging.bool_objc_msgSendSuper_intptr(SuperHandle, selConformsToProtocolHandle, protocol) : Messaging.bool_objc_msgSend_intptr(Handle, selConformsToProtocolHandle, protocol)) { return true; } object[] customAttributes = GetType().GetCustomAttributes(typeof(AdoptsAttribute), inherit: true); for (int i = 0; i < customAttributes.Length; i++) { if (((AdoptsAttribute)customAttributes[i]).ProtocolHandle == protocol) { return true; } } return false; } [Export("respondsToSelector:")] public virtual bool RespondsToSelector(Selector sel) { if (IsDirectBinding) { return Messaging.bool_objc_msgSend_intptr(Handle, selRespondsToSelectorHandle, sel.Handle); } return Messaging.bool_objc_msgSendSuper_intptr(SuperHandle, selRespondsToSelectorHandle, sel.Handle); } [Export("doesNotRecognizeSelector:")] public virtual void DoesNotRecognizeSelector(Selector sel) { Messaging.void_objc_msgSendSuper_intptr(SuperHandle, Selector.DoesNotRecognizeSelectorHandle, sel.Handle); } public void Release() { Messaging.void_objc_msgSend(handle, Selector.ReleaseHandle); } public NSObject Retain() { Messaging.void_objc_msgSend(handle, Selector.RetainHandle); return this; } public NSObject Autorelease() { Messaging.void_objc_msgSend(handle, Selector.AutoreleaseHandle); return this; } private bool AllocIfNeeded() { if (handle == IntPtr.Zero) { handle = Messaging.intptr_objc_msgSend(Class.GetHandle(GetType()), Selector.AllocHandle); return true; } return false; } private IntPtr GetObjCIvar(string name) { object_getInstanceVariable(handle, name, out IntPtr val); return val; } public NSObject GetNativeField(string name) { IntPtr objCIvar = GetObjCIvar(name); if (objCIvar == IntPtr.Zero) { return null; } return Runtime.GetNSObject(objCIvar); } private void SetObjCIvar(string name, IntPtr value) { object_setInstanceVariable(handle, name, value); } public void SetNativeField(string name, NSObject value) { if (value == null) { SetObjCIvar(name, IntPtr.Zero); } else { SetObjCIvar(name, value.Handle); } } [DllImport("/usr/lib/libobjc.dylib")] private static extern void object_getInstanceVariable(IntPtr obj, string name, out IntPtr val); [DllImport("/usr/lib/libobjc.dylib")] private static extern void object_setInstanceVariable(IntPtr obj, string name, IntPtr val); [Export("performSelector:withObject:afterDelay:")] public virtual void PerformSelector(Selector sel, NSObject obj, double delay) { if (sel == null) { throw new ArgumentNullException("sel"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_intptr_intptr_double(Handle, Selector.PerformSelectorWithObjectAfterDelayHandle, sel.Handle, obj?.Handle ?? IntPtr.Zero, delay); } else { Messaging.void_objc_msgSendSuper_intptr_intptr_double(SuperHandle, Selector.PerformSelectorWithObjectAfterDelayHandle, sel.Handle, obj?.Handle ?? IntPtr.Zero, delay); } } [Export("awakeFromNib")] public virtual void AwakeFromNib() { if (IsDirectBinding) { Messaging.void_objc_msgSend(Handle, selAwakeFromNibHandle); } else { Messaging.void_objc_msgSendSuper(SuperHandle, selAwakeFromNibHandle); } } private void InvokeOnMainThread(Selector sel, NSObject obj, bool wait) { Messaging.void_objc_msgSend_intptr_intptr_bool(Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle, sel.Handle, obj?.Handle ?? IntPtr.Zero, wait); } public void BeginInvokeOnMainThread(Selector sel, NSObject obj) { InvokeOnMainThread(sel, obj, wait: false); } public void InvokeOnMainThread(Selector sel, NSObject obj) { InvokeOnMainThread(sel, obj, wait: true); } public void BeginInvokeOnMainThread(NSAction action) { NSAsyncActionDispatcher nSAsyncActionDispatcher = new NSAsyncActionDispatcher(action); Messaging.void_objc_msgSend_intptr_intptr_bool(nSAsyncActionDispatcher.Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle, NSActionDispatcher.Selector.Handle, nSAsyncActionDispatcher.Handle, arg3: false); } public void InvokeOnMainThread(NSAction action) { using (NSActionDispatcher nSActionDispatcher = new NSActionDispatcher(action)) { Messaging.void_objc_msgSend_intptr_intptr_bool(nSActionDispatcher.Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle, NSActionDispatcher.Selector.Handle, nSActionDispatcher.Handle, arg3: true); } } public static NSObject FromObject(object obj) { if (obj == null) { return NSNull.Null; } Type type = obj.GetType(); if (type == typeof(NSObject) || type.IsSubclassOf(typeof(NSObject))) { return (NSObject)obj; } switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: return new NSNumber((bool)obj); case TypeCode.Char: return new NSNumber((char)obj); case TypeCode.SByte: return new NSNumber((sbyte)obj); case TypeCode.Byte: return new NSNumber((byte)obj); case TypeCode.Int16: return new NSNumber((short)obj); case TypeCode.UInt16: return new NSNumber((ushort)obj); case TypeCode.Int32: return new NSNumber((int)obj); case TypeCode.UInt32: return new NSNumber((uint)obj); case TypeCode.Int64: return new NSNumber((long)obj); case TypeCode.UInt64: return new NSNumber((ulong)obj); case TypeCode.Single: return new NSNumber((float)obj); case TypeCode.Double: return new NSNumber((double)obj); case TypeCode.String: return new NSString((string)obj); default: { if (type == typeof(IntPtr)) { return NSValue.ValueFromPointer((IntPtr)obj); } if (type == typeof(CGSize)) { return NSValue.FromSize((CGSize)obj); } if (type == typeof(CGRect)) { return NSValue.FromRectangle((CGRect)obj); } if (type == typeof(CGPoint)) { return NSValue.FromPoint((CGPoint)obj); } INativeObject nativeObject = obj as INativeObject; if (nativeObject != null) { return Runtime.GetNSObject(nativeObject.Handle); } return null; } } } public void SetValueForKeyPath(IntPtr handle, NSString keyPath) { if (keyPath == null) { throw new ArgumentNullException("keyPath"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr(Handle, selSetValueForKeyPath_Handle, handle, keyPath.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr(SuperHandle, selSetValueForKeyPath_Handle, handle, keyPath.Handle); } } public override string ToString() { return Description ?? base.ToString(); } public virtual void Invoke(NSAction action, double delay) { NSAsyncActionDispatcher obj = new NSAsyncActionDispatcher(action); PerformSelector(NSActionDispatcher.Selector, obj, delay); } public virtual void Invoke(NSAction action, TimeSpan delay) { NSAsyncActionDispatcher obj = new NSAsyncActionDispatcher(action); PerformSelector(NSActionDispatcher.Selector, obj, delay.TotalSeconds); } internal void ClearHandle() { handle = IntPtr.Zero; } protected virtual void Dispose(bool disposing) { if (disposed) { return; } disposed = true; if (handle != IntPtr.Zero) { if (disposing) { ReleaseManagedRef(); } else { NSObject_Disposer.Add(this); } } if (super != IntPtr.Zero) { Marshal.FreeHGlobal(super); super = IntPtr.Zero; } } private void InitializeObject(bool alloced) { if (alloced && handle == IntPtr.Zero && Class.ThrowOnInitFailure) { if (ClassHandle == IntPtr.Zero) { throw new Exception($"Could not create an native instance of the type '{GetType().FullName}': the native class hasn't been loaded.\nIt is possible to ignore this condition by setting CPF.Mac.ObjCRuntime.Class.ThrowOnInitFailure to false."); } throw new Exception($"Failed to create a instance of the native type '{new Class(ClassHandle).Name}'.\nIt is possible to ignore this condition by setting CPF.Mac.ObjCRuntime.Class.ThrowOnInitFailure to false."); } IsDirectBinding = (GetType().Assembly == MonoMacAssembly); if (IsDirectBinding) { IsDirectBinding = !(this is NotMonoMac); } Runtime.RegisterNSObject(this, handle); CreateManagedRef(!alloced); } private static int GetRetainCount(IntPtr @this) { return Messaging.int_objc_msgSend(@this, Selector.RetainCount); } private void UnregisterObject() { Runtime.NativeObjectHasDied(handle); } private void FreeGCHandle() { if (gchandle != IntPtr.Zero) { GCHandle.FromIntPtr(gchandle).Free(); gchandle = IntPtr.Zero; } } private void SwitchGCHandle(bool to_weak) { if (gchandle != IntPtr.Zero) { GCHandle.FromIntPtr(gchandle).Free(); } if (to_weak) { gchandle = GCHandle.ToIntPtr(GCHandle.Alloc(this, GCHandleType.WeakTrackResurrection)); } else { gchandle = GCHandle.ToIntPtr(GCHandle.Alloc(this, GCHandleType.Normal)); } } internal static void OverrideRetainAndRelease(IntPtr @class) { lock (lock_obj) { if (ReleaseTrampolineFunctionPointer == IntPtr.Zero) { retainTrampoline = RetainTrampoline; releaseTrampoline = ReleaseTrampoline; RetainTrampolineFunctionPointer = Marshal.GetFunctionPointerForDelegate(retainTrampoline); ReleaseTrampolineFunctionPointer = Marshal.GetFunctionPointerForDelegate(releaseTrampoline); } } Class.class_addMethod(@class, Selector.RetainHandle, RetainTrampolineFunctionPointer, "@@:"); Class.class_addMethod(@class, Selector.ReleaseHandle, ReleaseTrampolineFunctionPointer, "v@:"); } private static bool IsUserType(IntPtr @this) { IntPtr intPtr = object_getClass(@this); if (Class.class_getMethodImplementation(intPtr, Selector.RetainHandle) == RetainTrampolineFunctionPointer) { return true; } Type type = Class.Lookup(intPtr, throw_on_error: false); if (type != null) { return Class.IsCustomType(type); } return false; } private void CreateGCHandle(bool force_weak) { bool num = force_weak || GetRetainCount(handle) == 1; has_managed_ref = true; if (num) { gchandle = GCHandle.ToIntPtr(GCHandle.Alloc(this, GCHandleType.WeakTrackResurrection)); } else { gchandle = GCHandle.ToIntPtr(GCHandle.Alloc(this, GCHandleType.Normal)); } } private void CreateManagedRef(bool retain) { if (IsUserType(handle) && gchandle == IntPtr.Zero) { CreateGCHandle(!retain); } if (retain) { Messaging.void_objc_msgSend(handle, Selector.RetainHandle); } } private void ReleaseManagedRef() { IntPtr intPtr = handle; if (IsUserType(intPtr)) { has_managed_ref = false; } else { UnregisterObject(); } Messaging.void_objc_msgSend(intPtr, Selector.ReleaseHandle); } [DllImport("/usr/lib/libobjc.dylib")] private static extern IntPtr object_getClass(IntPtr @this); [DllImport("/usr/lib/libobjc.dylib")] private static extern IntPtr objc_msgSendSuper(ref objc_super super, IntPtr selector); private static IntPtr InvokeObjCMethodImplementation(IntPtr @this, IntPtr sel) { IntPtr cls = object_getClass(@this); IntPtr cls2 = Class.class_getSuperclass(cls); IntPtr value = Class.class_getMethodImplementation(cls, sel); IntPtr value2 = Class.class_getMethodImplementation(cls2, sel); while (value == value2) { cls2 = Class.class_getSuperclass(cls2); value2 = Class.class_getMethodImplementation(cls2, sel); } objc_super objc_super = default(objc_super); objc_super.receiver = @this; objc_super.super = cls2; return objc_msgSendSuper(ref objc_super, sel); } private static void ReleaseTrampoline(IntPtr @this, IntPtr sel) { int num = Messaging.int_objc_msgSend(@this, Selector.RetainCount); NSObject nSObject = null; if (num == 1) { nSObject = Runtime.TryGetNSObject(@this); if (nSObject != null) { nSObject.UnregisterObject(); nSObject.FreeGCHandle(); } } if (num == 2) { nSObject = Runtime.TryGetNSObject(@this); if (nSObject != null && nSObject.has_managed_ref) { nSObject.SwitchGCHandle(to_weak: true); } } InvokeObjCMethodImplementation(@this, sel); } private static IntPtr RetainTrampoline(IntPtr @this, IntPtr sel) { int num = Messaging.int_objc_msgSend(@this, Selector.RetainCount); NSObject nSObject = null; if (num == 1) { nSObject = Runtime.TryGetNSObject(@this); if (nSObject != null && nSObject.has_managed_ref) { nSObject.SwitchGCHandle(to_weak: false); } } @this = InvokeObjCMethodImplementation(@this, sel); return @this; } internal void SetAsProxy() { IsDirectBinding = true; } [Export("observeValueForKeyPath:ofObject:change:context:")] public virtual void ObserveValue(NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context) { if (keyPath == null) { throw new ArgumentNullException("keyPath"); } if (ofObject == null) { throw new ArgumentNullException("ofObject"); } if (change == null) { throw new ArgumentNullException("change"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr_IntPtr_IntPtr(Handle, selObserveValueForKeyPathOfObjectChangeContext_Handle, keyPath.Handle, ofObject.Handle, change.Handle, context); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr_IntPtr_IntPtr(SuperHandle, selObserveValueForKeyPathOfObjectChangeContext_Handle, keyPath.Handle, ofObject.Handle, change.Handle, context); } } [Export("addObserver:forKeyPath:options:context:")] public virtual void AddObserver(NSObject observer, NSString keyPath, NSKeyValueObservingOptions options, IntPtr context) { if (observer == null) { throw new ArgumentNullException("observer"); } if (keyPath == null) { throw new ArgumentNullException("keyPath"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr_UInt64_IntPtr(Handle, selAddObserverForKeyPathOptionsContext_Handle, observer.Handle, keyPath.Handle, (ulong)options, context); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr_UInt64_IntPtr(SuperHandle, selAddObserverForKeyPathOptionsContext_Handle, observer.Handle, keyPath.Handle, (ulong)options, context); } } [Export("removeObserver:forKeyPath:")] public virtual void RemoveObserver(NSObject observer, NSString keyPath) { if (observer == null) { throw new ArgumentNullException("observer"); } if (keyPath == null) { throw new ArgumentNullException("keyPath"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr(Handle, selRemoveObserverForKeyPath_Handle, observer.Handle, keyPath.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr(SuperHandle, selRemoveObserverForKeyPath_Handle, observer.Handle, keyPath.Handle); } } [Export("willChangeValueForKey:")] public virtual void WillChangeValue(string forKey) { if (forKey == null) { throw new ArgumentNullException("forKey"); } IntPtr arg = NSString.CreateNative(forKey); if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr(Handle, selWillChangeValueForKey_Handle, arg); } else { Messaging.void_objc_msgSendSuper_IntPtr(SuperHandle, selWillChangeValueForKey_Handle, arg); } NSString.ReleaseNative(arg); } [Export("didChangeValueForKey:")] public virtual void DidChangeValue(string forKey) { if (forKey == null) { throw new ArgumentNullException("forKey"); } IntPtr arg = NSString.CreateNative(forKey); if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr(Handle, selDidChangeValueForKey_Handle, arg); } else { Messaging.void_objc_msgSendSuper_IntPtr(SuperHandle, selDidChangeValueForKey_Handle, arg); } NSString.ReleaseNative(arg); } [Export("willChange:valuesAtIndexes:forKey:")] public virtual void WillChange(NSKeyValueChange changeKind, NSIndexSet indexes, NSString forKey) { if (indexes == null) { throw new ArgumentNullException("indexes"); } if (forKey == null) { throw new ArgumentNullException("forKey"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_UInt64_IntPtr_IntPtr(Handle, selWillChangeValuesAtIndexesForKey_Handle, (ulong)changeKind, indexes.Handle, forKey.Handle); } else { Messaging.void_objc_msgSendSuper_UInt64_IntPtr_IntPtr(SuperHandle, selWillChangeValuesAtIndexesForKey_Handle, (ulong)changeKind, indexes.Handle, forKey.Handle); } } [Export("didChange:valuesAtIndexes:forKey:")] public virtual void DidChange(NSKeyValueChange changeKind, NSIndexSet indexes, NSString forKey) { if (indexes == null) { throw new ArgumentNullException("indexes"); } if (forKey == null) { throw new ArgumentNullException("forKey"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_UInt64_IntPtr_IntPtr(Handle, selDidChangeValuesAtIndexesForKey_Handle, (ulong)changeKind, indexes.Handle, forKey.Handle); } else { Messaging.void_objc_msgSendSuper_UInt64_IntPtr_IntPtr(SuperHandle, selDidChangeValuesAtIndexesForKey_Handle, (ulong)changeKind, indexes.Handle, forKey.Handle); } } [Export("willChangeValueForKey:withSetMutation:usingObjects:")] public virtual void WillChange(NSString forKey, NSKeyValueSetMutationKind mutationKind, NSSet objects) { if (forKey == null) { throw new ArgumentNullException("forKey"); } if (objects == null) { throw new ArgumentNullException("objects"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_UInt64_IntPtr(Handle, selWillChangeValueForKeyWithSetMutationUsingObjects_Handle, forKey.Handle, (ulong)mutationKind, objects.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr_UInt64_IntPtr(SuperHandle, selWillChangeValueForKeyWithSetMutationUsingObjects_Handle, forKey.Handle, (ulong)mutationKind, objects.Handle); } } [Export("didChangeValueForKey:withSetMutation:usingObjects:")] public virtual void DidChange(NSString forKey, NSKeyValueSetMutationKind mutationKind, NSSet objects) { if (forKey == null) { throw new ArgumentNullException("forKey"); } if (objects == null) { throw new ArgumentNullException("objects"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_UInt64_IntPtr(Handle, selDidChangeValueForKeyWithSetMutationUsingObjects_Handle, forKey.Handle, (ulong)mutationKind, objects.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr_UInt64_IntPtr(SuperHandle, selDidChangeValueForKeyWithSetMutationUsingObjects_Handle, forKey.Handle, (ulong)mutationKind, objects.Handle); } } [Export("keyPathsForValuesAffectingValueForKey:")] public static NSSet GetKeyPathsForValuesAffecting(NSString key) { if (key == null) { throw new ArgumentNullException("key"); } return (NSSet)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(class_ptr, selKeyPathsForValuesAffectingValueForKey_Handle, key.Handle)); } [Export("automaticallyNotifiesObserversForKey:")] public static bool AutomaticallyNotifiesObserversForKey(string key) { if (key == null) { throw new ArgumentNullException("key"); } IntPtr arg = NSString.CreateNative(key); bool result = Messaging.bool_objc_msgSend_IntPtr(class_ptr, selAutomaticallyNotifiesObserversForKey_Handle, arg); NSString.ReleaseNative(arg); return result; } [Export("valueForKey:")] public virtual NSObject ValueForKey(NSString key) { if (key == null) { throw new ArgumentNullException("key"); } if (IsDirectBinding) { return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(Handle, selValueForKey_Handle, key.Handle)); } return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSendSuper_IntPtr(SuperHandle, selValueForKey_Handle, key.Handle)); } [Export("setValue:forKey:")] public virtual void SetValueForKey(NSObject value, NSString key) { if (value == null) { throw new ArgumentNullException("value"); } if (key == null) { throw new ArgumentNullException("key"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr(Handle, selSetValueForKey_Handle, value.Handle, key.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr(SuperHandle, selSetValueForKey_Handle, value.Handle, key.Handle); } } [Export("valueForKeyPath:")] public virtual NSObject ValueForKeyPath(NSString keyPath) { if (keyPath == null) { throw new ArgumentNullException("keyPath"); } if (IsDirectBinding) { return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(Handle, selValueForKeyPath_Handle, keyPath.Handle)); } return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSendSuper_IntPtr(SuperHandle, selValueForKeyPath_Handle, keyPath.Handle)); } [Export("setValue:forKeyPath:")] public virtual void SetValueForKeyPath(NSObject value, NSString keyPath) { if (value == null) { throw new ArgumentNullException("value"); } if (keyPath == null) { throw new ArgumentNullException("keyPath"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr(Handle, selSetValueForKeyPath_Handle, value.Handle, keyPath.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr(SuperHandle, selSetValueForKeyPath_Handle, value.Handle, keyPath.Handle); } } [Export("valueForUndefinedKey:")] public virtual NSObject ValueForUndefinedKey(NSString key) { if (key == null) { throw new ArgumentNullException("key"); } if (IsDirectBinding) { return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(Handle, selValueForUndefinedKey_Handle, key.Handle)); } return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSendSuper_IntPtr(SuperHandle, selValueForUndefinedKey_Handle, key.Handle)); } [Export("setValue:forUndefinedKey:")] public virtual void SetValueForUndefinedKey(NSObject value, NSString undefinedKey) { if (value == null) { throw new ArgumentNullException("value"); } if (undefinedKey == null) { throw new ArgumentNullException("undefinedKey"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr(Handle, selSetValueForUndefinedKey_Handle, value.Handle, undefinedKey.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr(SuperHandle, selSetValueForUndefinedKey_Handle, value.Handle, undefinedKey.Handle); } } [Export("setNilValueForKey:")] public virtual void SetNilValueForKey(NSString key) { if (key == null) { throw new ArgumentNullException("key"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr(Handle, selSetNilValueForKey_Handle, key.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr(SuperHandle, selSetNilValueForKey_Handle, key.Handle); } } [Export("dictionaryWithValuesForKeys:")] public virtual NSDictionary GetDictionaryOfValuesFromKeys(NSString[] keys) { if (keys == null) { throw new ArgumentNullException("keys"); } NSArray nSArray = NSArray.FromNSObjects(keys); NSDictionary result = (!IsDirectBinding) ? ((NSDictionary)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSendSuper_IntPtr(SuperHandle, selDictionaryWithValuesForKeys_Handle, nSArray.Handle))) : ((NSDictionary)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(Handle, selDictionaryWithValuesForKeys_Handle, nSArray.Handle))); nSArray.Dispose(); return result; } [Export("setValuesForKeysWithDictionary:")] public virtual void SetValuesForKeysWithDictionary(NSDictionary keyedValues) { if (keyedValues == null) { throw new ArgumentNullException("keyedValues"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr(Handle, selSetValuesForKeysWithDictionary_Handle, keyedValues.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr(SuperHandle, selSetValuesForKeysWithDictionary_Handle, keyedValues.Handle); } } [Export("exposedBindings")] public virtual NSString[] ExposedBindings() { if (IsDirectBinding) { return NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSend(Handle, selExposedBindingsHandle)); } return NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSendSuper(SuperHandle, selExposedBindingsHandle)); } [Export("valueClassForBinding:")] public virtual Class BindingValueClass(string binding) { if (binding == null) { throw new ArgumentNullException("binding"); } IntPtr arg = NSString.CreateNative(binding); Class result = (!IsDirectBinding) ? new Class(Messaging.IntPtr_objc_msgSendSuper_IntPtr(SuperHandle, selValueClassForBinding_Handle, arg)) : new Class(Messaging.IntPtr_objc_msgSend_IntPtr(Handle, selValueClassForBinding_Handle, arg)); NSString.ReleaseNative(arg); return result; } [Export("bind:toObject:withKeyPath:options:")] public virtual void Bind(string binding, NSObject observable, string keyPath, NSDictionary options) { if (binding == null) { throw new ArgumentNullException("binding"); } if (observable == null) { throw new ArgumentNullException("observable"); } if (keyPath == null) { throw new ArgumentNullException("keyPath"); } IntPtr arg = NSString.CreateNative(binding); IntPtr arg2 = NSString.CreateNative(keyPath); if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr_IntPtr_IntPtr(Handle, selBindToObjectWithKeyPathOptions_Handle, arg, observable.Handle, arg2, options?.Handle ?? IntPtr.Zero); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr_IntPtr_IntPtr(SuperHandle, selBindToObjectWithKeyPathOptions_Handle, arg, observable.Handle, arg2, options?.Handle ?? IntPtr.Zero); } NSString.ReleaseNative(arg); NSString.ReleaseNative(arg2); } [Export("unbind:")] public virtual void Unbind(string binding) { if (binding == null) { throw new ArgumentNullException("binding"); } IntPtr arg = NSString.CreateNative(binding); if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr(Handle, selUnbind_Handle, arg); } else { Messaging.void_objc_msgSendSuper_IntPtr(SuperHandle, selUnbind_Handle, arg); } NSString.ReleaseNative(arg); } [Export("infoForBinding:")] public virtual NSDictionary BindingInfo(string binding) { if (binding == null) { throw new ArgumentNullException("binding"); } IntPtr arg = NSString.CreateNative(binding); NSDictionary result = (!IsDirectBinding) ? ((NSDictionary)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSendSuper_IntPtr(SuperHandle, selInfoForBinding_Handle, arg))) : ((NSDictionary)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(Handle, selInfoForBinding_Handle, arg))); NSString.ReleaseNative(arg); return result; } [Export("optionDescriptionsForBinding:")] public virtual NSObject[] BindingOptionDescriptions(string aBinding) { if (aBinding == null) { throw new ArgumentNullException("aBinding"); } IntPtr arg = NSString.CreateNative(aBinding); NSObject[] result = (!IsDirectBinding) ? NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSendSuper_IntPtr(SuperHandle, selOptionDescriptionsForBinding_Handle, arg)) : NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSend_IntPtr(Handle, selOptionDescriptionsForBinding_Handle, arg)); NSString.ReleaseNative(arg); return result; } [Export("defaultPlaceholderForMarker:withBinding:")] public static NSObject GetDefaultPlaceholder(NSObject marker, string binding) { if (marker == null) { throw new ArgumentNullException("marker"); } if (binding == null) { throw new ArgumentNullException("binding"); } IntPtr arg = NSString.CreateNative(binding); NSObject nSObject = Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr(class_ptr, selDefaultPlaceholderForMarkerWithBinding_Handle, marker.Handle, arg)); NSString.ReleaseNative(arg); return nSObject; } [Export("setDefaultPlaceholder:forMarker:withBinding:")] public static void SetDefaultPlaceholder(NSObject placeholder, NSObject marker, string binding) { if (placeholder == null) { throw new ArgumentNullException("placeholder"); } if (marker == null) { throw new ArgumentNullException("marker"); } if (binding == null) { throw new ArgumentNullException("binding"); } IntPtr arg = NSString.CreateNative(binding); Messaging.void_objc_msgSend_IntPtr_IntPtr_IntPtr(class_ptr, selSetDefaultPlaceholderForMarkerWithBinding_Handle, placeholder.Handle, marker.Handle, arg); NSString.ReleaseNative(arg); } [Export("objectDidEndEditing:")] public virtual void ObjectDidEndEditing(NSObject editor) { if (editor == null) { throw new ArgumentNullException("editor"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr(Handle, selObjectDidEndEditing_Handle, editor.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr(SuperHandle, selObjectDidEndEditing_Handle, editor.Handle); } } [Export("commitEditing")] public virtual bool CommitEditing() { if (IsDirectBinding) { return Messaging.bool_objc_msgSend(Handle, selCommitEditingHandle); } return Messaging.bool_objc_msgSendSuper(SuperHandle, selCommitEditingHandle); } [Export("commitEditingWithDelegate:didCommitSelector:contextInfo:")] public virtual void CommitEditing(NSObject objDelegate, Selector didCommitSelector, IntPtr contextInfo) { if (objDelegate == null) { throw new ArgumentNullException("objDelegate"); } if (didCommitSelector == null) { throw new ArgumentNullException("didCommitSelector"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr_IntPtr(Handle, selCommitEditingWithDelegateDidCommitSelectorContextInfo_Handle, objDelegate.Handle, didCommitSelector.Handle, contextInfo); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr_IntPtr(SuperHandle, selCommitEditingWithDelegateDidCommitSelectorContextInfo_Handle, objDelegate.Handle, didCommitSelector.Handle, contextInfo); } } [Export("copy")] public virtual NSObject Copy() { if (IsDirectBinding) { return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend(Handle, selCopyHandle)); } return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSendSuper(SuperHandle, selCopyHandle)); } [Export("mutableCopy")] public virtual NSObject MutableCopy() { if (IsDirectBinding) { return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend(Handle, selMutableCopyHandle)); } return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSendSuper(SuperHandle, selMutableCopyHandle)); } [Export("performSelector:withObject:afterDelay:inModes:")] public virtual void PerformSelector(Selector selector, NSObject withObject, double afterDelay, NSString[] nsRunLoopModes) { if (selector == null) { throw new ArgumentNullException("selector"); } if (withObject == null) { throw new ArgumentNullException("withObject"); } if (nsRunLoopModes == null) { throw new ArgumentNullException("nsRunLoopModes"); } NSArray nSArray = NSArray.FromNSObjects(nsRunLoopModes); if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr_Double_IntPtr(Handle, selPerformSelectorWithObjectAfterDelayInModes_Handle, selector.Handle, withObject.Handle, afterDelay, nSArray.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr_Double_IntPtr(SuperHandle, selPerformSelectorWithObjectAfterDelayInModes_Handle, selector.Handle, withObject.Handle, afterDelay, nSArray.Handle); } nSArray.Dispose(); } [Export("performSelector:onThread:withObject:waitUntilDone:")] public virtual void PerformSelector(Selector selector, NSThread onThread, NSObject withObject, bool waitUntilDone) { if (selector == null) { throw new ArgumentNullException("selector"); } if (onThread == null) { throw new ArgumentNullException("onThread"); } if (withObject == null) { throw new ArgumentNullException("withObject"); } if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr_IntPtr_bool(Handle, selPerformSelectorOnThreadWithObjectWaitUntilDone_Handle, selector.Handle, onThread.Handle, withObject.Handle, waitUntilDone); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr_IntPtr_bool(SuperHandle, selPerformSelectorOnThreadWithObjectWaitUntilDone_Handle, selector.Handle, onThread.Handle, withObject.Handle, waitUntilDone); } } [Export("performSelector:onThread:withObject:waitUntilDone:modes:")] public virtual void PerformSelector(Selector selector, NSThread onThread, NSObject withObject, bool waitUntilDone, NSString[] nsRunLoopModes) { if (selector == null) { throw new ArgumentNullException("selector"); } if (onThread == null) { throw new ArgumentNullException("onThread"); } if (withObject == null) { throw new ArgumentNullException("withObject"); } if (nsRunLoopModes == null) { throw new ArgumentNullException("nsRunLoopModes"); } NSArray nSArray = NSArray.FromNSObjects(nsRunLoopModes); if (IsDirectBinding) { Messaging.void_objc_msgSend_IntPtr_IntPtr_IntPtr_bool_IntPtr(Handle, selPerformSelectorOnThreadWithObjectWaitUntilDoneModes_Handle, selector.Handle, onThread.Handle, withObject.Handle, waitUntilDone, nSArray.Handle); } else { Messaging.void_objc_msgSendSuper_IntPtr_IntPtr_IntPtr_bool_IntPtr(SuperHandle, selPerformSelectorOnThreadWithObjectWaitUntilDoneModes_Handle, selector.Handle, onThread.Handle, withObject.Handle, waitUntilDone, nSArray.Handle); } nSArray.Dispose(); } [Export("cancelPreviousPerformRequestsWithTarget:")] public static void CancelPreviousPerformRequest(NSObject aTarget) { if (aTarget == null) { throw new ArgumentNullException("aTarget"); } Messaging.void_objc_msgSend_IntPtr(class_ptr, selCancelPreviousPerformRequestsWithTarget_Handle, aTarget.Handle); } [Export("cancelPreviousPerformRequestsWithTarget:selector:object:")] public static void CancelPreviousPerformRequest(NSObject aTarget, Selector selector, NSObject argument) { if (aTarget == null) { throw new ArgumentNullException("aTarget"); } if (selector == null) { throw new ArgumentNullException("selector"); } Messaging.void_objc_msgSend_IntPtr_IntPtr_IntPtr(class_ptr, selCancelPreviousPerformRequestsWithTargetSelectorObject_Handle, aTarget.Handle, selector.Handle, argument?.Handle ?? IntPtr.Zero); } } }