Eject!

I had the opportunity to watch how a single post can have a pretty big effect on your site. I posted the other day on why I prefer C# over Objective-C and the same day I posted it, I lost 45% of my subscribers. Granted my site doesn't have many to begin with (< 100) it was still interesting to see that many go at once.

It kind of makes me think of our society as a whole. We as a society are less open to the opinions of other people. If someone's opinion doesn't fit in to our comfort zone than we immediately label them as wrong and disconnect ourselves. In a lot of cases, you can't have a decent debate anymore without getting flamed or hated on pretty extremely. That appears to be what has happened here (not the flaming part) - instead of hanging around to see what content I'll continue posting, the Objective-C (presumably) crowd bailed.

It's a free world and all, and I'm not here for subscriber counts anyway so I don't really care. It was just something I found interesting.

Instance run-time defined objects dynamically in Objective-C

In C# I wrote a nice little feature that allowed users to write custom C# script files that the application's runtime would compile, load and instance during the applications life-cycle. The app even supported modifying or creating new scripts and compiling them, loading and instancing without ever re-starting the application. I did most of this with reflection so it wasn't to hard.

I started thinking about it tonight and thought that it would be neat to implement something like that in Objective-C, just for fun. The goal was to accept a user defined class name, check if it exists and instance it. Once it is instanced, allow for invoking the classes methods. All at runtime.

Another nice thing we could do, is check if the object implements a specific protocol. If you are building game development tools, or wanting to provide an abstract way of instancing objects in your app without having to hard-code all of the different types, you could easily do so. You create a new instance based on what object name is provided (such as a object called "Hydrant" and your user selecting a Hydrant in the game, thus requesting an object called Hydrant), then you verify if it implements one or more protocols such as "Interactable" or "destructible" and then invoke the methods or access the properties that are guaranteed to exist.

The Factory

The Factory will be the heart and soul of this example. It's responsibility is to create the object instances, invoke their methods or access their properties for your models and/or view controllers. Assuming you have created a fresh project, we will create new Objective-C class called Factory, which inherits from NSObject. We will provide it with the following public methods in the header.

@interface OFactory : NSObject

- (id)createObject:(NSString *)objectName;
- (void)invokeMethod:(NSString *)methodName onObject:(id)object;

@end

The first method we will implement is the createObject: method. This method will take a NSString object that hopefully has a valid object name. This could be done by creating another method called objectIsValidForCreation:(NSString *)string; that verifies that the object passed as a string has a matching class with the same name. We can look at that in another post. For now, we assume that the user always passes a string with a objectName that matches an existing class. If not, nil will be returned.

Next we have the invokeMethod: onObject: method which will take a string containing a method name and invoke it on the object supplied as an argument.

Let's implement the createObject: method first in our implememtation file.

#import "Factory.h"
@import ObjectiveC.runtime;

@implementation Factory

- (id)createObject:(NSString *)objectName {
    id objectInstance = [[NSClassFromString(objectName) alloc] init];
    return objectInstance;
}

@end

This is a pretty easy method to implement. We just need to make sure that the ObjectiveC.runtime api is imported. Using the Objective-C runtime we can instance a class by providing it with a NSString object containing the name of the class. The NSClassFromString method does just that. It returns a class, which we then alloc and init. You now can invoke this method like such:

Factory *factory = [[Factory alloc] init];
id testObject = [factory createObject:@"NSDate"];

if ([testObject isKindOfClass:[NSDate class]]) {
    NSLog(@"%@", [testObject description]);
}

When you run that code, you should see the current date printed to the debugger. Pretty cool right?

Next, let's build a simple class called "User" that implements two properties and a initializer. The header looks like this.

@interface User : NSObject
@property (strong, nonatomic) NSString *name;
@property (nonatomic) int age;

- (id)initWithName:(NSString *)name andAge:(int)age;
@end

The method we will implement will be done in the .m implementation file. Let's implement the description method, which is a method belonging to the super class NSObject

@implementation OFTestObject

- (id)init {
    self = [super init];
    if (self) {
        self.name = @"Billy";
        self.age = 33;
    }
    return self;
}

- (id)initWithName:(NSString *)name andAge:(int)age {
    self = [super init];
    if (self) {
        self.name = name;
        self.age = age;
    }
    return self;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"The user name is %@ and is %d years old", self.name, self.age];
}
@end

Done. We can use this class to test our next feature, method invoking.

I actually already showed how to do this in my Monitoring Property Changes at Runtime post. There are several changes that I made however to make the implementation more durable in a dynamic environment. This time around it provides support for a unlimited number of arguments that can be passed into the invokeMethod and it returns the same return value that the method you invoked returned.

