Sometimes Being Lazy is Good

November 4th, 2013

I have seen code like this in some projects:

[myArray removeAllObjects];

for (Thing *thing in anotherArray) {
    [myArray addObject:thing];
}

[self.myTable reloadData];

Now, you may look at this and think it’s is a fine way of coding and you’d be right for the most part. The coder is simply removing all the objects in a mutable array and then looping through another array and adding all of its objects to the first array. After that, a table is told to reload its data which it presumably gets from myArray. The problem with this code is that it (or something like it) is re-written and executed in multiple places in the same file. The user performs some sort of action which the triggers the removing of all the objects in the array, reloading a bunch of new objects and then reloading the data in the table to refresh its view. There is a better way to handle this situation and the better way to handle it is by being lazy.

Lazy Loading

There is a design pattern known as lazy loading that helps immensely in exactly this situation. The idea behind lazy loading is that you have some sort of memory-intensive data structure that you need to access, but you may not need it immediately or you may not need it in memory at all times. Hence, you craft your code so that the information is loaded into memory exactly when it is needed. By implementing lazy loading in your code, you centralize the management of the contents of the data structure making the code more readable and more maintainable since there is only one place in which you need to worry about properly initializing the data. By implementing lazy loading, it also makes it easier for you to free up memory in low memory situations.

How to Implement Lazy Loading

There are three basic steps to implementing lazy loading in your code:

  1. Declare the data structure as a private property.
  2. Implement a custom getter for that property in which you allocate, initialize and return the needed data.
  3. There is no step three, except may to make use of it in code.

Let’s talk about each of these three steps.

Step 1. Declare the data structure as a private property.

“What?” you say, “I thought there was no such thing as private methods in Objective-C.” and you are right. In general in Objective-C, all methods are public and there is no way to make them private. However, in the Objective-C language, you can make use of anonymous class extensions effectively giving you private properties. Let me explain.

If you use Xcode’s menu items for creating a new class file, you will get something like the following.

The header (.h) file looks like this:

@interface MyGreatClass : NSObject

// Your properties get declared here. 

@end

And the implementation file (.m) looks like this:

@interface : MyGreatClass ()

@end

@implementation MyGreatClass

// Implementation of methods

@end

We’ve seen this many times, but the part to focus on is in the first couple of lines in the implementation file:

@interface MyGreatClass ()

@end

You’ve probably seen this in the class files and either ignored it or perhaps put some code in there and things worked anyway so you just left it there. That additional @interface declaration is known as an “anonymous class extension” in Objective-C. In Objective-C, one can add additional methods to an existing class (extend its functionality) by redeclaring the @interface section of the class and adding a new name inside the parentheses. You then effectively have a new class with the additional functionality you define. (A more in-depth discussion of extending classes may be the topic of a different blog post.) For now I’d like to focus on NOT putting a new name inside the parentheses when extending a class. When you do that, you are still extending the class (adding functionality) but are not providing a new identifier. As a result, such classes with this additional functionality cannot be declared and created and hence this additional functionality is anonymous.

We can take advantage of this by declaring a property of the type of object you want to lazily implement. Like such:

@interface MyGreatClass ()

@property (nonatomic, strong) NSArray* myPrivateArray; 

@end

Here I’m declaring a standard Objective-C property for an NSArray called myPrivateArray making it nonatomic because I am not concerned about multi-threaded access and strong because I want the class to retain ownership of that object. Because it is declared in the anonymous class extension rather than in the header file, myPrivateArray is now effectively private, it cannot be accessed from outside the class (or any subclass). With automatic synthesis of properties, you simply use self.myPrivateArray to access the contents of the array anywhere in the class‘s code. This leads us to step 2.

Step 2. Implement at custom getter for that property in which you allocate, initialize and return the needed data.

We all know, or should know, that when you use the @synthesize directive, the compiler will automatically generate appropriate setters and getters for the specified property. If you don‘t need custom behavior in the setter or the getter, you can just leave it alone. With the introduction of LLVM 4.0 the @synthesize directives are automatically included for every property so you no longer need to write that yourself, but you are still getting the default setters and getters implemented for you.

Furthermore, we all know (or should know) that the default setters and getters can be overridden. If you provide an implementation in the class file, the compiler will not overwrite it with the automatically generated methods. We can take advantage of this in our code. Implement a getter for the property you want to lazily load like such:

