ARC Support Without Branching
When Apple announced support for ARC (Automatic Reference Counting), iOS developers jumped for joy at the prospect of no longer having to litter codebases with manual memory management code anymore. Finally, we can concentrate on logic without all the error-prone, time-consuming boilerplate. But, even moreso than most of the new features in iOS5, the transition period for ARC has been a bit painful.
The Problem
The decision to support ARC in your project is clear cut. Yes or no. Most iOS developers use ARC for all new projects that only require a minimum of 4.0 support. (ARC is not supported by iOS 3.1.3.) However, if you are the author of a framework or library, the decision to support ARC isn’t so easy and there are several choices you can make.
The easiest way to go about it is not to convert to ARC at all. Developers can still use your library source code by specifying the -fno-objc-arc option in their project’s Project Sources section.
A big problem with this approach is requiring that option at all. It has to be specified on a per-file basis and, if your library consists of many files such as Cocos2D, the developer would have to set the option for all of them. The XCode interface for this is pretty convoluted and many developers are unaware of the option or where to specify it. Also, if they later updates the library in their project, XCode removes the option and it has to be entered all over again. Pretty obnoxious, and a poor reflection on your code.
Another way to go is to just convert your library to ARC-only. Anyone who isn’t using ARC for their project will have memory leaks and likely a ton of warnings from their static analyzer. This isn’t a realistic option right now. Once a much larger percentage of iOS developers are using ARC it will be. There’s just too many non-ARC projects still out there, especially if iOS 3.1.3 support is required.
So, many developers have decided to add ARC support. A common way is to add a branch to their project that supports ARC. TouchXML, TouchJSON, XMLDocument, and Nimbus are just a small handful of projects that have taken this approach. SVProgressHUD even tried such a branch and abandoned it completely due to the complexity and undesirability of doing such a silly thing!
I highly dissuade you from this approach. Maintaining two branches is rarely a good idea in the real world, let alone for a simple, open-source iOS library. It adds a little complexity to grabbing your source code and will inevitably lead to some commit issues.
There’s a better way.
The Basic Solution
The solution to the problem is conditional compilation. Yes, it’s not only possible, but rather straightforward, to write your code so that it automatically detect the context it’s running in. You won’t have to maintain a second branch and you’ll be able to support ARC and non-ARC code right out of the box.
There’s two methods for doing this and both use the same basic check:
#if __has_feature(objc_arc) ...ARC code here... #else ...non-ARC code here... #endif
The __has_feature(objc_arc) check will not compile the enclosed code for any compiler that doesn’t support ARC, nor for the LLVM 3.0 compiler if ARC isn’t enabled. You can certainly use this code structure and separate your ARC and non-ARC code without reading any further, but if you do you might quickly discover your code will become a mess very quickly. In addition, XCode has historically done a pretty shitty job of automatically indenting code when you use conditional compilation.
How do we keep the code clean?
The Macro Solution
If you want your code to retain (no pun intended) a level of simple readability, macros are definitely the way to go. The idea is that instead of writing completely separate lines of code for ARC and non-ARC, you write macros that adapt to the environment instead.
This is best described by presenting the set of macros which you’re free to drop in to your own project (ARCMacros.h):
// // ARCMacros.h // // Created by John Blanco on 1/28/2011. // Rapture In Venice releases all rights to this code. Feel free use and/or copy it openly and freely! // #if !defined(__clang__) || __clang_major__ < 3 #ifndef __bridge #define __bridge #endif #ifndef __bridge_retain #define __bridge_retain #endif #ifndef __bridge_retained #define __bridge_retained #endif #ifndef __autoreleasing #define __autoreleasing #endif #ifndef __strong #define __strong #endif #ifndef __unsafe_unretained #define __unsafe_unretained #endif #ifndef __weak #define __weak #endif #endif #if __has_feature(objc_arc) #define SAFE_ARC_PROP_RETAIN strong #define SAFE_ARC_RETAIN(x) (x) #define SAFE_ARC_RELEASE(x) #define SAFE_ARC_AUTORELEASE(x) (x) #define SAFE_ARC_BLOCK_COPY(x) (x) #define SAFE_ARC_BLOCK_RELEASE(x) #define SAFE_ARC_SUPER_DEALLOC() #define SAFE_ARC_AUTORELEASE_POOL_START() @autoreleasepool { #define SAFE_ARC_AUTORELEASE_POOL_END() } #else #define SAFE_ARC_PROP_RETAIN retain #define SAFE_ARC_RETAIN(x) ([(x) retain]) #define SAFE_ARC_RELEASE(x) ([(x) release]) #define SAFE_ARC_AUTORELEASE(x) ([(x) autorelease]) #define SAFE_ARC_BLOCK_COPY(x) (Block_copy(x)) #define SAFE_ARC_BLOCK_RELEASE(x) (Block_release(x)) #define SAFE_ARC_SUPER_DEALLOC() ([super dealloc]) #define SAFE_ARC_AUTORELEASE_POOL_START() NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; #define SAFE_ARC_AUTORELEASE_POOL_END() [pool release]; #endif
These macros come packaged with InnerBand. In fact, the InnerBand project supports ARC and non-ARC using these same macros. It serves as an excellent reference of how to use them.
Your mindset should be to use these macros as if you’re programming with old-fashioned manual memory management. When you’re not using ARC, the macros behave as you’d expect with SAFE_ARC_AUTORELEASE calling autorelease and so on. When you’re using ARC, the call is ignored.
The bottom line is you don’t have to worry about it. Just use the macros as if you were coding the old way and everything will be taken care of for you. With just a few caveats, of course.
Notice that __bridge_tranfer isn’t present. It’s not something that can simply be ignored in a non-ARC context. Toll-free bridging is hairy with ARC. If you use it, I recommend sticking with the __has_feature(objc_arc) check and implementing the ARC and non-ARC completely separately.
Also, there may be some edge cases where you need to copy a block in ARC. This is done somewhat differently than using Block_copy. It’s rare, but know that if there is a problem with not calling the copy, you’ll know in the form of crashes.
Demonstration
Now I’ll show you how to use the macros. You can leave your project as non-ARC or convert it to ARC. I prefer leaving it as non-ARC, but that’s just me. You can even create a second target and have both. However you do it, just be sure to test both compiled versions of your code before releasing.
Here’s how you’d perform an autorelease:
- (User *)userWithName:(NSString *)name { return SAFE_ARC_AUTORELEASE([[User alloc] initWithName:name]); }
In non-ARC code, it performs the autorelease. In ARC code, it simply returns the value. Note that with this macro if you call SAFE_ARC_AUTORELEASE on a standalone line, you’ll get a warning that the value is not being used. In almost all cases, an autorelease is coupled with a return or at the end of an allocation, but if you do get the warning you can simply assign the autorelease back itself like this to fix it:
myName = SAFE_ARC_AUTORELEASE(myName);
Retains and releases are similar to autoreleasing:
- (void)setName:(NSString *)name { if (name_ != name) { SAFE_ARC_RELEASE(name_); name_ = SAFE_ARC_RETAIN(name); } ...
If you like to perform your setters with the three-step idiom (retain, release, set), you’ll get the same warning you did with SAFE_ARC_AUTORELEASE. The same fix applies. If you do the two-step idiom (release, retain with if conditional) as above then you won’t need to worry.
Blocks don’t generally need to be copied in ARC. Here’s how you’d handle it in your multi-context code:
- (id)initWithBlock:(void (^)(void))block if ((self = [super init])) { block_ = SAFE_ARC_BLOCK_COPY(block); } return self; } - (void)dealloc { SAFE_ARC_BLOCK_RELEASE(block_); SAFE_ARC_SUPER_DEALLOC(); }
The above also demonstrates how to call a dealloc on the super class, which is expressly forbidden in ARC. The code is removed by the compiler when using ARC, but calls [super dealloc] when compiled as older code.
Autorelease pools have changed, too. Although not strictly necessary, the two different autorelease pool declarations are supported. When you write code to work within an autorelease pool, wrap it like this:
- (id)complexMethodCall { SAFE_ARC_AUTORELEASE_POOL_START(); ...my code here... SAFE_ARC_AUTORELEASE_POOL_END(); }
In ARC, there’s a lot more options for specifying a property. While assign and copy can still be used, there’s a newer specifier called strong. This is essentially retain, so you can write your property like this:
@property(nonatomic, SAFE_ARC_PROP_RETAIN) User *user;
If you want to use any ARC-specific specifiers other than that, you’ll need to use code compilation with __has_feature(objc_arc) since there are no non-ARC equivalents.
And finally, there’s Toll-Free Bridging. This is one area that got more complex in ARC.
I usually resort to code compilation. See the InnerBand code for examples of this surgical procedure. Luckily, you won’t use it much unless you’re using Core Graphics.
Parting Words
These macros are not being offered as an alternative to knowing ARC. On the contrary, you should know ARC before attempting to convert any older code over. The spirit of these macros is to easily, and cleanly, allow library code to run in either context. If you’re not feeling so hot on your ARC knowledge, my favorite resources for ARC are Apple’s ARC Documentation, Mike Ash, and a hidden gem from the maker of Kobold2D.
Getting Started with Mogenerator
NOW UPDATED FOR XCODE 5
If you’re an iOS developer using Core Data in your app, whether a n00b or expert, you should be using Mogenerator. I mean, really, you *should* be using it. If you don’t, well don’t worry, I’m not only going to tell you why you need it, I’m including a tutorial on how to use it!
So let’s get to it!
I know Core Data already, so why do I need Mogen?
Core Data is a huge beast of a thing. There’s so much to know, and you’re not going to get any new functionality from Mogen either. What you *will* get, however, is a Core Data that will be far, far easier to use. This is what Mogen does for you:
- Faster and easier generation of concrete classes for your model.
- A proper two-class treatment in that generation.
- Alleviates the need to wrap numeric attributes in NSNumber objects.
- Handy setter methods for manipulating sets easily.
- Handy wrapper methods for insertion/entity identification.
I can’t wait to get into it all, but first you need to install Mogen and set up your project!
Installation
The first thing you’ll need to do is install Mogen. It’s simple, you install Mogen from a DMG. After this one-time step, we’ll now configure your project to use it:
- In your project, open your project properties and tap the “+” button at the bottom of the Targets list.
- Add an “Aggregate” target (you’ll find it in the iOS/Other grouping). Tap Next.
- Name the target whatever you’d like. I’ll call mine Mogenerator. Hit Done.
- Now select the new target you just created, select the “Build Phases” tab, tap “+” to add a build phase then select “New Run Script Build Phase”.
- Open the Run Script group that just appeared, keep the Shell at /bin/sh, and then enter the following script if you’re using Objective-C:
mogenerator -m MyCoreDataApp/MyModel.xcdatamodeld -O MyCoreDataApp/Model --template-var arc=true
And for Swift:
mogenerator -m MyCoreDataApp/MyModel.xcdatamodeld -O MyCoreDataApp/Model --swift --template-var arc=true
You’re passing in your Core Data model path and directory you want the generated files to live (the directory will be created if it doesn’t exist), so feel free to change the names to match your project. Remove the ARC option if, for some reason, you’re not using ARC. Do note that we take advantage of mogen’s ability to automatically find your current model version. If you don’t have versions, or your project is brand new, this may fail. In that case, you’ll need to be more explicit with the model name. This would work:
mogenerator -m MyCoreDataApp/MyModel.xcdatamodeld/MyModel.xcdatamodel -O MyCoreDataApp/Model --template-var arc=true
And for Swift:
mogenerator -m MyCoreDataApp/MyModel.xcdatamodeld/MyModel.xcdatamodel -O MyCoreDataApp/Model --swift --template-var arc=true
- When you create entities in your data model, be sure to populate the “Class” field with the same name as the entity. (You can name it whatever you want, actually, but that would be mighty stupid to do.)
Now, we’re all ready to go, but what did we win? I’ll outline that next.
Faster, Improved Class Generation
I’ve been programming iPhone apps for almost 3 years now and, I’ll be honest, I still can’t tell you the exact steps to generate Core Data classes. It seems to involve selecting the right entities in the model, adding a new file, and changing some check- — look, I don’t know. I think they made it a little easier recently, but it was crazy and I use Mogen now so I don’t care anymore. ;-) All I know is it’s much easier now.
Change your build target to “Mogenerator” (or whatever you called it) and hit ⌘B to build. And you’re done. At this point, since you generated new files, you’ll need to add them to your project. You won’t have to do this on future regenerations, but for new entities, yes.
You’ll notice that there are two sets of files, _Event.* and Event.*. If you’re not familiar with this pattern, it’s amazing. It’s also been used for years and shame on Apple that they don’t do this out of the box. The _Event.* files are generated and you should never touch them. The Event.* files are generated only if they don’t exist and you can feel free to add any methods and properties you like.
Yes, that’s right, gone are the days where you avoided adding methods to your concrete classes knowing that once you did you wouldn’t be able to generate them anymore. Add all you want, now! The clean coding gods will thank you!
From here on out, whenever you change your model, regenerate the classes, rinse and repeat.
Better Setters
Maybe I’m alone, but early on one of the mistakes I made over and over again was to forget that my numeric entity attributes were wrapped in NSNumber. I’d constantly write code like this:
if (user.isAdmin) { ... }
WRONG! The isAdmin attribute is an NSNumber, so this will evaluate to true for all cases where isAdmin isn’t nil! I ran into this so many times I even contemplated scrapping Core Data to erase the emotional pain.
Not anymore with Mogen. You can now write the code as:
if (user.isAdminValue) { ... }
This simple upgrade is a godsend! Setting attributes is equally easy, and you get to keep the original setters and getters to boot. You can use whatever is useful at the moment. With some attributes, I’ll use both versions:
Thank you, thank you Mogen!
Even More Useful Methods
Aside from the setters and getters, you get some useful methods for relationships, too. Now, I believe Apple has learned their lesson and now provide similar methods like these, but too little, too late. So, let’s say for example you have a entities named User and Role with a to-many relationship on User named roles. You can write code like this to add a role to the user:
User *user = [User insertInManagedObjectContext:moc]; user.name = @"John Blanco"; Role *role = [Role insertInManagedObjectContext:moc]; role.type = @"Administrator"; [user addRolesObject:role];
And you’re done. No need to create a mutable set or anything, it’s all handled for you. There’s a handful of other methods like this, one that lets you remove an object and two more that let you add or remove multiples objects in a set.
Validations, Too!
Mind you, this isn’t a Mogen thing. This is a Core Data thing. Validations let you test your data before saving to your persistant store. But, you might not even have known this existed! This is because you have to specify your validations in the concreate class and, if you’re not using Mogen, you’d have to keep rewriting them every time you regenerated your classes. WHAT?!
Now, you can specify validations like this:
- (BOOL)validateEmail:(id *)value error:(NSError **)error { if (self.email && ![self.email isValidEmailAddress] && error) { *error = [NSError errorWithDomain:@"MyErrorDomain" code:1]; return NO; } return YES; }
This is how you validate individual attributes, but there are other hooks available. Find out more about Core Data Validations to harness even more power.
Conclusion
I hope I’ve made my case for Mogenerator. It’s an invaluable tool! It simplifies anything and since I learned about it I haven’t worked on a project without it. Even better, since it’s a tool and not a library, it interoperates perfectly with other Core Data libraries like InnerBand’s Core Data Store and Magical Record.
Now go forth, young soldier!
That Day Animal Alphabet HD Beat Out Cookie Doodle
Last October, I unofficially partnered up with Fish the Mouse Media and headed up the programming for Animal Alphabet HD, the interactive and kid-friendly alphabet app exclusively for iPad. After nearly 6 months of development (in mostly evening hours) interrupted only by the birth of my daughter in January 2011, the app was released to critical acclaim and glowing reviews.
Unfortunately, as goes the unpredictable world of the App Store, it didn’t equate to sales. It was tough watching it languish while my kids continued to play with it every day as they did while I developed it. When I’d finish an animal screen, I’d hand it off to my sons and say, “Hey guys, want to play with the Kookaburra?” They were the best beta testers and they still love it. Alas, being lost in the monstrous caverns of the App Store meant very few others got to enjoy it as well.
Then — A few weeks ago, while doing some pre-research for my own gaming project, I started tinkering with Animal Alphabet HD to see if I could squeeze it onto an iPhone screen. After a bit of success I got addicted and, in just a few days, an iPhone version was complete! Then, we not only released the update as a Universal app but we lowered the price to $0.99.
And that’s when we beat Cookie Doodle.
Ironically, on my daughter’s 1st birthday, the update arrived on the App Store (9 days ago now) and AAHD has steadily risen up the charts since. Today, it’s the #10 Top Paid iPad app in the Education category and still rising! It’s good to see the recognition for what I feel is an engaging, addictive, and most-of-all educational experience for kids! The Fish the Mouse team did an excellent job coordinating, designing and developing this game. Just the 3 of us.
I’ve written a couple dozen apps for the iOS platform. Many I developed on my own, others with teams. A few have hit high in the App Store, namely the MLS app (as a team via Double Encore) and Fuzz Alert Pro (independently for Fuzz Alert LLC). Animal Alphabet HD, though, is much closer to my heart. For all the work I’ve put in, it’s great to see it rewarded. It shows that despite all of us being underdogs when it comes to competing on the App Store, it makes the reward that much greater.
Let’s all keep pluggin’!
Note: In full disclosure, the Blanco family loves Cookie Doodle. :-)
iBoost is now InnerBand!
Just a quick announcement, to avoid naming conflicts with the mobile provider I’ve renamed iBoost to InnerBand. It’s hosted at its new InnerBand GitHub location.
iOS Brownbag: View vs. Layers (including Clock Demo)
For many iOS developers, layers are a lower-level, complex version of the UIView. In reality, it’s the UIView which is a thin layer on top of CALayer. Unfortuntely, 95% of the iOS books and documentation out there talk almost exclusively about the UIKit and so it’s no surprise we get that impression.
In this blog, I’m going to explain the difference between UIView and CALayer, tell you when you should be using either, and demonstrate the power of layers by creating a working clock.
UIView vs. CALayer
Despite what many developers think, it’s the CALayer that’s the fundamental drawing unit in iOS. The reason why we perceive UIView as such is because it’s a thin layer on top of CALayer and for most UI challenges using some form of UIView works just fine. You can create custom views, draw into them, handle user interactions, and even animate them without ever having to touch CALayer.
Every UIView comes packaged with a CALayer knows as the “backing layer” or “underlying layer.” Many of the methods you call on UIView simply delegate to the layer. When you change a view’s frame, it’s simply changing the layer’s frame. If you change the alpha, it changes the layer’s alpha…and so on with background colors, transformations and more. And while you can maintain a hierarchy of UIViews each representing parents and children of one another, you can do the same with CALayer.
Now, let’s say you wanted to write a Bar Chart component. You’d subclass UIView (or better yet, UIControl) and write the logic for displaying the colored bars you need to represent your data. If you’re comfortable with the UIKit, you might find it an easy choice to use subviews to represent each bar. You can use a plain UIView, slap a background color on it, size it…and repeat a dozen times depending on how much data you’re representing. But, you’d be wrong. You shouldn’t be using subviews, you should be using sublayers.
Should I use subviews or sublayers?
This isn’t a simple question, but there’s one rule of thumb that make deciding a lot easier. The main different between a view and a layer is that views can accept user input while a layer cannot. A layer is simply a graphical representation. Views can handle user taps, drags, pinches, etc. To me, this is all you need to know.
So, when making your bar chart, you should be using sublayers for the bars. Why? Because they don’t need user input and since they’re lighter weight than views, they’re the right choice. So what do you gain by using layers? Well, aside from performance, you also gain implicit animation and better control of the visual representation. You see, every property you change on a layer is automatically animated. You can disable them if you need to, but they come in handy. Also, you can apply shadow effects, corner radiuses, 3D transforms and more on layers. You can apply many of these on views, too, but they’re simply delegating to their “underlying layer” and in many cases stealing event notifications you’d rather they not from your view. :-)
Demo: Let’s build a working clock!
To demonstrate how we use layers, I’m going to build a working clock. The architecture will be as follows:
- ClockView will extend UIControl so that we can use it with Interface Builder and, potentially in the future, handle user events.
- All the parts of the clock will be layers.
- Since all of the parts are layers, we won’t be implementing drawRect.
- A timer, that we can start and stop, will handle updating the clock by adjusting the three hands.
Here’s what our clock looks like:
Every piece of it is rendered in layers: the face, numbers, ticks, all three hands, and the centerpoint. I used a mix of techniques to render it. Shadow effects give the hands depth, rounded line miters give the hands softness, and combining anchoring with transforms gives the hands a more natural clock look by having them rotate around the centerpoint. No PNGs were used and no primitives were drawn.
Here’s the source code. You can take this code and drop it right into your own project. Simply call ClockView#startUpdates to get things going! Also, note that I only implement initWithCoder, so if you want to add it to your UI programmatically, override initWithFrame as well. You’ll also need to link in the QuartzCore framework — anything that uses CA* will need it.
(NOTE: It’s not a memory leak, it’s ARC! Also, I recommend using constants instead of raw time constants. Why not try iBoost?)
On line #41, I use a CAShapeLayer. These things are awesome! By providing a path, you can make a layer of any shape. You can specify stroke and fill colors, change line attributes, and so on. The clock would be way more complex without these bad boys.
On line #45, I use the position property to place the face layer. Layers are positioned differently than views. While you might use frame, bounds, or center to position a view…you use bounds, position, and anchorPoint to position a layer. While bounds works as expected, position and anchorPoint are different. The anchorPoint is a CGPoint where the X and Y normally range between 0 and 1. The 0 represents the top or left of the image, and 1 is the bottom or right of the image. The default is 0.5, 0.5 which is the center of the image. That means that whatever you set the position property to, that’s where the center of the layer will be. You can change the anchorPoint to position things differently. If you set it to 0, 0, position will be where the top left of the image is. Get it? Additionally, you can make an anchor 0.5, 10 which will position the layer 10X the height of the layer above the position. Magic.
On line #59, I use a CATextLayer which lets you specify text easily as a layer.
On line #67, I use 3D transforms to position the numbers. By making the bounds of the number higher than expected, a simple rotational transform positions the numbers where I want. (If you wanted the numbers all “face up”, you’d have to position these using trigonometry instead, but this is a layer demo!) Note that the last 3 params of this method specify which axes to rotate around. I specify the last one, which is the z-axis, which is by far the most common.
Summary
Layers are the powerful core of the Cocoa Touch framework. Even if you’ve never used a layer directly, you’re probably familiar with many concepts because UIViews are simply thin layers on top of them. Want to give your view a rounded rectangle appearance? Simply set myView.layer.cornerRadius to 5.0! Want dynamic drop shadows to make image sizing easier? Set myView.layer.shadowOpacity greater than 0.0. DONE! Remember, UIViews are designed to handle user input, and layers are the graphical workhorse. Use them!