- (id)invokeMethod:(NSString *)methodName onObject:(id)object withParameter:(id)param, ... {
    if (methodName || object) {
        if ([object respondsToSelector:NSSelectorFromString(methodName)]) {
            // Invoke the getter of the property
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[object class] instanceMethodSignatureForSelector:NSSelectorFromString(methodName)]];
            if (invocation) {
                invocation.target = object;
                invocation.selector = NSSelectorFromString(methodName);

                // Pass the name of the property as the valueForKey: key argument.
                @try {
                    if (param) {
                        // first value is not part of the argument list, so it has to be handled separately.
                        [invocation setArgument:&param atIndex:2];

                        id eachObject;
                        va_list argumentList;

                        va_start(argumentList, param);
                        int index = 3; // Next in the index.
                        while ((eachObject = va_arg(argumentList, id))) {
                            [invocation setArgument:&eachObject atIndex:index];
                            index++;
                        }
                        va_end(argumentList);
                    }

                    id returnValue;
                    [invocation invoke];
                    [invocation getReturnValue:&returnValue];
                    return returnValue;
                }
                @catch (NSException *exception) {
                    NSLog(@"Failed to invoke the method");
                }
            } else {
                NSLog(@"ERROR: Failed to locate the method for @selector:%@", methodName);
            }
        }
    }
    return NULL;
}

Now if you want to test out this code, you can try it with the following code in a view controller some place.

self.factory = [[Factory alloc] init];
id testObject = [self.factory createObject:@"User"];

// user property can be a id, since the class is determined at run time.
self.user = [self.factory invokeMethod:@"description" onObject:testObject withParameter:nil];

The above code will instance a new factory, ask the factory to instance a User class and then invoke that User class method description. If the user class does not exist, nil is returned. In the event that the method does not exist or fails, nil is returned as well. The factory does all of the retrospection required to ensure the app does not crash.

Animate UITableView Data Source changes

Interface Setup

The UITableView has a method called reloadData that essentially removes all of the rows on the UITableView, reconstructs the datasource and then inserts all of the new rows. The issue with releadData is that it happens instantly. If you have an array that your UITableView is using as its datasource, and you remove an object from it, you should really have that object removal be animated. The row should slide out on either the left or right side of the UITableView and everything beneath it slide up.

In this post, I will walk through the steps to achieve that. it's fairly straight forward and will be really easy to reproduce in various different situations that require animating different types of UITableViewCell adjustments.

To start, we need a fresh project. Create a new Single View iOS project called TableView Row Animations and prefix the classes with TRA

This leaves us with a new blank project. Open the story board and add a UITableView to the View, take care that the UITableView does not take up the entire UIView as we need room along the top for another View. The upper portion of the UIView we will add a UISegmentedControl. Give the first index in the UISegmentedControl a title of "Original Data" and give the second index the title "Revised Data". It should look like the following:

Now you need to wire up the UITableView to the TRAViewController. You do that by selecting the UITableView, holding down Control and dragging down to the View Controller icon beneath the View you are editing. Releasing the mouse button will present you with a pop-over box with two options. A delegate and a datasource option; select the datasource and then repeat the process and select the delegate. The following video demonstrates this.

Finally, you need to set up a Action from the UISegmentedControl to your code. Open the assistant editor and control-drag from the UISegmentedControl over to the TRAViewController.m implementation. Create a method called toggleData. Set up a Outlet for your UITableView by control-dragging the UITableView over to your interface, giving it a name of tableView

UITableView Setup

We now have our UI completed, there is nothing left to do here so we can swap over to our TRAViewController.m file and start coding.

The file should be a blank template like the following:

#import "TRAViewController.h"

@interface TRAViewController ()
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end

@implementation TRAViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

@end

We will need to add just one property, a NSMutableArray.

#import "TRAViewController.h"

@interface TRAViewController ()
@property (strong, nonatomic) NSMutableArray *data;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end

@implementation TRAViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

@end

In order for our UITableView to properly work, we also need to tell our View Controller that we are going to conform to two protocols. The UITableViewDataSource and UITableViewDelegate protocols. You can do that by editing the @interface TRAViewController line.

@interface TRAViewController () <UITableViewDataSource, UITableViewDelegate>

As of right now, our app will not run. The UITableView we added will try to invoke two methods that are TRAViewController does not implement yet. We can add them next.

The first method we implement is the numberOfRowsInSection method. The UITableView invokes this method when it's data is loaded/reloaded in order to determine how many rows it needs to provide us with. In order to give it a proper number, we will return the number of items in our data property.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.data count];
}

The next method we invoke is the cellForRowAtIndexPath method. In this method, we will instance a UITableViewCell and assign it a value from our data array based on the current row in the UITableView.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];

    if (!cell) 
        cell = [[UITableViewCell alloc]  initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];

    [cell.textLabel setText:[self.data objectAtIndex:indexPath.row]];

    return cell;
}

Datasource setup

We now have the UITableView all set up and working properly. Since we have done nothing with our data property, the UITableView will not do anything. So let's create our initial data; this will be done in our viewDidLoad method.

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.data = [[NSMutableArray alloc] init];
    [self.data addObject:@"Test Item 1"];
    [self.data addObject:@"Test Item 2"];
    [self.data addObject:@"Test Item 3"];
    [self.data addObject:@"Test Item 4"];
    [self.data addObject:@"Test Item 5"];
}

Animate datasource changes

Now we can work on the meat of the app, animating changes made to our data. We will implement our toggleData method. In this method, we check which segment is selected and we edit our data based on this.

