2013-01-02 10 views
5

Z mojego pytania tutaj: Without subclassing a UIView or UIViewController: possible to catch if a subview was added?Jak przenieść "method_getImplementation" i "method_setImplementation" do MonoTouch?

Zastanawiam się, jak przenieść kod z odpowiedzi na MonoTouch. Zasadniczo zamienia metodę na nową, a następnie wywołuje starą bez podklasy. Czy to możliwe, aby ten wskaźnik żonglował nim w 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); 
+0

Jestem również ciekawy, jak to można zrobić. Właśnie teraz łączę się z biblioteką ObjC, która to robi. –

Odpowiedz

6

To wygląda na to, że jesteśmy dobrym kandydatem do zapewnienia mechanizmu przejęcia kontroli nad ogólnym celem. Oto implementacja w czystym kod C#, które można używać w międzyczasie:

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

Czy myślisz, że to jest App Store? – Krumelur

+0

Jak zresetować przejęta metodę i ponownie użyć oryginalnej? – Krumelur

+0

@ Krumelur: Po prostu wywołaj 'method_setImplementation (method, original_impl);', aby powrócić do oryginalnego. –

0

musiałem wprowadzić następujące zmiany do przykładu Miguel aby dostać pracy na urządzeniu.

 [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"); 
     } 
Powiązane problemy