NSThread initWithTarget:selector:object:]: 目标未实现选择器 ((null))'

问题描述 投票:0回答:1

我尝试使用 metal-cpp(源代码也可以在 here)包装器为我的应用程序实现自定义 Cocoa 主循环。

第一步是写一些类似的内容:

[NSThread detachNewThreadSelector:@selector(doNothing:)
                         toTarget:stubTarget
                         withObject:nil];

运行存根选择器(解决方案基于 GLFW 源代码)。

metal-cpp不包含

NSThread
类,所以我实现了它:

metal-cpp/Foundation/NSThread.hpp:

#pragma once

#include <functional>

#include "NSObject.hpp"

namespace NS
{

class Runnable
{
public:
    virtual ~Runnable() {}
    virtual void run() {}
};

class Thread: public NS::Referencing< Thread >
{
public:
    static void detachNewThread( const Runnable* pRunnable );
};

_NS_INLINE void NS::Thread::detachNewThread( const Runnable* pRunnable )
{
    NS::Value* pWrapper = NS::Value::value( pRunnable );

    typedef void (*DispatchFunction)( NS::Value*, SEL, void* );
    
    DispatchFunction run = []( Value* pSelf, SEL, void* unused )
    {
        auto pDel = reinterpret_cast< NS::Runnable* >( pSelf->pointerValue() );
        pDel->run();
    };

    return Object::sendMessage<void>(_NS_PRIVATE_CLS(NSThread), _NS_PRIVATE_SEL(detachNewThreadSelector_toTarget_withObject_), run, pWrapper, nullptr );
}

}

我还在

metal-cpp/Foundation/NSPrivate.hpp
: 中注册了新的 _NS_PRIVATE_SEL

变体
_NS_PRIVATE_DEF_SEL(detachNewThreadSelector_toTarget_withObject_,
    "detachNewThreadSelector:toTarget:withObject:");

最后,我将

NSThread
纳入主标题
metal-cpp/Foundation/Foundation.hpp

NSThread
的源代码是在研究
NSApplication
的源代码和Apple参考文献时编写的。我不了解 Objective-C,它的代码对我来说有点神奇。

后来,我在我的应用程序中调用

NSThread::detachNewThread()

class MainLoopTarget: public NS::Runnable
{
    public:
        void run() override
        {
            std::cout << "run()" << std::endl;
        }
};

auto target = new MainLoopTarget();
NS::AutoreleasePool* autorelease_pool = NS::AutoreleasePool::alloc()->init();

NS::Thread::detachNewThread(target);

autorelease_pool->release();
delete target;

它因错误而崩溃:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSThread initWithTarget:selector:object:]: target does not implement selector ((null))'
*** First throw call stack:
(
        0   CoreFoundation                      0x00000001856aeccc __exceptionPreprocess + 176
        1   libobjc.A.dylib                     0x0000000185196788 objc_exception_throw + 60
        2   Foundation                          0x00000001867641d0 -[NSThread setQualityOfService:] + 0
        3   Foundation                          0x00000001867c1118 +[NSThread detachNewThreadSelector:toTarget:withObject:] + 60
        4   libb3engine.dylib                   0x000000010506bb88 _ZN2b38platform6darwin9DarwinApp5startEv + 336
        5   B3                                  0x0000000104b7dd4c main + 252
        6   dyld                                0x00000001851d20e0 start + 2360
)
libc++abi: terminating due to uncaught exception of type NSException

我知道类方法的参数有问题,但我的 Objective-C 技能还不足以了解哪里和什么。

c++ objective-c foundation nsthread
1个回答
0
投票

好吧,我犯了错误。正确的实现如下:

metal-cpp/Foundation/NSPrivate.hpp 中

_NS_PRIVATE_DEF_SEL(detachNewThreadSelector_toTarget_withObject_,
    "detachNewThreadSelector:toTarget:withObject:");
_NS_PRIVATE_DEF_SEL(run_,
    "run:");

metal-cpp/Foundation/NSThread.hpp:

_NS_INLINE void NS::Thread::detachNewThread( const Runnable* pRunnable )
{
    NS::Value* pWrapper = NS::Value::value( pRunnable );

    typedef void (*DispatchFunction)( NS::Value*, SEL, void* );
    
    DispatchFunction run = []( Value* pSelf, SEL, void* unused )
    {
        auto pDel = reinterpret_cast< NS::Runnable* >( pSelf->pointerValue() );
        pDel->run();
    };

    // Register the class method on Objective-C side
    class_addMethod( (Class)_NS_PRIVATE_CLS( NSValue ), _NS_PRIVATE_SEL( run_ ), (IMP)run, "v@:@" );
    // Here we call an Objective-C side's selector
    return Object::sendMessage<void>(_NS_PRIVATE_CLS(NSThread), _NS_PRIVATE_SEL(detachNewThreadSelector_toTarget_withObject_), _NS_PRIVATE_SEL(run_), pWrapper, nullptr );
}
© www.soinside.com 2019 - 2024. All rights reserved.