Archive for the 'Skyward App Company' Category

A Critical Weakness

Closed

Last week, I touched on a tricky implementation of an eventListener. One object could register to receive events by another by implementing the appropriate protocol and then adding itself to an eventListeners array.

The code assumes you are utilizing ARC, the automatic reference counting system implemented in the newer objective-c releases. This frees us from the majority of memory management, and banishes the days of retain/release/autorelease. Unfortunately, it also introduces a tricky memory problem here.

CyclicReferences

Because our view controller stores a reference to the CharacterData object, the CharacterData object won’t be freed as long as the view controller exists. But since the view controller has been added to the eventListener array on the CharacterData object, the reverse is also true – the view controller won’t be freed as long as the CharacterData object exists! This is called a circular reference, and prevents either of those objects from every being freed! Obviously if we have a lot of these objects and listeners, this can add up to a real problem.

We can create a simple situation that demonstrates this:

// Dancer.h
  1. // A Dancer
  2. @interface Dancer : NSObject
  3.  
  4. // Strong reference to our dance partner.
  5. @property Dancer* dancePartner;
  6.  
  7. // We log on dealloc.
  8. (void) dealloc;
  9.  
  10. // A static method for creating a dance pair.
  11. + (void) createDancePair;
  12.  
  13. @end
// Dancer.m
  1. @implementation Dancer
  2.  
  3. // We log on dealloc.
  4. (void) dealloc
  5. {
  6.     NSLog(@"Dancer %p was deallocated", self);
  7. }
  8.  
  9. + (void) createDancePair
  10. {
  11.     Dancer* man = [[Dancer alloc] init];
  12.     Dancer* woman = [[Dancer alloc] init];
  13.     man.dancePartner = woman;
  14.     woman.dancePartner = man;
  15.  
  16.     // Leaving scope should dealloc both dancers, but…
  17. }
  18.  
  19. @end

The standard fix to this is to make a weak reference. A weak reference is a reference that is valid as long as the target object exists, but doesn’t count towards keeping the target object alive. That is to say, as long as something else refers to the object, it will exist, but as soon as there are no other references that aren’t weak (aka strong references), the object will be freed.

There are two syntaxes, depending on where you declare it:

  1. @interface WeakReferenceExample : NSObject
  2. {
  3.     __weak NSObject* weakVariable;
  4. }
  5.  
  6. @property (weak) NSObject* weakProperty;
  7. @end

And as an added boon, the weak references will be set to nil when the target object is freed. So we can fix our very contrived example with a simple ‘weak’ keyword like so:

  1. // A Dancer
  2. @interface Dancer : NSObject
  3.  
  4. // Strong reference to our dance partner.
  5. @property (weak) Dancer* dancePartner;
  6.  
  7. // We log on dealloc.
  8. (void) dealloc;
  9.  
  10. // A static method for creating a dance pair.
  11. + (void) createDancePair;
  12.  
  13. @end

Now, when the dancers go out of scope at the end of the createDancePair method, the dealloc method is actually invoked on both, proving that they’ve been correctly destroyed.

Unfortunately, it isn’t immediately obvious how to apply this to our original problem. The issue is with the NSMutableArray, which always takes a strong reference. Making our reference to the array weak doesn’t work, because the array will simply be immediately freed. The solution here requires a wrapper class.

By creating a class whose sole purpose is to store a weak reference to another object, we can circumvent the NSArray problem.

// WeakWrapper.h
  1. @interface WeakWrapper : NSObject
  2.  
  3. // The weak reference to the actual object
  4. @property (weak,atomic,readonly) id object;
  5.  
  6. // Basic initializer with the actual object
  7. (id) initWithObject:(id)object;
  8.  
  9. @end
// WeakWrapper.m
  1. @implementation WeakWrapper
  2.  
  3. // The weak reference to the actual object
  4. @synthesize object;
  5.  
  6. // Basic initializer with the actual object
  7. (id) initWithObject:(id)pobject
  8. {
  9.     if((self = [super init]))
  10.     {
  11.         // Store the weak reference.  This will become nil automatically when this object is disposed of.
  12.         object = pobject;
  13.     }
  14.     return self;
  15. }
  16.  
  17. @end

This does mean we have to be aware of the fact that we’re using this wrapper class. It doesn’t really make sense to expose the raw array and hope that no one does it incorrectly, so we will hide the internals and provide accessor functions.

