Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
212 views
in Technique[技术] by (71.8m points)

ios - How to port "method_getImplementation" and "method_setImplementation" to MonoTouch?

From my question here: Without subclassing a UIView or UIViewController: possible to catch if a subview was added?

I'm wondering how to port the code from the answer to MonoTouch. It basically replaces a method with a new one and then calls the old one without subclassing. Is it possible at all to get this pointer juggling it to work in 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);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This looks like a good candidate for us to provide a general purpose mechanism to hijack methods. Here is an implementation in pure C# code that you can use in the meantime:

    [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");
    }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...