如何在 pyobjc 中生成线程

How to spawn threads in pyobjc

我正在学习如何使用 pyobjc 进行一些基本的原型制作。现在我有一个主 UI 设置和一个运行主应用程序的 python 脚本。唯一的问题是当脚本运行时,脚本在主线程上运行从而阻塞 UI。

这是我在 python 中尝试使用线程导入的示例代码片段:

def someFunc(self):
    i = 0
    while i < 20:
        NSLog(u"Hello I am in someFunc")
        i = i + 1

@objc.IBAction
def buttonPress(self, sender):
    thread = threading.Thread(target=self.threadedFunc)
    thread.start()

def threadedFunc(self):
    NSLog(u"Entered threadedFunc")
    self.t = NSTimer.NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(1/150., self,self.someFunc,None, True)
    NSLog(u"Kicked off Runloop")
    NSRunLoop.currentRunLoop().addTimer_forMode_(self.t,NSDefaultRunLoopMode)

当点击按钮时,threadedFunc 中的 NSLogs 打印到控制台,但它从未进入 someFunc

所以我决定使用NSThread来启动一个线程。在 Apple 的文档中,Objective-C 调用如下所示:

(void)detachNewThreadSelector:(SEL)aSelector
                   toTarget:(id)aTarget
                 withObject:(id)anArgument

所以我将其翻译成我解释为调用 objective-c 函数的 pyobjc 规则:

detachNewThreadSelector_aSelector_aTarget_anArgument_(self.threadedFunc, self, 1)

所以在上下文中,IBAction 函数看起来像这样:

@objc.IBAction
def buttonPress(self, sender):
    detachNewThreadSelector_aSelector_aTarget_anArgument_(self.threadedFunc, self, 1)

但是当按下按钮时,我收到此消息:未定义全局名称 'detachNewThreadSelector_aSelector_aTarget_anArgument_'。

我也尝试过类似的 grand central dispatch 尝试,但同样的消息不断弹出全局名称 some_grand_central_function is not defined

显然我不理解 python 线程或 pyobjc 调用约定的细微差别,我想知道是否有人可以阐明如何进行。

翻译后的函数名应该是

detachNewThreadSelector_toTarget_withObject_(aSelector, aTarget, anArgument)

您目前正在将转换规则应用于参数部分而不是 Objective-C 调用部分。使用示例中的参数调用函数:

detachNewThreadSelector_toTarget_withObject_(self.threadedFunc, self, 1)

所以我按照下面的结构得到了我想要的结果。正如我在对评论的回复中所说:对于后台线程,NSThread 将不允许您执行某些任务。 (即更新某些 UI 元素、印刷品等)。所以我使用 performSelectorOnMainThread_withObject_waitUntilDone_ 来处理我需要在线程操作之间执行的事情。操作时间短且强度不高,因此不会对性能产生太大影响。谢谢 Michiel Kauw-A-Tjoe 为我指明了正确的方向!

def someFunc(self):
    i = 0
    someSelector = objc.selector(self.someSelector, signature='v@:')
    while i < 20:
        self.performSelectorOnMainThread_withObject_waitUntilDone(someSelector, None, False)
        NSLog(u"Hello I am in someFunc")
        i = i + 1

@objc.IBAction
def buttonPress(self, sender):
    NSThread.detachNewThreadSelector_toTarget_withObject_(self.threadedFunc, self, 1)

def threadedFunc(self):
    NSLog(u"Entered threadedFunc")
    self.t = NSTimer.NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(1/150., self,self.someFunc,None, True)
    NSLog(u"Kicked off Runloop")
    self.t.fire()