【问题标题】:Can a C++ signals2 slot callback contain Objective-C/C++ Class/Selector (Method) information?C++ 信号2 槽回调是否可以包含 Objective-C/C++ 类/选择器(方法)信息?
【发布时间】:2013-06-05 23:08:28
【问题描述】:

这对你们中的某些人来说一定很明显,但我找不到这样的例子:

我需要一个 boost::signals2 信号来连接作为 C++ 类成员函数或函子的槽回调,因此我可以将模型回调制作成 Objective-C/C++ 控制器代码。

该回调需要存储可以在 C++ 回调函数中调用的 Objective-C/C++ 方法实例的类和选择器。 (我假设没有办法实际提供 Objective-C/C++ 方法的直接回调函数地址)。我假设我需要创建一个 C++ 类/仿函数的实例来包含用于调用 Objective-C/C++ 方法的信息。

我也不确定是否可以分离出 Class 和 SEL(选择器)并将它们存储在 C++ 类的实例中以进行回调而不将它们作为 void* 传递。一旦 signal() 调用了 C++ 回调,我希望我可以使用 class_getInstanceMethod 和 method_getImplementation 将它们转换为可用(可调用)的形式。

此外,我可能希望将至少一个带有任意结构(“EventInfo”)的参数从信号发送到槽,它可以提供有关信号性质的信息。

任何人都可以照亮黑暗吗?