- (IBAction)toggleData:(UISegmentedControl *)sender {
    NSMutableArray *indexPaths = [[NSMutableArray alloc] init];

    // Determine which option is selected.
    // 0 = Original Data; 1 = Revised Data
    if (sender.selectedSegmentIndex == 0) {

        // Tell the table view we are going to update it's data.
        [self.tableView beginUpdates];
        // If original data, we restore our modifed data.
        [self.data insertObject:@"Test Item 1" atIndex:0];
        [self.data insertObject:@"Test Item 3" atIndex:2];
        [self.data insertObject:@"Test Item 5" atIndex:4];

        // Build an array of index's that need to be inserted into the tableview.
        // We match these to the index's we are adding to the data array.
        [indexPaths addObject:[NSIndexPath indexPathForRow:0 inSection:0]];
        [indexPaths addObject:[NSIndexPath indexPathForRow:2 inSection:0]];
        [indexPaths addObject:[NSIndexPath indexPathForRow:4 inSection:0]];

        // Next we insert them into the tableview.
        // We slide these rows in from the left.
        [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];

        // We end our updates.
        [self.tableView endUpdates];
    } else if (sender.selectedSegmentIndex == 1) {
        // Tell the table view we are going to update it's data.
        [self.tableView beginUpdates];

        // If revised data, we delete some items from the datasource.
        // Do this in reverse.
        [self.data removeObjectAtIndex:4];
        [self.data removeObjectAtIndex:2];
        [self.data removeObjectAtIndex:0];

        // Build an array of index's that need to be inserted into the tableview.
        // We match these to the index's we are adding to the data array.
        [indexPaths addObject:[NSIndexPath indexPathForRow:4 inSection:0]];
        [indexPaths addObject:[NSIndexPath indexPathForRow:2 inSection:0]];
        [indexPaths addObject:[NSIndexPath indexPathForRow:0 inSection:0]];


        // Next we delete them into the tableview.
        // We slide these rows in from the right.
        [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationRight];

        // We end our updates.
        [self.tableView endUpdates];
    }
}

You can run this code and watch as the rows are animated in and out of your UITableView very nicely. It should look like the following:

Last notes

You can extend on this by supporting multiple sections in your UITableView if you want. If you have your new data handy, instead of calling reloadData, you can instead perform a beginUpdate, clear your datasource array, invoke the deleteRowsAtIndexPaths: method and then call endUpdates. Once you have done that, you can re-call beginUpdate, add your new data to your datasource array, invoke the insertRowsAtIndexPaths: and then call endUpdates. This will animate the reloading of your data source. This can be used in place of the reloadData method call, which just happens instantly with no animations.

Adjust NSDate by a specified amount

Isn't annoying when you want to adjust a NSDate object by 3 days, or 8 hours, or even by 4 months? You have to instance a NSDateComponents object, edit what you need and then instance a new NSDate object by using a [NSCalendar dateByAddingComponents:toDate:options] method call. In my current app, I have these little adjustments littered all through-out my code. So much so that I decided it was time to make things easier. I just made a simple method that handles this for me:

- (NSDate *)adjustTimeOfDate:(NSDate *)date byAmount:(int)amount  usingPeriod:(AdjustmentPeriod)period;

It allows me to do something like this in my code:

someDateInMyApp = [NSDateCategory adjustTimeOfDate:someDateInMyApp byAmount:2 usingPeriod:AdjustByDay];

I successfully adjusted a NSDate object by two days without having to write 4 lines of code everytime, or without having to figure out how many seconds it takes to increase a NSDate object by for 2 days. I can also go backwards in time:

someDateInMyApp = [NSDateCategory adjustTimeOfDate:someDateInMyApp byAmount:-4 usingPeriod:AdjustByDay];

It makes life so much easier. In order to implement the method, we first need to have a custom enum in place that we can use to select what time frame we want to adjust by. My code was not placed into a NSDate category for my app, but I would recommend that you do that. It seems like the best place for it to go. If you need some help creating a category, check out how I did it in my Understanding Categories post.

My enum goes in my header file like such:

typedef enum adjustmentPeriod {
    AdjustByYear,
    AdjustByMonth,
    AdjustByDay,
    AdjustByHour,
    AdjustByMinute,
    AdjustBySecond
} AdjustmentPeriod;

Next, we define our method in the header file:

- (NSDate *)dateByAdjustingTimeOfDate:(NSDate *)dateToAdjust byAmount:(int)amount usingPeriodOfTime:(AdjustmentPeriod)period;

We are now ready to implement the method. It is really simple, we just instance a blank NSDateComponents and add the amount specified to the correct period of time based on what is provided as an argument. In order to determine it, we will use a switch/case statement.

- (NSDate *)dateByAdjustingTimeOfDate:(NSDate *)dateToAdjust byAmount:(int)amount usingPeriodOfTime:(AdjustmentPeriod)period {
    NSDateComponents *components = [[NSDateComponents alloc] init];

    switch (period) {
        case AdjustByYear:
            components.year = amount;
            break;
        case AdjustByMonth:
            components.month = amount;
            break;
        case AdjustByDay:
            components.day = amount;
            break;
        case AdjustByHour:
            components.hour = amount;
            break;
        case AdjustByMinute:
            components.minute = amount;
            break;
        case AdjustBySecond:
            components.second = amount;
            break;
        default:
            break;
    }

    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    return [calendar dateByAddingComponents:components toDate:dateToAdjust options:0];
}

