@JonB now we're getting somewhere!
Running your test gave me an interesting result, so I set up a series of three tests which nicely illustrate the issue:
import ui
import objc_util
import ctypes
v=ui.View()
#v.present('sheet')
@objc_util.on_main_thread
def test_which_works(inview):
p=inview.objc_instance.pyObject(argtypes=[], restype=ctypes.py_object)
print p
v2=ui.View()
p=v2.objc_instance.pyObject(argtypes=[], restype=ctypes.py_object)
print p
for i in range(10):
test_which_works(v)
@objc_util.on_main_thread
def test_which_is_interesting():
p=v.objc_instance.pyObject(argtypes=[], restype=ctypes.py_object)
print p
for i in range(10):
test_which_is_interesting()
@objc_util.on_main_thread
def test_which_crashes():
for i in range(10):
v3=ui.View()
p=v3.objc_instance.pyObject(argtypes=[], restype=ctypes.py_object)
print p
#test_which_crashes()
Run the above, uncommenting the crashing one to see it crash Pythonista.
So, the first test gets the pyObject of a local reference to a globally held view (it doesn't appear to matter if the view is presented or not). It also does the same thing to a locally created and held view.
The crashing test is the same scenario as in my simplest example: in a loop, create and access the pyObject of a locally created view.
The second test produces an interesting result: multiple calls to a function which attempts to access the pyObject of a global reference to a view. This one doesn't crash, but it does produce a traceback:
Traceback (most recent call last):
File "_ctypes/callbacks.c", line 315, in 'calling callback function'
File "/var/containers/Bundle/Application/7BBC6AD0-AD54-4A7F-A649-D1A5084BD15B/Pythonista3.app/Frameworks/Py2Kit.framework/pylib/site-packages/objc_util.py", line 1066, in OMMainThreadDispatcher_invoke_imp
retval = func(*args, **kwargs)
File "/private/var/mobile/Containers/Shared/AppGroup/EE2056B2-9D54-47EC-AF60-07E05B54F00C/Pythonista3/Documents/test.py", line 29, in test_which_is_interesting
p=v.objc_instance.pyObject(argtypes=[], restype=ctypes.py_object)
AttributeError: 'weakref' object has no attribute 'objc_instance'
And sure enough, if I print out what p and v are in that second test, they suddenly become weakrefs a couple iterations in. And then a few more iterations in, they suddenly lose the ability to get the objc_instance. The question is why? How does it suddenly change from a _ui.View to a weakref (with the same memory location)? Why does it continue to work for a few more iterations?
The first test is accessing a global view which is definitely held to the end. But it also accesses a local view created within the function, but that view is also technically held until the end of the function.
The crashing test creates views inside a loop inside a function, which ought to work the same as the first test.
The interesting test starts to make it clear: the only difference between it and the first test is that it accesses the global view, not a local reference to it. And that global is becoming a weakref at some point.
This must be related to what happens with @on_main_thread and the execution of the code in the interpreter thread. It's getting into some thick weeds with the inner workings of things...and I think this gets me enough info to make it work for my purposes.