2013-06-05 45 views
1

这必须是非常明显的一些你,但我不能找到这样一个例子:C++信号2槽回调是否可以包含Objective-C/C++类/选择器(方法)信息?

我需要一个boost :: signals2信号连接一个插槽回调是一个C++类的成员函数或仿函数,所以我可以将模型回调变成Objective-C/C++控制器代码。

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

我也不能确定我是否能分离出类和SEL(选择),并将其存储回调C++类的实例里面,而不将它们作为无效*。一旦C++回调由信号()调用,我期望我可以将它们转换为可用(可调用)形式class_getInstanceMethod和method_getImplementation。

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

谁能请照在黑暗里一些轻?

回答

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模型文件:

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

MyEventKind theEvent(someUsefulParams); 

fSignalObservers(&theEvent); 
1

您可以使用此解决方案: 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_