Now you have a method that can adjust any date. Due to this being a category, you can't add properties (without a bit of grunt work) so I instance the NSCalendar object in the method itself. Due to my app using this method a lot, I chose to put it into a custom class inheriting from NSObject rather than a category so that the NSCalendar object can be a property that is shared by all method calls. Instancing a NSCalendar object is expensive, so if you plan on using this a lot through-out your code, you might want to consider abandoning the category and just sub-class NSObject so you can have a instance variable of NSCalendar to re-use.

If you find that you need to adjust multiple parts of the NSDate, such as the day and hour in one shot, you can modify our method to accept a NSDictionary object. The NSDictionary would have the periods of time you want to edit as the keys and the amount to edit as the value. So you could do something like this:

NSDictionary *adjustmentOptions = @{ @"Year" : @(4), @"Day" : @(12)};

You then loop through your dictionary keys, adjusting each period using a switch/case statement once again. This way, you only create one new NSDate object and not a series of them.

Monitoring Property Changes On Objects

Today we go over the various ways that you can monitor properties in your classes for changes, and act on those changes. There are three ways that I am going to demonstrate.

  • Manually - Notify a specific class of changes to specific properties manually.
  • Monitoring statically via KVO - Notifies specific classes of changes made to specific properties automatically.
  • Monitoring dynamically via KVO - Notifies any class of changes made to any property, without having to specify which properties by using the Objective-C runtime library. Yay C functions!

Object monitoring

There are instancs were monitoring property changes to an object can be very useful. You might want to monitor changes to various object properties that might need to get wrote to a local database, propogate back to a server, or perhaps you want to immediately write out property changes to file. Monitoring an object for changes allows you to save the changes as they happen, and prevent invoking any save methods or update methods when nothing has changed.

In order to monitor the properties of an object, you need to determine what the extent of the monitoring needs to be. Are you only going to monitor a handful of properties in a single object? Perhaps you have several dozen properties spread out over multiple objects, or you might want to make something flexible so you can re-use it on other projects if needed.

I should note that two of the three approachs I'm going to discuss use KVO. If you have a lot of objects and need your app to be fairly performant, this might not be the best solution for you. While KVO is very quick, it does come with some additional overhead. The performance hit is negligible on standard apps, or even hard-core apps with very few KVO's; a large quantity (we're talking hundreds) of KVO setups can significantly affect your performance though. A general rule of thumb is not to use these in any kind of app/game loop and keep the code that they perform fairly short. It should be used primarily as a callback, letting something know that things have changed.

Manually

Manually is the most straight forward approach. You create a property, preferably a BOOL, and set it to YES when a property is changed. In the BOOL properties setter, you would invoke what ever method that is neccessary to commit or process those changes.

It's best to demonstrate with an exampe, so let's say we have a class we are building called PlayerSettings and this class is responsible for saving the players settings in a game. When a setting is changed, we want to automatically save the settings to what ever format you happen to choose. The format isn't important, getting to the save code automatically without manually invoking a [player saveSettings]; method all the time is.

Lets start with the header API, which just exposes the public properties for the player settings class.

#import <Foundation/Foundation.h>

@interface MYPlayerSettings : NSObject

@property (strong, nonatomic) NSString *name;
@property (nonatomic) int age;
@property (nonatomic) double mouseSensitivity;
@property (strong, nonatomic) NSString *currentLevel;

@end

What we did was create four properties that pertain to the player settings. If any of these four properties are changed, we want to instantly save the player settings. Notice that there is no - (void)saveSettings; method? That's because there will be no need to manually save the settings; we'll do it all automatically. In order to do that though, we need to implement the player settings, so lets get to that.

#import "MYPlayerSettings.h"

@interface MYPlayerSettings ()
@property (nonatomic) BOOL settingsChanged;
@end

@implementation MYPlayerSettings
@end

In order to make things simple, we are going to use a BOOL property called settingsChanged. This property will be the only thing responsible for saving the player settings. I'll show you how by implementing the properties setter method next.

#import "MYPlayerSettings.h"

@interface MYPlayerSettings ()
@property (nonatomic) BOOL settingsChanged;
@end

@implementation MYPlayerSettings

// Setter method
- (void)setSettingsChanged:(BOOL)settingsChanged {
    _settingsChanged = settingsChanged;
    if (settingsChanged) [self savePlayerSettings];
    _settingsChanged = NO; // We are saved; no longer changed.
}

- (void)savePlayerSettings {
    // Do stuff.
}
@end

In our settingsChanged setter method, we check if the settingsChanged property is being set to YES. If it is, then we need to save the player settings, so we invoke the [self savePlayerSettings]; method. Note that the savePlayerSettings method is private; just like I said above, the player settings class will handle saving itself, there is no need to expose the method via the public API.

Next, we need to actually provide a way to set the settingsChanged property right? We do that by implementing the setter methods for our four properties like so:

- (void)setName:(NSString *)name {
    _name = name;
    self.settingsChanged = YES;
}

- (void)setAge:(int)age {
    _age = age;
    self.settingsChanged = YES;
}

- (void)setCurrentLevel:(NSString *)currentLevel {
    _currentLevel = currentLevel;
    self.settingsChanged = YES;
}

- (void)setMouseSensitivity:(double)mouseSensitivity {
    _mouseSensitivity = mouseSensitivity;
    self.settingsChanged = YES;
}

Not to bad right? Anytime that your game needs to adjust a setting, the player settings will automatically get saved. Now this does have some drawbacks, such as what happens if you change the player's settings from two different threads or what if you save method is asynchronous? There are some edge cases to consider with this approach, so keep that in mind. For small objects such as this, with quick file I/O operations, this would work just fine.

What if I have a handful of classes, each with a dozen properties that I want to implement this with? Isn't there an easier way? Why yes there is. You can either statically monitor or dynamically monitor an object via KVO, both of which I'll show you next.

Monitoring statically via KVO Part 1:

We will continue to use the PlayerSettings class for this example, but we will build on it because (hypothetically) you have added additional settings to the player that need to be saved. As mentioned above, it's a royal pain to write out a setter method for every single property, just for the sake of setting settingsChanged to YES. Let's do this a bit differently. We will use KVO.

KVO stands for Key-value observing and it provides a mechanism for objects to be notified when changes are made to a object's properties. There are a couple of ways we could do this, one of which modifies the above setter methods to look like such:

#import "MYPlayerSettings.h"

@implementation MYPlayerSettings

- (void)setName:(NSString *)name {
    _name = name;
    [[NSNotificationCenter defaultCenter] postNotificationName:@"settingChanged" object:self];
}

- (void)setAge:(int)age {
    _age = age;
    [[NSNotificationCenter defaultCenter] postNotificationName:@"settingChanged" object:self];
}

- (void)setCurrentLevel:(NSString *)currentLevel {
    _currentLevel = currentLevel;
    [[NSNotificationCenter defaultCenter] postNotificationName:@"settingChanged" object:self];
}

- (void)setMouseSensitivity:(double)mouseSensitivity {
    _mouseSensitivity = mouseSensitivity;
    [[NSNotificationCenter defaultCenter] postNotificationName:@"settingChanged" object:self];
}

- (void)savePlayerSettings {
    // Do stuff.
}
@end

As you can see, we no longer have the @property (nonatomic) BOOL settingsChanged; property, nor the setter method were we invoke the [self savePlayerSettings]; method. Instead, we have this nifty [[NSNotificationCenter defaultCenter] postNotificationName:object:]; call. What this does is send a message to the specified object (in this case self) with a notification called settingChanged. The notification name can be anything, I just happened to use settingChanged because it seems appropriately titled.

Once this happens, NSNotificationCenter will look for any object that is registered to receive the settingChanged message. This is called observing an object and in this case, the above code will do nothing because we have not added any observers. We will do that by implementing the PlayerSettings initializer method.

- (id)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(savePlayerSettings)
         name:@"settingChanged"
         object:self];
    }
    return self;
}