// CharacterData.m
  1. // NEW: Add a new listener into the list
  2. (void) addEventListener:(NSObject*)listener
  3. {
  4.     // Wrap the incoming object in a weak reference wrapper
  5.     WeakWrapper* wrapper = [[WeakWrapper alloc] initWithObject:listener];
  6.     [eventListeners addObject:wrapper];
  7. }
  8.  
  9. // NEW: Remove the specified listener from the list
  10. (void) removeEventListener:(NSObject*)listener
  11. {
  12.     NSArray* localEventListeners = [eventListeners copy];
  13.     // emit the event to any interested listeners
  14.     for(WeakWrapper* wrapper in localEventListeners)
  15.     {
  16.         // Try to get out the real object into a temporary strong reference
  17.         NSObject* delegate = wrapper.object;
  18.  
  19.         // Remove this if it's nil or our object
  20.         if(delegate == nil || delegate == listener)
  21.         {
  22.             [eventListeners removeObject:wrapper];
  23.         }
  24.     }
  25. }
  26.  
  27. (void) emitPropertyChangedEvent:(NSString*)propertyName
  28. {
  29.     NSArray* localEventListeners = [eventListeners copy];
  30.     // emit the event to any interested listeners
  31.     for(WeakWrapper* wrapper in localEventListeners)
  32.     {
  33.         // Try to get out the real object into a temporary strong reference
  34.         NSObject* delegate = wrapper.object;
  35.  
  36.         // If this is nil, then the object has been deallocated so we can remove the wrapper
  37.         if(delegate == nil)
  38.         {
  39.             [eventListeners removeObject:wrapper];
  40.         }
  41.         // Otherwise send it the event if it responds
  42.         else if([delegate respondsToSelector:@selector(characterData:propertyChanged:)])
  43.         {
  44.             [delegate characterData:self propertyChanged:propertyName];
  45.         }
  46.     }
  47. }

We clean up any dead references whenever we iterate through the event listeners.

Now, objects can listen for events from other objects, but not be kept alive by them. We can implement our original design with impunity.

Example XCode iOS project: WeakReferenceProject

An Aspect of Aspect-Oriented Programming

Closed

Today I’d like to explain a solution I’ve cobbled together for what tends to be a rather common design obstacle. Imagine, if you will, that we’re creating a simple game and we’re trying to display the main character’s stats on screen in some fashion. The exact UI isn’t important, so lets just start with the data object that represents the main character.

// CharacterData.h
  1. @interface CharacterData : NSObject
  2.  
  3. @property NSInteger combatSkill;
  4. @property NSInteger endurance;
  5. @property NSInteger baseArmor;
  6. @property NSInteger equipmentArmor;
  7. @property (readonly) NSInteger totalArmor;
  8.  
  9. @end

We have a basic character with four stored stats, and one derived stat (totalArmor just returns base + equipment). We can change the values by just assigning to them easily enough.
Now lets say we have a view hooked up to display the character’s data to the user. This view needs to be updated any time the data changes. We can use the Observer Pattern for this. Wikipedia has the following to say about it:

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

Unfortunately, this can be a bit cumbersome in objective-c. We would have to write a custom setter for every property that emitted the appropriate event. Perhaps there’s a way we can simply… intercept all property sets?

You’ve probably guessed that I’m about to propose a solution. Before I do, let me introduce NSProxy with a quote from the apple documentation:

NSProxy is an abstract superclass defining an API for objects that act as stand-ins for other objects or for objects that don’t exist yet. Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or transform itself into) the real object.

In a nutshell, this will allow us to create an object to stand in for our CharacterData object and inspect incoming messages before passing them on to the original CharacterData object. If we see a ‘property set’ message come in, then we can emit an event. Let’s give it a shot.

// PropertyEventProxy.h
  1. @interface PropertyEventProxy : NSProxy
  2. {
  3.   id _proxiedObject;
  4.   SEL _eventSelector;
  5.   NSDictionary* _setterMap;
  6. }
  7.  
  8. (id) initWithProxiedObject:(id)proxyObject eventSelector:(SEL)eventSelector;
  9. @end
// PropertyEventProxy.m
  1. @implementation
  2. (id) initWithProxiedObject:(id)proxyObject eventSelector:(SEL)eventSelector
  3. {
  4.   // NSProxy does NOT inherit from NSObject, so there's no super implementation to invoke
  5.   _proxiedObject = proxyObject;
  6.   _eventSelector = eventSelector;
  7.  
  8.   NSMutableDictionary* registeredProperties = [NSMutableDictionary dictionary];
  9.  
  10.   // Loop through and find all assignable properties
  11.   unsigned int propertyCount = 0;
  12.   objc_property_t* propertyList = class_copyPropertyList([_proxiedObject class], &propertyCount);
  13.   for(int i = 0; i < propertyCount; ++i)
  14.   {
  15.     // turn this into a property selector
  16.     NSString* propertyName = [NSString stringWithUTF8String:property_getName(propertyList[i])];
  17.     NSString *propertySetterName = [NSString stringWithFormat:@"set%@:",
  18.     [propertyName stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[propertyName substringToIndex:1] capitalizedString]]];
  19.  
  20.     [registeredProperties setObject:propertyName forKey:propertySetterName];
  21.   }
  22.   _setterMap = [registeredProperties copy];
  23.   return self;
  24. }
  25.  
  26. @end

