6

从我的问题来看:没有子类化 UIView 或 UIViewController:如果添加了子视图,是否可以捕获?

我想知道如何将代码从答案移植到 MonoTouch。它基本上是用一个新方法替换一个方法,然后在没有子类化的情况下调用旧方法。是否有可能让这个指针在 MonoTouch 中工作?

//Makes views announce their change of superviews
Method method = class_getInstanceMethod([UIView class], @selector(willMoveToSuperview:));
IMP originalImp = method_getImplementation(method);

void (^block)(id, UIView*) = ^(id _self, UIView* superview) {
    [_self willChangeValueForKey:@"superview"];
    originalImp(_self, @selector(willMoveToSuperview:), superview);
    [_self didChangeValueForKey:@"superview"];
};

IMP newImp = imp_implementationWithBlock((__bridge void*)block);
method_setImplementation(method, newImp);
4

2 回答 2

9

对于我们来说,这看起来是一个很好的候选者,可以提供一个通用的机制来劫持方法。这是一个纯 C# 代码的实现,您可以同时使用:

    [DllImport ("/usr/lib/libobjc.dylib")]
    extern static IntPtr class_getInstanceMethod (IntPtr classHandle, IntPtr Selector);
    [DllImport ("/usr/lib/libobjc.dylib")]
    extern static Func<IntPtr,IntPtr,IntPtr> method_getImplementation (IntPtr method);
    [DllImport ("/usr/lib/libobjc.dylib")]
    extern static IntPtr imp_implementationWithBlock (ref BlockLiteral block);
    [DllImport ("/usr/lib/libobjc.dylib")]
    extern static void method_setImplementation (IntPtr method, IntPtr imp);

    static Func<IntPtr,IntPtr,IntPtr> original_impl;

    void HijackWillMoveToSuperView ()
    {
        var method = class_getInstanceMethod (new UIView ().ClassHandle, new Selector ("willMoveToSuperview:").Handle);
        original_impl = method_getImplementation (method);
        var block_value = new BlockLiteral ();
        CaptureDelegate d = MyCapture;
        block_value.SetupBlock (d, null);
        var imp = imp_implementationWithBlock (ref block_value);
        method_setImplementation (method, imp);
    }

    delegate void CaptureDelegate (IntPtr block, IntPtr self, IntPtr uiView);

    [MonoPInvokeCallback (typeof (CaptureDelegate))]
    static void MyCapture (IntPtr block, IntPtr self, IntPtr uiView)
    {
        Console.WriteLine ("Moving to: {0}", Runtime.GetNSObject (uiView));
        original_impl (self, uiView);
        Console.WriteLine ("Added");
    }
于 2013-01-04T03:08:18.863 回答
1

我必须对 Miguel 的示例进行以下更改才能使其在设备上运行。

        [DllImport("/usr/lib/libobjc.dylib")]
        extern static IntPtr class_getInstanceMethod(IntPtr classHandle, IntPtr Selector);

        [DllImport("/usr/lib/libobjc.dylib")]
        extern static IntPtr method_getImplementation(IntPtr method);

        [DllImport("/usr/lib/libobjc.dylib")]
        extern static IntPtr imp_implementationWithBlock(ref BlockLiteral block);

        [DllImport("/usr/lib/libobjc.dylib")]
        extern static void method_setImplementation(IntPtr method, IntPtr imp);

        static IntPtr original_impl;

        [MonoNativeFunctionWrapper]
        public delegate void OriginalDelegate(IntPtr one,IntPtr two);

        static void HijackWillMoveToSuperView()
        {
            var method = class_getInstanceMethod(new UIView().ClassHandle, new Selector("willMoveToSuperview:").Handle);
            original_impl = method_getImplementation(method);
            var block_value = new BlockLiteral();
            CaptureDelegate d = MyCapture;
            block_value.SetupBlock(d, null);
            var imp = imp_implementationWithBlock(ref block_value);
            method_setImplementation(method, imp);
        }

        delegate void CaptureDelegate(IntPtr block,IntPtr self,IntPtr uiView);

        [MonoPInvokeCallback(typeof(CaptureDelegate))]
        static void MyCapture(IntPtr block, IntPtr self, IntPtr uiView)
        {
            Console.WriteLine("Moving to: {0}", Runtime.GetNSObject(uiView));

            var del = (OriginalDelegate) Marshal.GetDelegateForFunctionPointer (original_impl,typeof(OriginalDelegate));
            del (self, uiView);

            Console.WriteLine("Added");
        }
于 2015-02-17T20:07:23.673 回答