In the initializer we are adding ourself as on observe to any property within ourself that sends the settingChanged notification. It's important that the object argument has self as the parameter, otherwise our PlayerSettings class will be registering to receive settingChanged notifications from any object, which could be bad. For this example, we only want to receive messages from changes made to ourself. Also note that the parameter selector:@selector(savePlayerSettings) is telling NSNotificationCenter to invoke our [self savePlayerSettings] method when it receives the settingChanged notification. Now, unlike our manual approach, we are no longer manually invoking the save method in our private code either!

Now, let's assume someplace in your game you need to instance some player settings and assign some values. You would do so like this:

MYPlayerSettings *settings = [[MYPlayerSettings alloc] init];
settings.name = @"Bob";
settings.age = 22;
settings.currentLevel = @"Last level";

Each time you assign a property a value, the settings object will be saved automatically. As mentioned before, it works just fine for something small like this, or if you are only saving the changes. In the event that you have a massive amount of properties, or a lot of objects that will have it's entire object saved or transferred, you don't want to have your save code being called after each assignment. What if your save code is sending the data across the network to a server someplace? You are wasting data by just sending the save data across the network multiple times. This needs to be fixed! On top of that, wasn't the point of using KVO to elemenate the need for implementing the setter method on our properties? We're still doing that! Let's take care of that.

Monitoring statically via KVO Part 2:

We will continue to use our previous PlayerSettings.h file, but we are going to start fresh on our PlayerSettings.m file. It should look like this:

#import "MYPlayerSettings.h"

@implementation MYPlayerSettings
@end

Nice and empty! Now, as your class grows, it can be a pain in the behind to continously add new setter method for our properties, so that's going to stop. Instead, we will rely on KVO a bit differently by observing actual properties themselves rather than observing a object for a broadcasted message. Our PlayerSettings will no longer broadcast a settingChanged message when properties are changed, instead the PlayerSettings class will be self-aware and know when it has had it's own properties changed. In order to do this, we need to do a couple of things first. We need to implement a init method, a observeValueForKeyPath:ofObject:change:context: method and finally our savePlayerSettings method.

To get started, the PlayerSettings object needs to know what properties to monitor for changes, so we implement our initializer method and add ourself as an observer to those properties.

- (id)init {
    self = [super init];
    if (self) {
        [self addObserver:self forKeyPath:@"name" options:0 context:NULL];
        [self addObserver:self forKeyPath:@"age" options:0 context:NULL];
        [self addObserver:self forKeyPath:@"currentLevel" options:0 context:NULL];
        [self addObserver:self forKeyPath:@"mouseSensitivity" options:0 context:NULL];
    }
    return self;
}

