Hi --
After much hunting with google and through the content on the pyobjc
website, I was unable to find documentation on how one creates a class
method. I was, in particular, wanting to add a class method to an
existing Foundation class (for use only on the Python side of the
bridge, though I can imagine wanting to have access from the
Objective-C runtime as well). Is there an official, approved of way
of doing this?
After some experimentation and poking at source code, I did get this to work:
>>> def foo(arg, *args):
... print arg, args
...
>>> foo = objc.selector(foo)
>>> NSObject.__class__.foo = foo
>>> NSObject.foo()
<objective-c class NSObject at 0xa06bdcc0> ()
>>> NSObject.foo(1, 2, 3)
<objective-c class NSObject at 0xa06bdcc0> (1, 2, 3)
I'm unsure if setting attributes of a class's __class__ attribute is
frowned upon for some reason, or if there were a better way. Note, I
haven't tried to access any such function from Objective-C code. If
someone knows, after doing the above, would it work?
The hunt to figure this out came out of a desire to have an alternate
'syntax' to call objective-C methods from python code. Instead of:
>>> d = NSMutableDictionary.alloc().init()
>>> d.setObject_forKey_(5, "foo")
I wanted the option of saying something more like:
>>> d = NSMutableDictionary.alloc().init()
>>> d.call( "setObject:", 5,
"forKey:", "foo")
Mostly for aesthetic/readibility (and sane line wrapping in the editor) reasons.
I was able to write such a function "call", and with modest testing,
it seems to work just fine. I'm wondering a few things:
* is there some facility that I missed that already allows for
something like this?
* is this a bad and/or insane idea? if so, why? what sort of gotchas
are lurking out there if I were to add a "call" function to NSObject
(both instance and class method) and then use it in my code?
* if this is not an insane idea, and there is no facility like this
already in place, should there / could there be something like this
available in pyobjc?
My little proof of concept code is below.
Thanks,
Matt Anderson
======================================================================
#!/usr/bin/env python
from Foundation import *
import objc
def call(self, *arg):
if len(arg) == 0:
return None
elif len(arg) == 1:
sel = arg[0]
return getattr(self,sel)()
elif len(arg) % 2 == 0:
sel = "".join(arg[::2]).replace(":","_")
callargs = arg[1::2]
return getattr(self,sel)(*callargs)
else:
raise Exception("selector plus arguments must be even in number!")
call = objc.selector(call)
NSObject.call = call
NSObject.__class__.call = call
d = NSMutableDictionary.alloc().init()
d.call( "setObject:", 5,
"forKey:", "foo")
print d
# prints {
# foo = 5;
#}
print d.call("valueForKey:", "foo")
# prints 5
print d.call("className")
# prints NSCFDictionary
print NSUserDefaults.call('standardUserDefaults')
# prints <NSUserDefaults: 0x355870>
o = NSObject.alloc().init()
print NSObject.call("description")
# prints NSObject
print o.call("description")
# prints <NSObject: 0x361810>
|