This gives us the basic object that tracks what it is proxying, and takes an ‘event emitter’ selector it will invoke on the proxied object when there is a ‘property set’. When this proxy object is initialized, we query the proxied object to find all of its properties. From the property names we build up the signature to expect for the set method, and store it by mapping it to the actual property name for lookup later.

The magic comes in overloading the forwardingTargetForSelector: method. Again from apple’s documentation:

If an object implements (or inherits) this method, and returns a non-nil (and non-self) result, that returned object is used as the new receiver object and the message dispatch resumes to that new object.

So, in essence, our proxy object gets to peek at every message that is going to the data object, before asking the runtime to pass it on to the original object. In this case, we check to see if the message matches the signature of a know property setter. If it does, we invoke the ‘event’ selector on the original object and pass it the name of the property that changed.

// PropertyEventProxy.m
  1. // Other code from above
  2. (id)forwardingTargetForSelector:(SEL)aSelector
  3. {
  4.   NSString* selectorName = [NSString stringWithUTF8String:sel_getName(aSelector)];
  5.   NSString* propertyNameMatch = [_setterMap objectForKey:selectorName];
  6.   if(propertyNameMatch != nil)
  7.   {
  8.     // This matches a property setter we're looking for, so trigger the event!
  9.     [_proxiedObject performSelector:_eventSelector withObject:propertyNameMatch];
  10.   }
  11.   // Pass back the proxied object so the method will get called on the actual object next
  12.   return _proxiedObject;
  13. }

Now we just need to fix up our original data object a little to emit the event, and actually use the proxy.

// CharacterData.h
  1.  
  2. // A Protocol that other objects can implement to register for CharacterData property change events
  3. @protocol CharacterDataEventListener
  4. // Invoked whenever an assignment is made to a property
  5. (void) characterData:(CharacterData*)data propertyChanged:(NSString*)propertyName;
  6. @end
  7.  
  8. @interface CharacterData : NSObject
  9.  
  10. // Existing properties here
  11. @property NSInteger combatSkill;
  12. @property NSInteger endurance;
  13. @property NSInteger baseArmor;
  14. @property NSInteger equipmentArmor;
  15. @property (readonly) NSInteger totalArmor;
  16.  
  17. // NEW: A list of entities listening to a property change event
  18. @property (readonly) NSMutableArray* eventListeners;
  19.  
  20. // NEW: Send the event to any listeners
  21. (void) emitPropertyChangedEvent:(NSString*)propertyName;
  22.  
  23. @end
// CharacterData.m
  1. @implementation CharacterData
  2.  
  3. @synthesize eventListeners, combatSkill, endurance, baseArmor, equipmentArmor;
  4. @dynamic totalArmor;
  5.  
  6. (id) init
  7. {
  8.   if((self = [super init]))
  9.   {
  10.     eventListeners = [NSMutableArray array];
  11.     // Anything custom to be done here    
  12.   }
  13.   // Now, very sneakily – return the proxy object instead of self!
  14.   return [[PropertyEventProxy alloc] initWithProxiedObject:self eventSelector:@selector(emitPropertyChangedEvent:)];
  15. }
  16.  
  17. (void) emitPropertyChangedEvent:(NSString*)propertyName
  18. {
  19.   // emit the event to any interested listeners
  20.   for(NSObject* delegate in self.eventListeners)
  21.   {
  22.     if([delegate respondsToSelector:@selector(characterData:propertyChanged:)])
  23.     {
  24.       [delegate characterData:self propertyChanged:propertyName];
  25.     }
  26.   }
  27. }
  28.  
  29. // Implementation for the derived totalArmor stat.
  30. (NSInteger) totalArmor
  31. {
  32.   return self.baseArmor + self.equipmentArmor;
  33. }
  34.  
  35. @end

You can see here that we’ve created an array property (eventListeners) that objects can assign themselves to in order to receive events. The emitPropertyChangedEvent: method then allows us to sent that event to any registered delegate.

There’s also a bit of craziness in the init method. Instead of returning ‘self’ as all other good initializers do, we actually construct the proxy and return it instead! This hides the fact that there’s a proxy object wrapper from the rest of the application entirely.

This proxy object can be used to wrap almost any object, whether your own custom objects or built-in classes. Classes that implement the protocol will need to be careful about the – (id) awakeAfterUsingCoder: method. We’ll cover dealing with that edge case in a future post.

If you’d like to play around with an example, I’ve create a simple XCode iOS project: ProxyObjectTest