1#!/usr/bin/env python 2""" 3Experimental code, attempting to work around Apple's KVO hacks. 4""" 5 6from Foundation import * 7import objc 8from sets import Set 9import sys 10 11_kvoclassed = {} 12 13def dumpClass(cls): 14 print "DUMP", cls 15 print cls.__bases__ 16 #for k, v in cls.__dict__.items(): 17 # print k, v 18 print "-"*40 19 20 21def toKVOClass(orig, new): 22 if new in _kvoclassed: 23 return new 24 origdct = dict(orig.__dict__) 25 origset = Set(origdct) 26 newset = Set(new.__dict__) 27 # Merge in non-methods from the dict 28 for key in (origset - newset): 29 value = origdct[key] 30 if isinstance(value, objc.selector): 31 continue 32 setattr(new, key, value) 33 # Remember the original class, 34 # KVO wants to go back to NSObject! 35 _kvoclassed[new] = orig 36 return new 37 38def fromKVOClass(new): 39 return _kvoclassed[new] 40 41class FooClass(NSObject): 42 _kvc_bar = None 43 outlet = objc.IBOutlet('outlet') 44 45 def XXaddObserver_forKeyPath_options_context_(self, observer, keyPath, options, context): 46 print 'addObserver_forKeyPath_options_context_', observer, keyPath, options, context 47 orig = FooClass #type(self) 48 super(orig, self).addObserver_forKeyPath_options_context_(observer, keyPath, options, context) 49 new = self.class__() 50 print orig, type(self), new 51 if orig is not new: 52 print "class changed!!" 53 self.__class__ = toKVOClass(orig, new) 54 55 def XXremoveObserver_forKeyPath_(self, observer, keyPath): 56 print 'removeObserver_forKeyPath_', observer, keyPath 57 orig = type(self) 58 super(orig, self).removeObserver_forKeyPath_(observer, keyPath) 59 new = self.class__() 60 print orig, type(self), new 61 if orig is not new: 62 print "class changed!!" 63 self.__class__ = fromKVOClass(orig) 64 65 def setBar_(self, bar): 66 print 'setBar_ ->', bar 67 print self, type(self), self.class__() 68 #print '->', bar 69 self._kvc_bar = bar 70 setBar_ = objc.accessor(setBar_) 71 72 def bar(self): 73 print 'bar', self._kvc_bar 74 #print self, type(self), self.class__() 75 return self._kvc_bar 76 bar = objc.accessor(bar) 77 78class FooObserver(NSObject): 79 def observeValueForKeyPath_ofObject_change_context_(self, keyPath, obj, change, context): 80 print '[[[[[]]]]] observeValueForKeyPath_ofObject_change_context_', keyPath, obj, change, context 81 dumpClass(type(obj)) 82 83 def willChangeValueForKey_(self, key): 84 print '[[[[[]]]]] willChangeValueForKey_', key 85 86foo = FooClass.alloc().init() 87fooObserver = FooObserver.alloc().init() 88 89print 90print 91print "***** unobserved set" 92print foo.bar() 93foo.setBar_(u'0shw00t') 94print foo.bar() 95 96print 97print 98print "***** observing, setting three times" 99print "foo's ISA:", foo.pyobjc_ISA 100print "Adding an observer" 101foo.addObserver_forKeyPath_options_context_(fooObserver, u'bar', (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld), 0) 102print "foo's ISA:", foo.pyobjc_ISA 103#foo.removeObserver_forKeyPath_(fooObserver, u'bar');sys.exit(1) 104print foo.bar() 105foo.setBar_(u'1w00t') 106print foo.bar() 107foo.setBar_(u'2sw00t') 108print foo.bar() 109foo.setBar_(u'3shw00t') 110print foo.bar() 111 112print 113print 114print "***** removing the observer and setting twice (unobserved)" 115foo.removeObserver_forKeyPath_(fooObserver, u'bar') 116print foo.bar() 117foo.setBar_(u'4sw00t') 118print foo.bar() 119foo.setBar_(u'5w00t') 120print foo.bar() 121 122print foo.__class__ 123