omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Access to pyObject() of ObjCInstance is crashy?

    Pythonista
    objc
    3
    19
    9117
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • mikael
      mikael @JonB last edited by

      @JonB, this runs peacefully on iPhone X.

      1 Reply Last reply Reply Quote 0
      • shinyformica
        shinyformica last edited by

        @JonB well, that cracks it then, definitely something in the deep woods of the interaction between the objective-c runtime and the python interpreter. I'm going to try grafting the retry technique above to the NavigationView wrapper to see if it will make it stable.

        mikael 1 Reply Last reply Reply Quote 0
        • mikael
          mikael @shinyformica last edited by

          @shinyformica, try just using c_void_p and on_main_thread first, without any retries?

          1 Reply Last reply Reply Quote 0
          • JonB
            JonB last edited by

            I'll say when I removed on_main_thread, and only wrapped the pyObject call, it originally failed every 10th time. Later, I couldn't get it to reproduce! But c_void_p is at least safer.

            1 Reply Last reply Reply Quote 0
            • shinyformica
              shinyformica last edited by

              @mikael, @JonB I wish I had better news, but it seems that no matter whether I attempt ctypes.py_object, ctypes.c_void_p with a cast, multiple retries, on_main_thread, etc. I always eventually crash. So I am going to give up for now...the solution I have now is less efficient, but stable, and works well for my purposes.

              It's quite a bit harder to debug than the simple tests demonstrated throughout this thread. I can create tests which crash, and ones which don't by switching around the order of things and where objects are created. In the actual code, there is a ui.NavigationView, which hosts views with ui.TableView children, and those tables have data sources which respond via their action callbacks by eventually calling the code which tries to get the pyObject of the current navigation view and then push or pop a view in response. So where the issue really arises is somewhere in the complex interaction of ui thread and main thread.

              Thanks for the ideas and help!

              1 Reply Last reply Reply Quote 0
              • JonB
                JonB last edited by

                Are you getting crashes just getting c_void_p? Or during cast? C_void_p shouldn't give you a seg fault. Then your can check it is valid before using it.

                If you have access to the views you are going to push, there may be two other options.

                First, set the tag parameter on both the objc_instance and ui.View, to unique integers.

                Then you can query the tag attribute, and look up the tag in python (not sure if the tag lookup methods in python views work with navigation views)

                Or, you can actually store your own pyObject, via objc_addAssociatedObject. When the views are first created.

                objc_addAssociatedObject(view.objc_instance, sel('pyObject'), ns(id(view)), 3)
                

                Then the view can be retrieved as

                py_object.from_address(ObjCInstance(objc_getAssociatedObject(objc_view, 
                sel('pyObject'))).integerValue()).value
                

                I am using this approach to develop a more pythonic way to use create_objc_class -- using a python class to encapsulate the objc class, with method decorators that replace the |_self, _sel ` arguments with a regular self (python object) argument, which is automatically looked up from the objc object.

                You can store whatever python data you want using associated objects, just change the key (which should be a selector, of your choosing).

                (Some of this is from memory, I'll post a working example later)

                mikael 1 Reply Last reply Reply Quote 0
                • shinyformica
                  shinyformica last edited by

                  @JonB I don't really have time to dig further into it. It doesn't matter whether I attempt to get the python ui.View from the objc instance via:

                  nc = self.navigationview.objc_instance.navigationController()
                  view = nc.topViewController().view()
                  pobj = view.pyObject(argtypes=[], restype=ctypes.c_void_p)
                  

                  or

                  nc = self.navigationview.objc_instance.navigationController()
                  view = nc.topViewController().view()
                  pobj = view.pyObject(argtypes=[], restype=ctypes.py_object)
                  

                  in either case, things become unstable and eventually crashes occur, especially after trying it again. The py_object seems to crash immediately, while the c_void_p way just makes things highly unstable. Oddly, getting the value via c_void_p gives me back the actual ui.View instance, not a c_void_p object which I need to cast(), which is what I was expecting...which to me is a sign of something fishy going on. It never appears to be None, and since it's coming in as an actual ui.View instance and not ctypes.c_void_p, there's no "value" property to check.

                  I'll look at the objc_addAssociatedObject() idea, though at this point that seems about the same as just keeping a mapping entirely in python of the id of the objc view to the python ui.View object, since I'm already going to the trouble of tracking things manually.

                  1 Reply Last reply Reply Quote 0
                  • mikael
                    mikael @JonB last edited by

                    @JonB:

                    I am using this approach to develop a more pythonic way to use create_objc_class -- using a python class to encapsulate the objc class, with method decorators that replace the |_self, _sel ` arguments with a regular self (python object) argument, which is automatically looked up from the objc object.

                    Yes, please!

                    1 Reply Last reply Reply Quote 0
                    • JonB
                      JonB last edited by JonB

                      @mikael
                      Still a little work in progress, I need to find something useful to do with it.

                      https://gist.github.com/e3ea36bfd652e7ace38987714c01622c

                      @shinyformica This includes a get_associatedObject, that you could call when initializing a view.

                      set_associated_object(v.objc_instance, v)
                      ...
                      pyobj=get_associated_object(n.objc_instance.navigationController().viewControllers()[0].view())
                      
                      1 Reply Last reply Reply Quote 0
                      • shinyformica
                        shinyformica last edited by

                        @JonB regardless of the troubles I was having...that objc decorator idea is brilliant, and ought to be rolled into objc_util.

                        re: my problems with pyObject being crashy. After going over the way my code was executing, I rearranged things to be absolutely certain that all attempts to access internals via pyObject() and cast() were within a @on_main_thread...and that seemed to finally make it stable. So, though I'm not entirely clear where it was going wrong, somewhere at least one of those calls was being made outside the main thread, and was therefore making the whole thing unstable at any future call.

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post
                        Powered by NodeBB Forums | Contributors