c++ - C++ signals2 槽回调是否可以包含 Objective-C/C++ 类/选择器(方法)信息?

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

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

我需要一个 boost::signals2 信号来连接作为 C++ 类成员函数或仿函数的槽回调,这样我就可以将模型回调放入 Objective-C/C++ Controller 代码中。

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

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

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

有谁能为黑暗点亮光明吗?

最佳答案

我花了很长时间,但我终于弄明白了。可能有更简单的方法来做到这一点,但我发现我需要在 .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);

关于c++ - C++ signals2 槽回调是否可以包含 Objective-C/C++ 类/选择器(方法)信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16951328/

相关文章:

c++ - 如何在 popen 函数 C++ 中插入计时器?

c++ - 移出的对象是否应该保留在 "safe"状态?

c++ - 更改 {} 和访问修饰符的 Clang 格式

ios - 如何将 UITableViewCell 显示为选中状态并仍然接收 didDeselectRowAtIndexPath

c++ - QCheckBox 检测标签上的点击

C++模板函数在 header 中编译但未在实现中编译

ios - 如何在数组中有多个图像路径?

php - JSON从mysql数据库获取和推送

python - wxpython 中的事件绑定(bind)仅适用于最后一个

python - QThread 不发出完成信号