#!/usr/bin/env python
"""
Experimental code, attempting to work around Apple's KVO hacks.
"""
from Foundation import *
import objc
from sets import Set
import sys
_kvoclassed = {}
def dumpClass(cls):
print "DUMP", cls
print cls.__bases__
#for k, v in cls.__dict__.items():
# print k, v
print "-"*40
def toKVOClass(orig, new):
if new in _kvoclassed:
return new
origdct = dict(orig.__dict__)
origset = Set(origdct)
newset = Set(new.__dict__)
# Merge in non-methods from the dict
for key in (origset - newset):
value = origdct[key]
if isinstance(value, objc.selector):
continue
setattr(new, key, value)
# Remember the original class,
# KVO wants to go back to NSObject!
_kvoclassed[new] = orig
return new
def fromKVOClass(new):
return _kvoclassed[new]
class FooClass(NSObject):
_kvc_bar = None
outlet = objc.IBOutlet('outlet')
def XXaddObserver_forKeyPath_options_context_(self, observer, keyPath, options, context):
print 'addObserver_forKeyPath_options_context_', observer, keyPath, options, context
orig = FooClass #type(self)
super(orig, self).addObserver_forKeyPath_options_context_(observer, keyPath, options, context)
new = self.class__()
print orig, type(self), new
if orig is not new:
print "class changed!!"
self.__class__ = toKVOClass(orig, new)
def XXremoveObserver_forKeyPath_(self, observer, keyPath):
print 'removeObserver_forKeyPath_', observer, keyPath
orig = type(self)
super(orig, self).removeObserver_forKeyPath_(observer, keyPath)
new = self.class__()
print orig, type(self), new
if orig is not new:
print "class changed!!"
self.__class__ = fromKVOClass(orig)
def setBar_(self, bar):
print 'setBar_ ->', bar
print self, type(self), self.class__()
#print '->', bar
self._kvc_bar = bar
setBar_ = objc.accessor(setBar_)
def bar(self):
print 'bar', self._kvc_bar
#print self, type(self), self.class__()
return self._kvc_bar
bar = objc.accessor(bar)
class FooObserver(NSObject):
def observeValueForKeyPath_ofObject_change_context_(self, keyPath, obj, change, context):
print '[[[[[]]]]] observeValueForKeyPath_ofObject_change_context_', keyPath, obj, change, context
dumpClass(type(obj))
def willChangeValueForKey_(self, key):
print '[[[[[]]]]] willChangeValueForKey_', key
foo = FooClass.alloc().init()
fooObserver = FooObserver.alloc().init()
print
print
print "***** unobserved set"
print foo.bar()
foo.setBar_(u'0shw00t')
print foo.bar()
print
print
print "***** observing, setting three times"
print "foo's ISA:", foo.pyobjc_ISA
print "Adding an observer"
foo.addObserver_forKeyPath_options_context_(fooObserver, u'bar', (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld), 0)
print "foo's ISA:", foo.pyobjc_ISA
#foo.removeObserver_forKeyPath_(fooObserver, u'bar');sys.exit(1)
print foo.bar()
foo.setBar_(u'1w00t')
print foo.bar()
foo.setBar_(u'2sw00t')
print foo.bar()
foo.setBar_(u'3shw00t')
print foo.bar()
print
print
print "***** removing the observer and setting twice (unobserved)"
foo.removeObserver_forKeyPath_(fooObserver, u'bar')
print foo.bar()
foo.setBar_(u'4sw00t')
print foo.bar()
foo.setBar_(u'5w00t')
print foo.bar()
print foo.__class__
|