*** __NSAutoreleaseNoPool(): Object 0x1040bf0f0 of class NSCFString autoreleased with no pool in place - just leaking
Found a way to get rid of these leakages. We need an NSAutoreleasePool to take care of all actions that happen under threads.
So if you have a CPU/disk/network heavy operation in a module that you're importing into say, a window controller, start them under an NSThread like this -
# foo_module.py
def do_heavy_task((callback, arg1, arg2)):
...
... # all heavy ops here
...
callback(message)
and in the controller -
import foo_module
...
...
class Controller_MainWindow(NSWindowController):
...
...
@IBAction
def btnFoo_Click_(self,sender):
thread = NSThread.detachNewThreadSelector_toTarget_withObject_(
'start_heavy_task',self, (self.return_heavy_task, arg1, arg2) )
def start_heavy_task(self, params):
pool = NSAutoreleasePool.alloc().init()
foo_module.do_heavy_task(params)
del pool
def return_heavy_task(self, msg):
NSLog(msg)
...
Why all the call spaghetti with start_heavy_task, etc?
The issue is with detachNewThreadSelector_toTarget_withObject_ where I haven't been able to figure out how to pass a module's function as selector and the module as object. Also in this way your foo_module can remain independent of cocoa/objc/Foundation pollutions.
Anyhow, this works out into a clean solution. In case you have all your logical code in the window controller itself, you would find
this programmish article extremely useful.
Update: a much better way would be to use decorators :D
def AutoPooled(f):
def pooled_func(self):
pool = NSAutoreleasePool.alloc().init()
f(self)
del pool
return pooled_func
Now your start_heavy_task function becomes -
@AutoPooled
def start_heavy_task(self, params):
foo_module.do_heavy_task(params)
How fantastic :D
Labels: cocoa, pyobjc, python