That's a pretty easy initializer to implement, we just tell ourself that we want to observe ourself, monitoring each property that we specify. Now, when a property is changed, our PlayerSettings object will be made aware of it! How does this happen though? If you remember earlier, we specified that we wanted our savePlayerSettings method to be used right? In the above code, we aren't specifying any method, so what gets invoked? The answer to that lays in the Apple Documentation:

The observer must implement the key-value observing method observeValueForKeyPath:ofObject:change:context:.

Since we are observing ourself, we have to implement the observeValueForKeyPath:ofobject:change:context: method ourself. When a property is changed, this method will automatically be invoked for us. So that means, within that method, we can invoke our savePlayerSettings method.

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    [self savePlayerSettings];
}

- (void)savePlayerSettings {
    NSLog(@"%@ saved", self.name);
}

Now we have a fully automated save system and it's actually fewer lines of code than before. As you add new properties to the PlayerSettings class, you just need to go and observe them in the initializer.

We still have the same problem however of saving multiple times when we don't really need to. Take the following code, re-used from above:

MYPlayerSettings *settings = [[MYPlayerSettings alloc] init];
settings.name = @"Bob";
settings.age = 22;
settings.currentLevel = @"Last level";
settings.mouseSensitivity = 5.0;

Due to all four properties being changed, the save code will be called four different times. Is that efficient? Not really, so we need to fix that. I chose to take a similar approach as to what Apple did with their UI animations. We will add two new methods and two different properties. The methods will be called beginUpdates and endUpdates and our properties will be two BOOL values called settingsChanged and performingBatchChanges.

First let's create the two properties in our .m file like such:

@interface MYPlayerSettings ()
@property (nonatomic) BOOL settingChanged;
@property (nonatomic) BOOL performingBatchChanges;
@end

When we invoke our observeValueForKeyPath: method, we will need to perform a check. First, check if we are performingBatchChanges and if so, do not save the player settings. Since we are doing batch changes, we will save the player setting once we are completed with all of the changes. Since we know that settings have changed though, we need to set settingChanged to YES.

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if (self.performingBatchChanges) {
        self.settingChanged = YES;
    } else {
        [self savePlayerSettings];
    }
}

In order to perform the batch changes, we need to implement our two new methods, beginUpdates and endUpdates. These two methods are really simple and need to be added to your .h file like this:

#import <Foundation/Foundation.h>

@interface MYPlayerSettings : NSObject

@property (strong, nonatomic) NSString *name;
@property (nonatomic) int age;
@property (nonatomic) double mouseSensitivity;
@property (strong, nonatomic) NSString *currentLevel;

- (void)beginUpdates;
- (void)endUpdates;
@end

Next we will add the implementation of these two new methods into our .m file like this:

- (void)beginUpdates {
    self.performingBatchChanges = YES;
}

- (void)endUpdates {
    self.performingBatchChanges = NO;

    if (self.settingChanged) {
        [self savePlayerSettings];
    }
}

This is pretty straight forward. When a property is changed, our observeValueForKeyPath: method is invoked. We check if we are performing batch changes (due to the user invoking beginUpdates prior to changing the property) and we set the settingChanged property to YES to indicate that we have changed settings but not saved them. If this is not a batch change, then we just save the settings. Once the user invokes the endUpdates method, we set our performingBatchChanges to NO because we are no longer making batch changes. Lastly, we have to check if the settings were changed and if they were, save them. Why perform this check? It's possible for the user to do the following:

[self.playerSettings beginUpdates];
[self.playerSettings endUpdates];

If they invoked the beginUpdates and endUpdates methods without ever making any changes, then we would be needlessly saving the player settings.

So, how do we use this? Pretty simply, if you are changing one or two properties, just use the settings file like normal.

self.playerSettings = [[MYPlayerSettings alloc] init];
self.playerSettings.mouseSensitivity = 5.0;

There's no harm in changing one or two settings, but if you are wanting to change several, then you use your new beginUpdates and endUpdates methods.

self.playerSettings = [[MYPlayerSettings alloc] init];
[self.playerSettings beginUpdates];
self.playerSettings.name = @"Bob";
self.playerSettings.age = 22;
self.playerSettings.currentLevel = @"Last level";
self.playerSettings.mouseSensitivity = 5.0;
[self.playerSettings endUpdates];

The player settings will only be saved once now, at the end when endUpdates is invoked. Saves on I/O or data usage if the content is sent over the network.

Alright, we are now monitoring our object's properties and automatically invoking our save method. What if we want to add another object, like a GameSettings to our project? It's simple enough that we can re-use the above code and get it up and running, but what if we could just write the code once and never re-write it again; while using across dozens of classes? Monitoring property changes dynamically via KVO can get the job done.

Monitoring dynamically via KVO

This approach digs into the Objective-C runtime and requires use of it's C runtime functions. I assume the reader has some understanding of what ARC does and is famiiar with introspection. As with most dynamic approaches, this one comes with the largest performance hit. You will not see the hit unless you are using this on hundreds of objects (like in a game).

Let's start off by creating a new class called MYGameSettings and providing it with some properties in the header.

#import <Foundation/Foundation.h>

@interface MYGameSettings : NSObject