-(NSArray*)myPrivateArray    // 1
{
    if (!_myPrivateArray) {  // 2
        _myPrivateArray = [[NSArray alloc] init];  // 3
        // Whatever else you need to do to properly initialize the contents. 
    } 

    return _myPrivateArray;  // 4
}

This requires some explanation. At line 1 note the name of the method. In Objective-C, when writing an accessor (getter) you always name the method with the same name as the property whose value you are getting. Naming the method this way is not optional. If you name it anything else accessing self.myPrivateArray will not use your custom getter but will use the automatically generated one.

At line 2 note the use of _myPrivateArray in the conditional. There is a long-standing tradition in Cocoa programming of using a leading underscore when naming instance variables (ivars). This is mostly to help distinguish the ivar from a method with the same name. When using the @property directive, an ivar of the same name, but with a preceding underscore is created for you. So in the above code example, we are checking to see if that ivar (_myPrivateArray) has been initialized. If so, we simply return that ivar. If not, we will then allocate and initialize the contents of the array.

At line 3, _myPrivateAray is being allocated and initialized to whatever is appropriate. Here you may be fetching data from a core data store, iniitalizing the contents of the array with the contents of a file on disk or a plist or querying a web-service to get the needed data. The point is that data is being loaded into the data structure in this one place, at this one time. Centralizing the behavior here helps to make dealing with any problems with loading the data easier because this is likely the only place you‘ll need to look.

Step 3. There is no step 3, except to make use of it in code.

How to make use of this new lazy loading? Just use dot-notation in your code like such: self.myPrivateArray whenever you want to access that private data member.

There remains some controversy among iOS programmers regarding the use of dot-notation in Objective-C. Many are opposed to it for a variety of reasons, many support it. Perhaps in another blog post I‘ll dig into this issue. For now I simply want to point out what is happening when you use dot-notation in your Objective-C code. Dot-notation does not do anything special, it is simply a shorthand notation for calling the method of the exact same name. For example, self.myPrivateArray is equivalent to [self myPrivateArray]. This highlights what many people who are opposed to the use of dot-notation point out. In the second example, it is clear that we are calling the myPrivateArray method (or more correctly, sending self the message myPrivateArray) whereas when using dot-notation it is not as clear. But the effect is the same no matter which method you use. Now, since we wrote our own custom getter method, when you use self.myPrivateArray, you will end up calling your myPrivateArray method you wrote. The first time this method is called anywhere in your code, the ivar _myPrivateArray will not be initialized and hence, the conditional will be executed and _myPrivateArray will be initialzed with whatever data you deemed appropriate. Subsequent calles to self.myPrivateArray will result in that same array of data to be returned, just like you‘d expect. Hence the name “lazy loading”, we are being lazy by not loading the contents of the array until absolutely necessary. Rather than doing this in your viewDidLoad or viewWillAppear methods and taking up precious memory resources that may not be needed, we load it just when needed.

There is another benefit—lazy loading makes it easier to change the contents of the data structure wholesale. Let‘s say that the contents of myPrivateArray are being populated by a core data fetch based on the settings in the user interface, or perhaps the data are coming from a web-service again based up what the user has selected in the app. When you want to refresh the data being stored in that array, just set the array to nil and then refresh the table data, like such:

self.myPrivateArray = nil; 
[self.myTable reloadData];

By setting myPrivateArray to nil, you are deleting the entire contents of the array. In the next line reloading the tableview causes the app to use the custom lazy-loading getter we implemented. In that method since _myPrivateArray is now nil it will automatically re-fetch new data and populate the array. By using this design pattern we shortened the code and centralized the behavior in one place making it easier to maintain.

Wrapping Up

That‘s about all there is to the lazy-loading design pattern. By implementing lazy loading in your apps you can centralize the allocation and initialization of memory intensive data structures making it easier to control when and how they are loaded into memory. When the application is running low on memory, it is easy to release that storage knowing that it will be automatically reloaded correctly the next time it is needed. Every time you can make your code shorter, cleaner and easier to maintain it will improve your productivity and make your apps easier to maintain in the future.

jdabrowski

Prior to joining Accella, Jim spent several years teaching computer science at the college level. He earned his Ph.D. in Computer Science from the University of Wisconsin-Milwaukee, where his studies focused on human-computer interaction. He has taught in many areas of computer science including introductory courses, programming in various languages, and web-design courses.

Leave a Reply

Categories