编辑:感谢您的建议。我仍然不清楚自动释放池的实际处理方式。
这是实际的代码:
import platform, time
if (platform.system().lower() == "darwin"):
from AppKit import NSSpeechSynthesizer
from Foundation import NSAutoreleasePool
[class's init function]
def __init__(self):
if (platform.system().lower() != "darwin"):
raise NotImplementedError("Mac OS X Speech not available on this platform.")
self.ve = NSSpeechSynthesizer.alloc().init()
[function that throws the errors normally]
def say(self,text,waitForFinish=False):
pool = NSAutoreleasePool.alloc().init()
self.ve.startSpeakingString_(text)
if (waitForFinish == True):
while (self.ve.isSpeaking() == True):
time.sleep(0.1)
del pool
如果我加载 python 控制台并仅导入模块,它会因以下回溯而失败:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "audio/__init__.py", line 5, in <module>
from speech_mac import *
File "audio/speech_mac.py", line 19, in <module>
class SpeechSynthesizer(object):
File "audio/speech_mac.py", line 56, in SpeechSynthesizer
del pool
NameError: name 'pool' is not defined
看起来 Python 不知何故没有保留“池”变量的知识。我真的很困惑所有这些是如何工作的——正如我在原始帖子中所说,我并不精通 ObjC 或 OS X 框架。
我阅读了有关使用 NSAutoreleasePools 的 Apple 文档,听起来我应该完全按照你们的建议去做 - 创建池,运行通常似乎引发异常的代码,然后销毁池。但是,正如您所看到的,这并不像人们期望的那样工作。
如果我离开,del pool
那么代码确实会运行并且错误会被抑制,但是,正如原始帖子中所写,在不可预知的情况下,当应用程序实际退出时,它会因原始帖子中显示的 OS X 系统崩溃而崩溃。
我在 SO 上找到了一些很棒的代码,可以直接与 Mac OS X 的语音合成器引擎交互。它基本上导入 AppKit,实例化 NSSpeechSynthesizer,然后将其方法和内容传递给 Python。效果很好。
我将代码包装到一个类中以便于使用。
唯一的问题是,在我的应用程序中,语音在单独的线程上运行,因为它连接到 wxPython 应用程序。
在我的控制台上,每次说话时,我都会收到大量这样的消息:
objc[53229]: Object 0x53d2d30 of class OC_PythonString autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
该应用程序运行良好,但“只是泄漏”让我害怕 - 听起来我正盯着内存泄漏的桶!
在做了一些研究之后,我发现你可以像这样在 Python 中从 pyobjc 实例化一个自动释放池:
from Foundation import NSAutoreleasePool
def __init__(self):
self.pool = NSAutoreleasePool.alloc().init()
def __del__(self):
self.pool.release()
但是,这样做会阻止错误消息的出现,并且在应用程序退出时它完全命中或错过,现在我有时会遇到严重到足以显示 OS X 崩溃对话框的崩溃。控制台吐出以下内容:
objc[71970]: autorelease pool page 0x4331000 corrupted
magic 0xf0000000 0xf0000000 0x454c4552 0x21455341
pthread 0xb0811000
为了进行实验,我将池分配移到了运行时抛出原始消息的函数(Speak 函数)中。这样做也抑制了消息,但是这一次,当应用程序退出时,我得到了:
Bus error: 10
在弹出的崩溃对话框中包含以下内容:
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000000000010
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x926ec465 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 525
1 com.apple.CoreFoundation 0x99cc3a73 _CFAutoreleasePoolPop + 51
2 com.apple.Foundation 0x90fca116 -[NSAutoreleasePool release] + 125
看起来 AutoreleasePools 在对象被销毁时仍在被释放(这是有道理的),但它仍然在崩溃。
我对 OS X 中的 Objective C 或 NS 基础类并不熟悉,所以我不确定如何继续调试它。
建议?
谢谢!