@property (strong, nonatomic) NSString *version;
@property (nonatomic) int brightness;
@property (nonatomic) BOOL hardMode;

@end

We will save the implementation for last, as we need to build our dynamic object monitoring class first.

We are going to create a new class called ObjectMonitor. This object will be used to observe our classes from now on, monitoring what happens to the classes and then acting on the changes that take place. Let's set up our ObjectMonitor.h header first.

#import <Foundation/Foundation.h>

@interface ObjectMonitor : NSObject

- (id)initWithMonitoringObject:(NSObject *)objectToMonitor respondingWithSelector:(SEL)selector;

@end

We will implement a new initializer that accepts the object we want to monitor, and a selector which identifies a method that we will invoke on the objectToMonitor. What this will do, is allow ObjectMonitor to monitor our GameSettings and PlayerSettings objects (or any other object you provide it) and each object will tell ObjectMonitor what method to invoke. When a property on the observed class changes, the ObjectMonitor will invoke the requested method, within the provided object, in this case our settings classes. You'll see how it all comes together in the end. For now, we need to implement our ObjectMonitor.m implementation, so let's do that. First, the initializer and our selector property:

#import "ObjectMonitor.h"
#import <objc/objc-runtime.h>

@interface ObjectMonitor ()
@property (nonatomic) SEL selector;
@end

@implementation ObjectMonitor

- (id)initWithMonitoringObject:(NSObject *)objectToMonitor respondingWithSelector:(SEL)selector {
    self = [super init];

    if (self) {
        self.selector = selector;

        unsigned int count;
        objc_property_t *properties = class_copyPropertyList([objectToMonitor class], &count);

        for (size_t i = 0; i < count; ++i) {
            NSString *key = [NSString stringWithUTF8String:property_getName(properties[i])];
            [objectToMonitor addObserver:self forKeyPath:key
                  options:0 context:NULL];
        }

        free(properties);
    }
    return self;
}
@end

The first thing we do in our initializer is store a reference to the selector provided to us for future use. A selector is nothing more than a pointer to a method stored in a variable for us to use at a later date. This can cause some issues, which we will discuss and handle in just a bit.

Next, we have this interesting Objective-C Runtime function: class_copyPropertyList([objectToMonitor class], &count); Here we are calling the C runtime function class_copyPropertyList which takes a class as an argument and outputs the number of properties contained within that class. It also returns an array of every property that the class has. So we have the number of properties that the object has stored in the count variable and an array of every property the object has stored in the properties variable. What next you ask? We itterate through each property and observe them!

In our for-loop we use another C runtime function called property_getName which takes a property from our array and determines it's name and returns it for us. That provides us with a fully qualified property name that belongs to objectToMonitor. We then tell objectToMonitor that we are going to observe it for any changes made to that property. We then loop through the rest of the array, adding ourself as an observer to each property found in the object.

Finally we invoke the C runtime function free which releases the properties array from memory. Since C functions are not managed by ARC, we have to manage the memory ourselves.

A side note on observing the objectToMonitor for property changes. If you wanted, you could expand on this by adding a NSArray argument to this initializer with properties that you want exempt from observation. Then you could adjust your for-loop to be like this:

    for (size_t i = 0; i < count; ++i) {
        NSString *key = [NSString stringWithUTF8String:property_getName(properties[i])];

        // If this property is in our exempt array, we skip it and move on to the next.
        if ([exemptProperties containsObject:key]) {
            continue;
        }
        [objectToMonitor addObserver:self forKeyPath:key
                  options:0 context:NULL];
    }

Instead of providing a list of exemptions, you could just provide a list of properties to observe as well. This could be useful if you have several dozen properties but only want to monitor a handful. In most cases though, manually observing those using static KVO or the manual approach above is probably a better idea.

Alright, we have our initializer wrote and we are now observing any object that instances our ObjectMonitor! The next thing to do would be to do something when the properties are actually changed. Remember the observeValueForKeyPath method we implemented in our PlayerSettings class? Well, our ObjectMonitor class will implement that now, and our PlayerSettings and GameSettings classes won't have to implement this at all.

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    NSLog(@"%@ had %@ changed!", NSStringFromClass([object class]), keyPath);

    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[object class] instanceMethodSignatureForSelector:self.selector]];
    if (invocation) {
        invocation.target = object;
        invocation.selector = self.selector;
        @try {
            [invocation invoke];
        }
        @catch (NSException *exception) {
            NSLog(@"Failed to invoke the method");
        }
        @finally {

        }
    } else {
        NSLog(@"ERROR: Failed to locate the method for @selector:%@", NSStringFromSelector(self.selector));
    }
}

The first thing we do is print to the debugger that we have entered the method due to an object's properties changing. The method arguments provides us with the property name and the object that the property belongs to. The property name is stored in keyPath and the object that owns the property is object. Since the method provides us with this information, we can print the name of the property using NSLog and include the class name. Since the object is not a string, we get the name of the class by using NSStringFromClass.

