A while ago I blogged about how I’d really like Objective-C to have built in support for lazy properties.
My ideal solution would be something like this:
@property (nonatomic, retain, lazy) NSString* name;
The synthesized getter for this property would automatically call a method
- (NSString*)nameInit
when the property was first accessed, and would use the resultant value to initialise the property.
This has some advantages over any hand-rolled solution:
In the absence of this solution in the language, I offered a rather complicated set of macros to attempt to implement something similar.
Since then I’ve thought about it a bit more, and come up with another couple of ways of tackling the same task… What Do We Want To Do? ———————-
Let’s say we’ve got a class:
@interface MyClass : NSObject
@property (nonatomic, retain) NSString* name;
@end
and we want to make the name property lazy.
What we need to do is to somehow insert some checking code into the -(NSString*)name getter function, that does something like this:
id value = self.name; // <-- this is a call to the ‘original’ getter
if (!value)
{
value = [self nameInit];
self.name = value;
}
return value;
Note that we need to be able to call the original getter here. We could attempt to access the underlying ivar directly, but using the original getter is much better as it preserves the property semantics regarding retain, copy etc.
One clean way to do this would be to insert a class in-front of our class, and implement our modified getter there. That allows us to cleanly call on to the original getter.
So we end up with something like this in our header file:
@interface MyClass : NSObject
@property (nonatomic, retain) NSString* name;
@end
@interface MyClassLazy : MyClass
@end
And this in our implementation file:
@implementation MyClass
@synthesize name;
// normal implementation here
// lazy initialisation function for name property
- (NSString*)nameInit
{
return @"blah";
}
@end
@implementation MyClassLazy
- (NSString*)name
{
id value = [super name];
if (!value)
{
value = [self nameInit];
self.name = value;
}
return value;
}
@end
That’s quite neat, but there’s a problem. Our class is called MyClass, but in order to get the lazy behaviour, we need to use the class called MyClassLazy.
We can fix this with a bit of renaming. The header now looks like
@interface MyClassNonLazy : NSObject
@property (nonatomic, retain) NSString* name;
@end
@interface MyClass : MyClassNonLazy
@end
And the implementation:
@implementation MyClass
@synthesize name;
// normal implementation here
// lazy initialisation function for name property
- (NSString*)nameInit
{
return @"blah";
}
@end
@implementation MyClass
- (NSString*)name
{
id value = [super name];
if (!value)
{
value = [self nameInit];
self.name = value;
}
return value;
}
@end
So that, in a nutshell, is a solution that works. With a bit of judicious macro definition, we can generalise this:
#define lazy_interface(class,parent) interface class##_nonlazy : parent
#define end_lazy_interface(class) end @interface class : class##_nonlazy @end
#define lazy_implementation(class) implementation class##_nonlazy
#define lazy_properties(class) end @implementation class
#define end_lazy_implementation(class) end
#define lazy_synthesize(prop) \
class Dummy__; \
- (NSString*)prop \
{ \
id value = [super prop]; \
if (!value) \
{ \
value = [super prop##Init]; \
self.test = value; \
} \
\
return value; \
}
So now, we can do this in the header:
@lazy_interface(TestClass, NSObject)
@property (nonatomic, retain) NSString* name;
@end_lazy_interface(TestClass)
And this in the implementation:
@lazy_implementation(TestClass)
@synthesize name;
// lazy initialisation function for name property
- (NSString*) nameInit
{
return @"blah";
}
@lazy_properties(TestClass)
@lazy_synthesize(name)
@end_lazy_implementation(TestClass)
Which is kind of nifty, but still, well, ugly. All our nasty macros make it not look like normal Objective-C.
So how about a different approach? Tune in to my next post…
In my previous post I presented a way to implement lazy properties.
It was a bit macro-heavy though, and looked kind of messy. I wondered if there was another way. Objective C is marvellously dynamic and introspective. Shouldn’t we be able to do something clever at runtime to achieve what we want?
In a word, the answer is yes, we can… Let’s say we adopt a standard pattern for the initialisation methods for any lazy properties, like we did in the previous implementation:
<prop>Init.
So for a property called name, the initialisation method would be called
nameInit
At class initialisation time, we can use Objective-C’s introspection routines to run through a list of all our class’s properties, looking for ones that have a lazy initialisation method.
For those that we find, we can swap out the normal implementation of the getter method for one which calls on to the original getter to get the current value, initialises it if the getter returned nil, then returns the value.
That sounds neat, but we will need to define a slightly different getter method for each property - since they all have to call on to a different original getter. Where are we going to put this code?
The answer turns out to be simple - we put it in the lazy initialisation method that we use to indicate that the property is lazy! So not only does the presence of the method tell us that it’s a lazy property, but the body of the method actually performs the lazy get.
Each of these new getter / lazy-initialisation methods is going to look pretty much the same - call the original getter, check the value, initialise if necessary, return the value. Most of the code is boilerplate, but the getter method that we need to call onto changes for each property.
We could probably do something clever here to work out the name of this property at runtime by performing some selector to string conversions, but we’d have to do it every single time the getter was called. As we don’t want the performance to totally suck, it would be good if we could just make a normal call to the original method, check the returned value, and only do potentially slow and clever things on the one occasion when we need to do some initialisation. We can achieve this quite easily with a macro that expands to a few lines of code for every lazy getter.
So what do we end up with?
The interface for our lazy class looks like this:
@interface TestClass : NSObject
@property (nonatomic, retain) NSString* test;
@end
Ok, that’s… erm… pretty normal!
The implementation looks like this:
@implementation TestClass
@synthesize test;
+ (void)initialize
{
if (self == [TestClass class])
{
[self initializeLazyProperties];
}
}
@lazy_synthesize(test, @"test value");
@end
That’s also pretty normal!
We only have two odd things going on here. First, we need to perform a one off initialisation when the class is first loaded, to hook up all the magic.
We can do this in the +initialize method of the class. We could make this step even briefer with a macro, but in this case I figured that it was cleaner to just put the code in.
The second thing we’re doing is “synthesizing” the lazy getter. We could easily just put in the actual boiler plate code each time, but since writing boiler-plate is really what we’re trying to get away from, a macro makes sense.
This solution is much cleaner, and it works. In my next post I’ll show you the implementation.
In my previous post I showed a relatively clean way to implement lazy properties generically using the dynamic runtime.
So how does this dynamic implementation actually work? The interface is pretty small:
@interface NSObject(ECLazyProperties)
+ (void)initializeLazyProperties;
#define lazy_synthesize(name,init) \
class Dummy__; \
- (id)name##Init__ \
{ \
id value = [self name##Init__]; \
if (!value) \
{ \
value = (init); \
[self setValue:value forKey:@#name]; \
} \
return value; \
}
#define lazy_synthesize_method(name,method) lazy_synthesize_value(name,[self method])
@end
Most of the work here is in one macro.
Essentially what this does is define a lazy initialisation method for a property. The method:
We define the name of the method by appending Init__ to the property name. We could have appended just Init, but this method really shouldn’t be called publicly, so I went for a slightly more obscure name.
How it calls the original getter is kind of interesting. If you unpick the macro you’ll see that it appears to be calling itself. Isn’t this going to lead to some hideous recursion?
The answer is no - because the method will have been swizzled. When we’re actually running in the method, it will be as a result of a call to the original getter method. So if we want to call the original getter method, we need to actually call the init method instead!
If we do discover that the value is uninitialised, we then use KVC to call the proper setter with an initial value.
So all of this relies on some swizzling. How do we set that up?
The implementation of initializeLazyProperties looks like this:
+ (void)initializeLazyProperties
{
uint count;
objc_property_t* properties = class_copyPropertyList(self, &count);
for (int i = 0; i < count ; i++)
{
const char* propertyName = property_getName(properties[i]);
SEL init = NSSelectorFromString([NSString stringWithFormat:@"%sInit__", propertyName]);
if ([self instancesRespondToSelector:init])
{
SEL getter = NSSelectorFromString([NSString stringWithFormat:@"%s", propertyName]);
Method initMethod = class_getInstanceMethod(self, init);
Method getterMethod = class_getInstanceMethod(self, getter);
method_exchangeImplementations(initMethod, getterMethod);
}
}
free(properties);
}
We iterate through a list of properties, looking to see if there is a corresponding lazy initialise method for it. If there is, we simply swizzle the original getter method with the init method.
When the user calls the getter, they’ll actually get the init method. This will call on to the getter, check the value, and initialise if necessary.
In the example, we’re just supplying a fixed initial value, but of course the real point of lazy initialisation is for situations where we need to do something time consuming in the initialisation, and we only want to actually do it if we have to.
For this situation you can use the second macro - lazy_synthesize_method. Instead of passing in an initial value, you pass in a method to call to return the value.
This code seems to actually work, but I’ve not tested it intensively to see whether it behaves property in all situations - for example with KVC/KVO.
I think it should do, but right now I view it largely as a thought experiment.
Right back at the beginning I said that the way I really think it should work is
@property (nonatomic, retain, lazy) NSString* name;
I still think that would be ideal. I think that what I’ve done illustrates that it ought to be entirely possible to add a hack to Clang to implement this, but I leave that as an exercise for the reader…
If anyone is interested in the full source code to my implementation, you’ll find it in the ECCore module of my open source ECFoundation library.
[Updated Feb 2012 to fix some broken links]
There comes a time in every programmers life when all the fancy symbolic debuggers let us down, and we have to fall back to that old standby, logging. Or to give it its full name “printf debugging”!
Actually there are lots of reasons why logging can be useful. Sometimes we have what I like to call a “heisenbug” - where the very act of stopping in a debugger to look at the problem causes the problem to disappear. Sometimes we have other timing issues. Sometimes we simply have too much data to analyse in real time, and we need a chance to process it or manually sift through it later.
In these cases the typical solution is to insert print statements into our code which output some text to the console or a file. In C this is typically printf(), or perhaps fprintf(). In Objective-C, we use NSLog instead. Problems ========
There are a few problems with logging code though:
Some of these problems can be solved, but it can get messy.
A typical solution is to define one or more macros which do the logging. By varying the definitions of the macros we can turn the logging on or off. This is a bit clumsy. You have to know that the macros exist, and where they are defined, and you have to recompile the program to change something. In a big program this may not be trivial - you may not even have source code for every framework.
In some solutions the logging macros that are defined include some concept of a level - for instance “warning”, “error”, and so on. This might allow us to vary the logging at runtime by only allowing through the log messages that match (or perhaps fall under) a given level. This can help, but it’s still clumsy. Logging messages don’t necessarily fall neatly into levels. Furthermore, messages from different modules will match the same level, so if you ask for a level you get everything at that level.
The ECLogging module sets out to solve these problems in a different way.
All logging is sent to a named channel, and there can be as many named channels as are needed. Named channels are intended to group logging messages by their purpose or their module, rather that by some concept of “level”.
Logging channels can of course be turned on and off. This can be done at runtime, and the particular configuration of channels that are enabled is saved on each machine, so that a programmer can set things up with only the channels that they want to see enabled. In fact, because of this, all channels default to being disabled, so you don’t get spammed with log output that you didn’t ask for.
Because channels in ECLogging are actual named objects, the logging system can iterate through them and present a user interface for their configuration.
Channels also come in two flavours - log and debug. Log channels exist in all builds. Debug channels only exist in debug builds, and the code associated with them is completely compiled away in release builds.
So log output goes in to the system via channels, but where does it come out?
The answer is handlers.
The logging system contains a number of predefined handlers, which know how to output to the console, the standard output and error streams, and to files on the disc. Custom handlers can be defined and added to do anything conceivable with log output - send it to another process over the network, for example.
By default, all channel output is sent to a global set of handlers. By choosing the handlers in this set you can easily influence where most of the logging output goes.
However, any logging channel can be configured to use it’s own custom set of handlers. In this way you can determine that some channels just go to the console, some just go to disc, and so on.
In use, the system is very similar to NSLog, except that you have to first define a channel, then direct output to it.
ECDefineLogChannel(MyChannel);
@implementation MyClass
- (void)myMethod
{
ECLog(MyChannel, @"some message with params %@ %d", self, 123);
}
@end
Add to this a small amount of code in your application delegate to initialise the system and install the handlers, and you’re good to go.
Drop in some additional iOS or Mac OS X user interface items, and you’ve got a way of configuring channels at runtime. Alternatively, you can just turn channels on and off in code, or by setting NSUserDefaults values.
ECLogging can be found on github, including some decent documentation.
The ECLoggingExamples projects illustrate how to use the ECLogging module on both the Mac and iOS. They should be built from a workspace which also includes the ECLogging project.
Both of these samples are quite basic, and should definitely be regarded as a hint in the right direction, not a definitive illustration of everything that’s possible.
The library design is quite mature - it’s a meme I’ve implemented many times over the last decade or more, in different environments.
The implementation is quite immature, for the simple reason that I’m doing bits when I need them. It does work though, and I use it extensively, both in my own products and others that I contract on.
If anyone shows any interest in it, no doubt I’ll be motivated to get my finger out and improve it further!
[Updated Feb 2012 to fix github links, which have moved]
Ambientweet 1.0.1 is on it’s way, and has been submitted to the Mac App store today for review.
It brings with it a slew of syncing/caching updates which should result in more reliable fetching of tweets (especially after it’s been running for a while), and a faster startup.
The posting interface has also been improved - it looks more like a normal tweet window now, and it correctly deals with long urls, allowing you to post tweets that appear to be longer than 140 character, but which will be under the limit after Twitter has shortened the links.