1

Это должно быть так очевидно для некоторых из вас, но я не могу найти примера:Может ли обратный вызов слота сигнала сигнала C++ содержать информацию класса Objective-C/C++/Methodor (Method)?

Мне нужно для сигнала boost сигналов сигналов signal2, чтобы подключить обратный вызов слота, который является функцией или функтором класса C++, поэтому Я могу сделать обратные вызовы модели в коде контроллера Objective-C/C++.

Этот обратный вызов должен хранить класс и селектор экземпляра метода Objective-C/C++, который можно вызвать внутри функции обратного вызова C++. (Я предполагаю, что нет возможности обеспечить прямой адрес функции обратного вызова метода Objective-C/C++). Я предположил, что мне нужно создать экземпляр класса/функтора C++, чтобы СОДЕРЖАТЬ информацию для вызова метода Objective-C/C++.

Я также не уверен, могу ли я выделить класс и SEL (селектор) и сохранить их внутри экземпляра класса C++ для обратного вызова без передачи их как void *. Как только вызов C++ вызывается сигналом(), я ожидаю, что смогу преобразовать их в пригодную для использования (вызываемую) форму с помощью class_getInstanceMethod и method_getImplementation.

Кроме того, я, возможно, захочу отправить хотя бы один параметр с произвольной структурой («EventInfo») в слот из сигнала, который может предоставить информацию о характере сигнала.

Может ли кто-нибудь пролить свет на темноту?

ответ

1

Мне потребовалось много времени, но я, наконец, понял это. Это могут быть более простые способы сделать это, но я обнаружил, что мне нужно создать класс C++ в файле .mm, который действует как мост между сигналом boost :: signal2 и функцией обратного вызова Objective-C:

В CPPToCocoaModelMessageCallbacks. ч:

/* ------------------------------------------------------------------------ 
    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); 
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_