The next part can make or break your app, so you really want to make sure and set it up properly. We instance a NSInvocation object, which will be used to actually invoke the method provided to us and stored under self.selector. It's really important that you don't use [object performSelector:self.selector]; because this will not be memory safe and can leak. The runtime needs to know what to do with the result of your method invocation, which could be anything (void,BOOL, MYPlayerSettings). ARC would normally acquire this information from your objects header. With this approach, the ObjectMonitor class has no idea what method is stored in the selector, preventing the runtime from determining what the result is. This causes a compiler warning to be generated stating that a leak could occure. You could potentially acquire the actual method pointer itself by using IMP imp = [methodForSelector:self.selector]; but there is no guarantee that the correct method signature will be returned. So invoking imp could crash your app.

So, how do we get around this safely, keeping the runtime happy? We use NSInvocation. This is not a crash free solution but if you code it right and provide proper documentation on how to use the ObjectMonitor then you can have it work without a hitch.

The [NSInvocation invocationWithMethodSignature: instanceMethodSignatureForSelector:] checks the properties owner (object argument) to see if it has the selector we have a reference stored to. If it does, then a valid NSInvocation object is returned. If no method exists, then nil is returned. We check against nil on the very next line, so if no method is returned, we don't try to invoke it and crash out app.

We tell the invocation which object we want to invoke the method on ( invocation.target = object;) and then we tell it which method to invoke (invocation.selector = self.selector;). Lastly, we invoke the method using [invocation invoke]; and we wrap this invocation in a @try/@catch in the event that the invocation fails.

Using this approach, our ObjectMonitor is fairly safe to use. In the event an invalid method is provided we are protected from crashes. One last item to mention before we move on from our ObjectMonitor class. The [invocation invoke]; call invokes the method specified with zero arguments. What if you would like to know what property changed? You can do that by adjusting the if statement to look like this:

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[object class] instanceMethodSignatureForSelector:self.selector]];
if (invocation) {
    invocation.target = object;
    invocation.selector = self.selector;
    [invocation setArgument:&keyPath atIndex:2]; // index 0 = self and index 1 = _cmd
    @try {
        [invocation invoke];
    }
    @catch (NSException *exception) {
        NSLog(@"Failed to invoke the method");
    }
    @finally {

    }
} else {
    NSLog(@"ERROR: Failed to locate the method for @selector:%@", NSStringFromSelector(self.selector));
}

It is critical that the atIndex argument in the setArgument call is 2 or greater. The Objective-C runtime invokes all methods by send a message to the object. The message is objc_msgSend() and it requires at least two arguments. The receiver (in this case our object we are monitoring) and a selector. All Objective-C messages have two arguments that are always included. The first argument is passed as the receiver of the second agument (our method selector) and is most often passed as self. The second argument (selector) is passed as \_cmd and contains a pointer to our actual object method. So we can start adding arguments at index 2. If you would like to invoke the method we specify and provide the property name that was changed, you can do so. Your object that actually implements the method being invoked must have an argument that accepts what you add to the NSInvocation, otherwise it will fail to invoke. Luckily, since we wrapped it in a @try/@catch it won't crash your app. It can be annoying to debug though.

So, that's it, we have built our ObjectMonitor class. Now let's use it. We will return to our PlayerSettings class and re-write it to make use of this. We add our ObjectMonitor as a property and then in our PlayerSettings initializer, we instance it, tell it to observe us and we provide it our savePlayerSettings method for invocation.

#import "MYPlayerSettings.h"
#import "ObjectMonitor.h"

@interface MYPlayerSettings ()
@property (strong, nonatomic) ObjectMonitor *objectMonitor;
@end

@implementation MYPlayerSettings

-(id)init {
    self = [super init];
    if (self) {
        self.objectMonitor = [[ObjectMonitor alloc]
                              initWithMonitoringObject:self
                              respondingWithSelector:@selector(savePlayerSettings)];
    }
    return self;
}

- (void)savePlayerSettings {
    NSLog(@"%@ saved", self.name);
}

@end

And we do the same thing with our GameSettings class.

#import "MYGameSettings.h"
#import "ObjectMonitor.h"

@interface MYGameSettings ()
@property (strong, nonatomic) ObjectMonitor *monitor;
@end

@implementation MYGameSettings

- (id)init {
    self = [super init];
    if (self) {
        self.monitor = [[ObjectMonitor alloc]
                        initWithMonitoringObject:self
                        respondingWithSelector:@selector(saveGameSettings)];
    }
    return self;
}

- (void)saveGameSettings {
    NSLog(@"Game settings saved!");
}
@end

Isn't it nice that we can now add object property monitoring to any class we want with just 2 lines of code? A property declaration and instancing. Now we can use the following code, anywhere in our app:

self.playerSettings = [[MYPlayerSettings alloc] init];
self.playerSettings.name = @"Bob";
self.playerSettings.age = 22;
self.playerSettings.currentLevel = @"Last level";
self.playerSettings.mouseSensitivity = 5.0;

self.gameSettings = [[MYGameSettings alloc] init];
self.gameSettings.brightness = 73;
self.gameSettings.hardMode = NO;
self.gameSettings.version = @"1.0";

Our game settings and player settings will always be saved.

Of course we lost the ability to use our cool beginUpdates and endUpdates, but that can easily be reimplemented. You just re-set it back up and in your savem methods, don't actually save if performingBatchUpdates is YES.

I hope this document on implementing the ability to dynamically monitor any property on any object proves to be useful to you guys. It only took me about 5 hours to write!

Until next post.