2013-01-02 22 views
5

मेरे सवाल का यहाँ से: Without subclassing a UIView or UIViewController: possible to catch if a subview was added?मोनो टच पर "method_getIplementation" और "method_setImplementation" को पोर्ट कैसे करें?

मैं कैसे बंदरगाह 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

मैं भी उत्सुक हूं कि यह कैसे किया जा सकता है। अभी मैं सिर्फ ओबीजेसी लिब के खिलाफ जुड़ा हूं जो यह करता है। –

उत्तर

6

यह हमारे लिए एक अच्छा उम्मीदवार जैसा दिखता है ताकि विधियों को अपहरण के लिए एक सामान्य उद्देश्य तंत्र प्रदान किया जा सके।

[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

क्या आपको लगता है कि यह ऐप स्टोर सहेजा गया है? – Krumelur

+0

मैं अपहृत विधि को कैसे रीसेट कर सकता हूं और इसे मूल रूप से फिर से उपयोग कर सकता हूं? – Krumelur

+0

@ क्रूमेलर: बस 'method_setImplementation (विधि, original_impl) पर कॉल करें;' मूल पर वापस जाने के लिए। –

0

मैं इसे एक डिवाइस पर काम पाने के लिए मिगुएल के उदाहरण में निम्न परिवर्तन करना पड़ा: यहाँ शुद्ध सी # कोड में एक कार्यान्वयन है कि आप बीच में उपयोग कर सकते हैं।

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