【问题讨论】:

    标签: c++ objective-c signals-slots boost-signals boost-signals2


    【解决方案1】:

    我花了很长时间,但我终于想通了。可能有更简单的方法可以做到这一点,但我发现我需要在 .mm 文件中创建一个 C++ 类,作为 boost::signals2 信号和 Objective-C 回调函数之间的桥梁:

    在 CPPToCocoaModelMessageCallbacks.h 中:

    /* ------------------------------------------------------------------------
        class CPPToCocoaModelMessageCallback - 
    --------------------------------------------------------------------------- */
    class CPPToCocoaModelMessageCallback
    {
    public:
        CPPToCocoaModelMessageCallback( PMD_Signal_Messenger<PrefEvent> *theSignalClass, 
                                        int         whichPrefIdxToObserve, 
                                        id          pObjCClass, 
                                        SEL         pObjCMethod);
    
        ~CPPToCocoaModelMessageCallback();
    
        void    CallBackMessage(PrefEvent* pPrefEvent);
    
    
    private:
    
        id          fpObjCClass;
        SEL         fpObjCMethod;
    
        ls_index    fWhichPrefIdxToObserve;
    
        boost::signals2::connection fTheConnection;
    
    };  // CPPToCocoaModelMessageCallback
    

    在 CPPToCocoaModelMessageCallbacks.mm 中

    /* ------------------------------------------------------------------------
        CPPToCocoaModelMessageCallback - CONSTRUCTOR
    
        whichPrefIdxToObserve - the preference idx to observe
    
        Pass the id and selector of the Objective-C/C++ object & method to be
        called.
    --------------------------------------------------------------------------- */
    CPPToCocoaModelMessageCallback::CPPToCocoaModelMessageCallback(PMD_Signal_Messenger<PrefEvent> *theSignalClass, int whichPrefIdxToObserve, id pObjCClass, SEL pObjCMethod) 
            :   fpObjCClass (pObjCClass),
                fpObjCMethod (pObjCMethod),
                fWhichPrefIdxToObserve (whichPrefIdxToObserve)
    {
        fTheConnection = theSignalClass->ObserveSignal(&CPPToCocoaModelMessageCallback::CallBackMessage, this);
    }
    
    /* ------------------------------------------------------------------------
        ~CPPToCocoaModelMessageCallback - DESTRUCTOR
    
        Pass the id and selector of the Objective-C/C++ object & method to be
        called.
    --------------------------------------------------------------------------- */
    CPPToCocoaModelMessageCallback::~CPPToCocoaModelMessageCallback()
    {
        fTheConnection.disconnect();
    }
    
    
    /* ------------------------------------------------------------------------
        CPPToCocoaModelMessageCallback::CallBackMessage - 
    
        Handles single and range-type preference change events.
    --------------------------------------------------------------------------- */
    void CPPToCocoaModelMessageCallback::CallBackMessage(PrefEvent* pPrefEvent)
    {
        // Only make the callback if this event is the preference we're observing
    
        if (pPrefEvent->GetChangedPrefIdx() == fWhichPrefIdxToObserve) {
            [fpObjCClass performSelector:fpObjCMethod];
        }
    }
    

    /////////////////////////////////////// ////////////////////////////

    在你的 controller.mm 中:

    // set up messaging from Model.  The message callback functions must be destructed in dealloc.  
    // I've done this in awakeFromNib but it could be elsewhere
    
    - (void)awakeFromNib {
    
        PMD_Signal_Messenger<MyEventKind>* theModelClass = GetMyModelClassPointer();
    
        displayMenuPrefChangedCallBack = new CPPToCocoaModelMessageCallback(theModelClass, kAppPrefDictionaryDisplayShortDef, self, @selector(displayMenuChanged));
    }
    
    
    /* ------------------------------------------------------------------------
        displayMenuChanged - this gets called when the model fires a signal
            (via CPPToCocoaModelMessageCallback::CallBackMessage())
    
    --------------------------------------------------------------------------- */
    - (void) displayMenuChanged
    {
        NSLog(@"displayMenuChanged\n");
    
        // DO SOMETHING TO RESPOND TO THE SIGNAL (in this case I'm reloading an NSWebView):
    
        [self reloadWebViewText];
    }
    

    /////////////////////////////////////// ///////////////////////////

    与模型类结合用于向观察者发出信号的类:

    PMD_Signal_Messenger.h:

    /* ------------------------------------------------------------------------
        class PMD_Signal_Messenger<MyEventKind> -
    
            This class is designed to be multiple inherited with various
            Model classes.
    --------------------------------------------------------------------------- */
    template <class MyEventKind>
    class PMD_Signal_Messenger {
    public:
    
        PMD_Signal_Messenger() { }
        ~PMD_Signal_Messenger() { }
    
            template<typename Fn, typename Obj>
                boost::signals2::connection ObserveSignal(Fn callback, Obj &object) {
                    return fSignalObservers.connect(boost::bind(callback, object, _1));
                }
    
    protected:
        boost::signals2::signal<void (MyEventKind*)> fSignalObservers;  // all observers of my preference changes
    
    private:
        PMD_Signal_Messenger(const PMD_Signal_Messenger& thePMD_Signal_Messenger)   { assert(false); }  // prevent copy constructor
    };
    

    在您要发出模型更改信号的 .cpp MODEL 文件中:

    // construct theEvent (your own struct) and fire the signal with your event structure that gets passed to CPPToCocoaModelMessageCallback::CallBackMessage()
    
    MyEventKind theEvent(someUsefulParams);
    
    fSignalObservers(&theEvent);
    

    【讨论】:

      【解决方案2】:

      您可以使用此解决方案: https://github.com/godexsoft/objc_callback

      #pragma once
      #ifndef _OBJC_CALLBACK_H_
      #define _OBJC_CALLBACK_H_
      
      template<typename Signature> class objc_callback;
      
      template<typename R, typename... Ts>
      class objc_callback<R(Ts...)>                                                              
      {                              
      public:                                                    
          typedef R (*func)(id, SEL, Ts...);                                              
      
          objc_callback(SEL sel, id obj)                  
          : sel_(sel)                                     
          , obj_(obj)                                     
          , fun_((func)[obj methodForSelector:sel])       
          {
          }     
      
          inline R operator ()(Ts... vs)
          {                                                   
              return fun_(obj_, sel_, vs...);      
          }                                                   
      private:                                                
          SEL sel_;                                           
          id obj_;                                            
          func fun_;                                          
      };      
      
      #endif // _OBJC_CALLBACK_H_
      

      【讨论】:

        猜你喜欢
        • 2010-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多