[Beta] Fun with MapKit and objc_util
I've been experimenting a lot with the new
objc_utilmodule lately, and I thought I'd share a few more advanced examples. So here's the first...
Please note that this relies on a couple of changes I made in the very latest build (uploaded about an hour ago), and it won't work in previous betas.
The example shows how you can combine the
objc_utilmodules to create entirely new UI elements, in this case a "native"
MapView(which has been a popular feature request).
MapViewclass should be usable pretty much like any other
ui.View, but it doesn't implement all features of the underlying (fairly complex) MapKit APIs, so you might want to extend it, if you need things like satellite view etc.
Some of the code is fairly advanced, and probably requires some low-level knowledge about the Objective-C runtime to understand completely. To support being notified about scroll/zoom events, it was necessary to create a new Objective-C class that acts as the
MKMapView's delegate. Creating new Objective-C classes is quite difficult to get right, and unfortunately there isn't really a good way to make this easier. The rest of the code is hopefully easier to understand – the only other "special" thing is the use of structs that aren't supported directly by
CLLocationCoordinate2Detc.). This makes it necessary to specify the return/argument types of some method calls explicitly (via the new
Note: I haven't tested this on a 32-bit device so far, and it's possible that some minor changes are needed to make it work on both architectures.
Feel free to ask me if there's something you don't understand in the code.
Amazing, Mapview example.
Great work from my favorite IOS developer. Nice indeed!
So if I want to dive in to the deep end of the objective-C pool, any suggestions on a good book to start with?
question re: memory management... when globals are cleared when clicking RUN, does the
__del__method get called on each deleted python object ?
I am experimenting with adding buttons to the
OMTabToolBar. I was thinking one safe approach( when running my script a second time for example) would be to monkey patch del on the ui.Button to call the objective c
removeFromSuperviewbefore the object is deleted.
question re: memory management... when globals are cleared when clicking RUN, does the del method get called on each deleted python object ?
The globals are cleared using a plain old Python script. If you're curious:
import os p = os.path.abspath(os.path.join(os.__file__, '../../clearglobals.py')) with open(p) as f: print f.read()
...which is to say, the memory management should behave pretty much like everywhere else in Python.
I was thinking one safe approach( when running my script a second time for example) would be to monkey patch del on the ui.Button to call the objective c removeFromSuperview before the object is deleted.
The thing about
__del__is that implementing/monkey-patching it may actually prevent your object from ever being garbage-collected. This happens when the object is part of a reference cycle, i.e. the object directly or indirectly points to itself, which is often very hard to see because there can be multiple levels of indirection. The garbage collector is generally capable of detecting and resolving cycles (that's actually all it does in Python), but it will never free objects that are part of a cycle and implement
__del__because it cannot decide a safe order in which the objects should be freed. Those objects are added to the
gc.garbagelist, so you can easily check in the console if this is what's happening.
If you want to check if your custom view is already present in the toolbar, you could do this by assigning a unique tag, e.g. like this:
# ... existing_view = toolbar.viewWithTag_(42) if existing_view: existing_view.removeFromSuperview() ObjCInstance(replacement_view).setTag_(42) toolbar.addSubview_(replacement_view) # ...
Of course you'd still need to ensure that your view is somehow "kept alive" as long as it's in the toolbar.
Memory management, del object.
omz, thanks for that. i see that
weakref.finalizemay be a better approach than
__del__when monkeypatching the pythonista ui (or else just hanging onto references in modules)
So I know that this is a very old thread, however I have wanted to be able to emplement this kind of thing. I keep getting the following error on the the line
class_ptr = c.objc_allocateClassPair(NSObject.ptr, 'OMMapViewDelegate', 0)
argument 2: <class 'TypeError'>: wrong type
What needs to change to allow me to use this? Thanks in advance!
This probably worked in python 2.7. The string arguments need to be byte instead. The recent objc_util includes create_objc_class, which simplifies the entire class creation process, and handles strong to byte conversions.
How do I use this and setup several different types of annotations with different images for different kinds. For instance, using a picture of a light to mark a light, a picture of a bush to mark and bush, and a picture of a tree to mark a tree.
This is an updated version of @omz's original, but converted to using create_objc_class so it works in latest version.
Also, I added a delegate method which returns an annotationView, and uses the annotation title to set the image