2013-06-05 74 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_