Saturday, December 7, 2013

A Successful Programmer: Reading

I’ve been thinking a long while about some of the things that have made me a successful programmer. One in particular is reading. I have read and continue to read many books. The books I read vary in topic and not all are technical. I will just to focus on technical books for now.

Even though I work professionally as an iOS developer. I keep my eyes open for useful or emerging technologies. There is something to learn from every field, technology, or language. When I find a useful technique, I adopt it into my current practices. Recently I’ve been incorporating more functional programming techniques. The idea of limiting mutable state greatly simplifies debugging later.

One of my favorite publishers is The Pragmatic Bookshelf. They publish books for programmers authored by programmers. They have books on almost any topic and at varying levels of expertise. Additionally their publications are easily affordable. They offer physical books, ebooks, and screencasts. Updated digital publications can be automatically synced with Dropbox. When I want to pick up a new technology and be assured I’m learning best practice, this is my first source. At the time of this writing, I own 31 of their books.

I also read many older books. There is much to learn from the past. One book I often reference is Design Patterns: Elements of Reusable Object-Oriented Software. Knowing good code design is fundamental to writing maintainable code. I love Don Norman’s Design of Everyday Things to better understand building usable apps. Fred Brook’s The Mythical Man Month is great for avoiding common pitfalls in managing technical projects. There are countless other classics I could mention, but these books are among my favorites.

I’ve often heard as a rule of thumb that every programmer should learn a new language every year. This is certainly not enough time to master the language. It is, however, sufficiently long to learn the unique features of the language. I personally try to read several books per year, both related and unrelated to my current work. Lately I have been studying distributed computing and Erlang/Elixir. I love parallel processing, and big data is one of the next big problems that needs to be solved. Though these studies are not directly related to iOS development, it helps me in building scalable web backends to service iOS apps.

Everyone has different learning patterns. If reading books doesn’t suit you, find other ways to learn new technologies and techniques.

As a disclaimer, I am not receiving any compensation from any publishers or authors. I have found the mentioned books useful and believe that they will benefit others.

Saturday, July 27, 2013

Update

For many months my blog has been left idle. Ever since I started working full-time, I have been unable to blog about many of the projects I work on. When I get off work for the day, I have little desire to work on Apple-related technologies. However, I have been working on other personal projects. These projects don’t fit the mold of what I usually blog about here. Here are a few of those projects.

I have been involved with robotics for years. It’s a field that has always fascinated and is what got me into programming. While attending Brigham Young University, I didn’t have the time nor the financial means to support my hobby in robotics. In the last year I have built a couple robots. The first is a hexapod. For the most part, I used a kit from Trossen Robotics. The default code is open source. I found the inverse kinematics engine most fascinating to study. I reprogrammed the hexapod with simple autonomous navigation using a sonar sensor. I also built a dashboard and control system for running and controlling the hexapod from my laptop.

The second robot I built is a quadcopter which I have named Tetra. I designed the frame using Inventor Fusion and printed each of the pieces using my 3D printer. The electronics are from ArduPilot. After many flights, both successful and unsuccessful, I learned a great deal about multi-copter flight and structural integrity.

I already have a third robot lined up. This one is a hexcopter made of carbon fiber. The main idea behind this one is to have a greater ratio of flight time to repair time.

As I previously mentioned I have been working with 3D printing. Not only have I printed Tetra, but I have also printed many trinkets. 3D printing is a young and exciting field. It’s especially great for robotics since I can quickly and easily make any parts I need. I have a few larger ideas lined up, which I may post later.

Outside robotics, I have been working on other projects. I have been teaching myself Erlang and Elixir. I am fascinated with parallel processing. Quite some time ago, I reached the peak of all I could learn about parallel processing from Grand Central Dispatch. Now I am expanding into more advanced techniques. In order to learn these languages, I started work on a simple wrapper around Forecast.io. I have also been using Elixir to solve problems in Project Euler. Elixir makes many of the problems trivial relative to other languages. It’s great for heavy computation, and makes it easy to take full advantage of all my laptop’s cores. As cloud computing continues to expand, I expect that Erlang, Elixir, and similar languages will play a great role.

Hopefully in the coming months my blog won’t be as silent. Though, the topics may be different from those I have done in the past.

Saturday, November 3, 2012

Clang Language Extensions: __builtin_unreachable()

Sometimes when programming, we encounter impossible situations. Unfortunately, the compiler isn’t as smart as we are. It can’t identify impossible situations like we can. For these situations, we can help the compiler by instructing it that a code path is impossible. For this we use __builtin_unreachable().

Let’s say we have an enum as follows:

typedef NS_ENUM(NSInteger, MyEnum) {
    MyEnumA,
    MyEnumB,
    MyEnumC,
    MyEnumD,
};

Now let’s say we have a switch statement that uses two of the four enum values, but the other two are impossible in this situation. Not including them in the switch will generate a compiler warning. However, including them doesn’t make sense. We can use __builtin_unreachable() to get rid of the warnings.

MyEnum value = // some value.

switch (value) {

    case MyEnumA:
          // Handle case A
        break;

    case MyEnumB:
          // Handle case B
        break;

    default:
        NSLog(@"Cases C and D are impossible");
        __builtin_unreachable();
}

We can also make a macro that we can use to mark a method as not implemented like the following:

- (NSString *)someMethod {
    NOT_IMPLEMENTED;
}

By using __builtin_unreachable(), this macro also makes it so we don’t need to return a bogus value to suppress the no return value warning. The macro looks like this:

#define NOT_IMPLEMENTED \
NSAssert1(NO, @"Method: %@ not implemented.", NSStringFromSelector(_cmd)); \
__builtin_unreachable();

Another perk of this macro is that it prints an error to the console including the name of the method that is not implemented.

Related to __builtin_unreachable() is the ‘noreturn’ attribute. This allows us to mark any function or method that once called, it will never return. This attribute is great for abort methods. We can mark methods like so:

- (void)gracefulAbort __attribute__((noreturn));

Let’s say our app encounters a terminal Core Data error and we need to gracefully terminate the app. We can encapsulate this into a method. This method obviously will never return since it will cause the app to close. By marking it with the noreturn attribute, we will gain the same benefits as if we did the following:

[self gracefulAbort];
__builtin_unreachable();

The above cases I described are few and far between, but when they come up, __builtin_unreachable() is useful. To learn more about this and other Clang language extensions, check out the clang docs.

Saturday, October 13, 2012

Clang Language Extensions: instancetype

Clang added several features to the Objective-C language. One of these features is the ‘instancetype’ keyword. When creating objects, we frequently use methods in the alloc and init families. They have a return type of id, but the compiler knows that they will return an object that matches the class being used. For example, [[NSString alloc] init] returns an NSString and [[NSMutableString alloc] init] returns an NSMutableString.

There are several methods that will automatically infer the return type from the method name. They must follow standard camel-case naming and start with the following words:

For class methods:
        alloc
        new

For instance methods:
        autorelease
        init
        retain
        self

For any methods that do not follow this naming convention, we use the keyword instancetype. Let’s say we have the following objects:

@interface Animal : NSObject

+ (instancetype)createAnimalWithName:(NSString *)name;

@end

@interface SnowLeopard : Animal

- (void)pounce;

@end

@interface MountainLion : Animal

- (void)roar;

@end

Now let’s say we create an object and call a method on it like so:

[[MountainLion createAnimalWithName:@"Maxwell"] roar];

If +createAnimalWithName: returns id or instancetype, then the compiler accepts this just fine. If it returns an Animal object, then the compiler gives the warning: “Animal may not respond to roar.”

So, when does instancetype have an advantage over id? Let’s say we do this instead:

[[MountainLion createAnimalWithName:@"Maxwell"] lastObject];

A MountainLion is clearly not an NSArray; however, the compiler will happily accept this if +createAnimalWithName: returns an id. It’s not until we run the app that the we find the error when our app crashes due to an unrecognized selector method exception.

In summary, the instancetype keyword helps the compiler help you know when something is wrong. If for any reason you need to know if the compiler supports this feature, you can use the macro __has_feature(objc_instancetype).

If you want to learn more about instancetype and other Clang features, check out the Clang docs.

Sunday, June 10, 2012

Linking Storyboards

Summary

Previously I wrote about best practices with UIStoryboards. Since then I have continued to explore the possibilities of storyboards. With today being the eve of WWDC 2012, I wanted to share one of the tricks I have learned.

A key practice of storyboards is to break them down into natural, reusable modules. The downfall to this decomposition is when we need to transition from one storyboard to another. Storyboards were supposed to save us from the tedious transition code, but decomposition brings some of it back. Fortunately, there is a way to remove this pain.

Before I go into any details, I want to start with a disclaimer. I am not going to label this as best practice…at least not yet. All good design patterns need to stand the test of time. I have not used this trick enough to know if it works in all cases. Also, with this week being WWDC, Apple may expand UIStoryboards to include segues between storyboards.

Implementing

You should first download my code from GitHub. Following along will help in understanding how everything works.

The first thing to do is build your storyboards as you normally would. It's best if you break them down into natural modules. The rule of thumb is, if you can give each storyboard a meaningful name, then you have probably decomposed them well.

Now that you have your various storyboards, you can begin connecting them. To do this, you need to identify where you will transition into a different storyboard. At each of these points, create a blank UIViewController. This will represent the view in the other storyboard you will transition to.

Next you need to create a segue to each of these surrogate scenes. You can choose a Push, Modal, or custom segue according to your needs. They should look something like the picture below:



Once you have your surrogate scene in place, we can make the magic happen. We get to use a little-known tool of Interface Builder. It is the User Defined Runtime Attributes tool. This tool is hidden away in the Identity Inspector (3rd tab of the utility view). Up until now, you have probably used this inspector only to set a custom class. It also allows us to set the values of any property of any view we may be using in the storyboard.

First, we need to change the surrogate's class to RBStoryboardLink. Don't forget to include my RBStoryboardLink class in your app. Next, we can add a couple properties instructing the link what to transition to. The first, and required, attribute is "storyboardName" This is the name of the storyboard file you are going to transition to (without the .storyboard extension). The second attribute is optional. It called "sceneIdentifier". This is the UIStoryboard identifier you have given to a scene in the destination storyboard. If you ignore this attribute, then RBStoryboardLink will simply transition to the first scene in the storyboard. This is often what you want. Your Identity Inspector should now look something like the picture below:



Explanation

RBStoryboardLink works much like a symbolic link in your file system. A symbolic link essentially looks and acts like file. Likewise, RBStoryboardLink looks and acts much like a storyboard scene.

The idea behind RBStoryboardLink is simple. At a high level, it does the following:
  1. Creates the destination scene.
  2. Adds the view controller as a child of itself using the iOS 5 container API.
  3. Copies all the destination scene's properties into RBStoryboardLink.
Conclusion

RBStoryboardLink is a clean, easy-to-use technique to link storyboards without leaving Interface Builder. With WWDC this week, Apple may release similar functionality built directly into Interface Builder. If not, expect to use this technique frequently in your projects.

Monday, May 7, 2012

UIStoryboards and UITabBarController

Previously I wrote about decomposing UIStoryboards into modules. One of the most natural modules are the tabs of a tab bar controller. Since segues can't cross storyboards, we can't use a UITabBarController in a storyboard. This means the UITabBarController must be written in code. I have put together an easy pattern for building UITabBarControllers in code.

UIStoryboard Category

The first step is to write a category on UIStoryboard. It will look something like this:

@implementation UIStoryboard (YourExtras)

+ (UIStoryboard *)searchStoryboard {
    return [UIStoryboard storyboardWithName:@"SearchStoryboard" bundle:nil];
}

+ (UIStoryboard *)mapStoryboard {
    return [UIStoryboard storyboardWithName:@"MapStoryboard" bundle:nil];
}

+ (UIStoryboard *)listStoryboard {
    return [UIStoryboard storyboardWithName:@"ListStoryboard" bundle:nil];
}

+ (UIStoryboard *)favoritesStoryboard {
    return [UIStoryboard storyboardWithName:@"FavoritesStoryboard" bundle:nil];
}

+ (UIStoryboard *)contactStoryboard {
    return [UIStoryboard storyboardWithName:@"ContactStoryboard" bundle:nil];
}

+ (UIStoryboard *)homeStoryboard {
    return [UIStoryboard storyboardWithName:@"HomeStoryboard" bundle:nil];
}

@end

The purpose of this category is to abstract away the storyboard file names. Should the storyboard name (or bundle) change, we will only need to change it in one place. Such methods are useful not just tabs but also for any storyboard module. For the purpose of tabs, each storyboard generally should have a UINavigationController as its initial view.

UITabBarController Category

The next step involves a category I wrote. It takes in an array of UIStoryboards, then instantiates each storyboard as a tab. It saves writing a little bit of code between each project.

@implementation UITabBarController (RBExtras)

+ (UITabBarController *)tabBarControllerWithStoryboardTabs:(NSArray *)tabs {

    UITabBarController * tabBarController = [UITabBarController new];
    NSMutableArray * instantiatedTabs = [NSMutableArray arrayWithCapacity:[tabs count]];

    // Instantiates each of the storyboards.
    [tabs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {

        NSAssert([obj isKindOfClass:[UIStoryboard class]],
                          @"Expected UIStoryboard, got %@",
                          NSStringFromClass([obj class]));

        [instantiatedTabs addObject:[obj instantiateInitialViewController]];
    }];

    [tabBarController setViewControllers:instantiatedTabs];

    return tabBarController;
}

@end

This category can be found on my Github.

App Delegate Superclass

Next is an app delegate superclass I wrote. This saves a few more lines of code from each tab-based app.

@implementation RBAppDelegate

@synthesize window = _window;

- (void)setUpTabBasedAppWithTabs:(NSArray *)tabs block:(RBTabBarCustomizationBlock)block {

    NSAssert(tabs, @"No tabs given.");
    NSAssert([tabs count] >= 2, @"Insufficient number of tabs.");

    // Sets up the tab bar controller.
    UITabBarController * tabBarController = [UITabBarController tabBarControllerWithStoryboardTabs:tabs];

    // The block is called to allow customization of the tab bar controller.
    if (block) block(tabBarController);

    // Sets up the window.
    UIWindow * window = [UIWindow new];
    [window setScreen:[UIScreen mainScreen]];
    [window setRootViewController:tabBarController];
    [window makeKeyAndVisible];
    [self setWindow:window];
}

@end

This superclass completes the set up of the tab bar controller. It provides a block for any customizations of the tab bar controller. You can also find this on my Github.

Your App Delegate

The final step is to call the set up method. Don't forget to subclass RBAppDelegate first.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Creates the tabs.
    NSArray * tabs = [NSArray arrayWithObjects:
                                  [UIStoryboard mapStoryboard],
                                  [UIStoryboard listStoryboard],
                                  [UIStoryboard searchStoryboard],
                                  [UIStoryboard favoritesStoryboard],
                                  [UIStoryboard contactStoryboard],
                                  nil];

    [self setUpTabBasedAppWithTabs:tabs
                                                   block:
     ^(UITabBarController * tabBarController) {
         tabBarController.tabBar.selectedImageTintColor = [UIColor greenColor];
     }];

    return YES;
}

The block for customizing the tab bar controller is optional, but I have shown the potential use of such a block. In this case I am setting the color of the selected tab icons.

Conclusion

Within a few lines of code, we can have a tab-based app constructed from several storyboards. Other UIStoryboard patterns can be created using similar techniques.

Sunday, May 6, 2012

Reverse Segues

UIStoryboards make transitioning between views very easy. However, segues work strictly in one direction. I have been asked several times what is the best way to send information back to the previous view controller. Unfortunately, there is no such thing as a reverse segue. In response, I have found four clean, useful patterns to create the needed behavior:
  1. Delegate
  2. Block
  3. Shared memory
  4. NSNotificationCenter
Each one has its advantages and disadvantages. I will discuss each one in turn.

Delegate

Summary

Cocoa uses delegates everywhere, so why not here too?

Code Sample

Let's say view controller X pushes view controller Y via segue. Y specifies a delegate protocol that it will call to pass the needed information. X conforms to that protocol and sets itself as Y's delegate. When Y is dismissed, it calls the delegate method.

// In view controller X
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    [[segue destinationViewController] setDelegate:self];
}

- (void)objectUpdated:(id)object {
    // Do something with the object.
}

// In view controller Y
@protocol MyDelegateProtocol
- (void)objectUpdated:(id object);
@end

- (void)viewWillDisappear:(bool)animated {
    [super viewWillDisappear:animated];

    [[self delegate] objectUpdated:[self object]];
}

Pros/Cons

Delegation is easy enough to implement. However, in this case, the delegate protocol probably has just one method. This hardly seems worth the effort to create the protocol. Because of this, I do not recommend delegates. I instead favor the next option: blocks. If you need more than one callback, a delegate may be more appropriate.

Blocks

Summary

Blocks are great for making callbacks and can easily replace any delegate.

Code Sample

Now when X pushes Y, it also gives Y a block. When Y finishes, it calls the given block and hands it the information to pass on. The block can then do whatever it needs with that information.

// In view controller X
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    [[segue destinationViewController] setBlock:^(id object) {
        // Do something with the object.
    }];
}

// In view controller Y
typedef void(^MyBlock)(id object);

- (void)viewWillDisappear:(bool)animated {
    [super viewWillDisappear:animated];

    if (self.block)
        self.block(self.object);
}

Pros/Cons

Blocks have two great advantages over delegates. First, they don't require a protocol. For convenience, you may write a one-line block typedef, but that is all. Second, blocks keep code where it is relevant, rather in a different method. For most cases, you should favor blocks.

Shared Memory

Summary

Sometimes you may push a new view so it can edit an object. In this case, you can avoid a callback entirely.

Code Sample

When pushing Y, just pass it a pointer to the object of interest. Any changes Y makes to the shared object will directly affect X.

// In view controller X
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    [[segue destinationViewController] setObject:[self object]];
}

Pros/Cons

This solution is the simplest of the four. However, it may not be suitable in some situations. One place this pattern doesn't do well is if you want view controller Y to have a Done and Cancel button. You would need to undo all the changes made to your object if the Cancel button is pressed. This could be made easier by using an NSUndoManager, but that may be overkill for what you want.

There is one particular place that this pattern is especially useful. When using Core Data with iOS 5, you may want view controller Y to have an NSManagedObjectContext that is a child of view controller X's NSManagedObjectContext. All you need to do is create the MOC in X, set the MOC's parent, and pass it on to Y.

NSNotificationCenter

Summary

Using NSNotificationCenter to pass around information is the least used option and the most work, but it can have some nice advantages worth mentioning.

Code Sample

Rather than have X tell Y it is interested in its information, X lets NSNotificationCenter know it is interested in an event.

// In view controller X
- (void)viewDidLoad {
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                                                          selector:@selector(consumeNotifcation:)
                                                                              name:MyNotification
                                                                             object:nil];
}

- (void)viewDidUnload {
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                                                    name:MyNotification
                                                                                   object:nil];
    [super viewDidUnload];
}

- (void)consumeNotification:(NSNotification * notification) {
    // Grab the information from the notification.
}

// In view controller Y
NSString * const MyNotification = @"MyNotification";
NSString * const MyObject = @"MyObject";

- (void)viewWillDisappear:(bool)animated {
    [super viewWillDisappear:animated];

    NSDictionary * userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
                                                [self object], MyObject,
                                                nil];

    [[NSNotificationCenter defaultCenter] postNotificationName:MyNotification
                                                                                           object:self
                                                                                       userInfo:userInfo];
}

Pros/Cons

Obviously this is a lot more code than the other options. It comes with two key advantages. First, this pattern makes multiple, unrelated observers very easy. Second, it allows for looser coupling between views. X and Y (and any other views/non-views) essentially don't know anything about each other. They simply send or receive information through NSNotificationCenter. One place I use this pattern is with an app-wide settings view. When the settings are changed, different parts of the app may need to know immediately when the change is made. For example, I may have a setting that can turn off downloading over the cell network. Both the networking code and the UI will need to know about this change. The notification makes sure that they are informed immediately without needing to hard code the interactions.

Conclusion

When passing information to a previous view controller, favor blocks. However, keep the other options in mind. They have their advantages too.

Other Information

For more information on UIStoryboards, check out my best practices.

Monday, April 23, 2012

Unique Email Channels

If you are anything like me, you probably have more than one email account. One account is only for trusted friends and colleagues. The other is for everyone else. I am always paranoid that I will get spammed from some service, like Facebook. Other times I want to get the newsletters or notifications from some site, but I may lose interest in them over time and want to quickly stop the emails.

The Problem

Every service I give my email address to needs to be handled differently. Gmail is really good about creating rules for handling emails. However, I don't know what email addresses I can possibly receive from. I also cannot feasibly create a rule for every email address a service has. For example, one web service alone may have a customer service email, a bug report email, a no reply email, and many others. This just won't work.

Another option is to create a new email account for every web service I use. I could have one email account each for Twitter, Stack Overflow, GitHub, etc. Creating an entirely separate email account is overkill though.

The Solution

Fortunately, there is a way. Many email providers allow for arbitrary tags to be added to an email address. For example, with Gmail, I can create an email account with the address my.email@gmail.com. Then, I can use my.email+twitter@gmail.com, my.email+stackoverflow@gmail.com, and my.email+github@gmail.com. All these email addresses will go to the same account. Most email providers have similar systems.

How it Works

You can think of the tags on an email address like a subdomain of a URL. The base email guarantees uniqueness and the tag allows for routing. These email addresses are known as disposable email addresses. I like to call them unique email channels. By giving every service a different email address, I can control the communication channel. If that email address is ever compromised by a spammer or I get tired of the emails, I just need to sever the channel.

Since all the unique email channels are delivered to the same email account, they are not immediately useful. We need to bring in the rule system. Gmail allows for rules to be based on the To: field. For example, I can have a rule that says, when I get an email sent to my.email+twitter@gmail.com, mark it as read, label it as Twitter, and archive it. I can have all sorts of complex rules that are specific to my needs for each service. I can even have Gmail forward an email to another email account.

Personally, I have one email account that just handles mail sorting. It takes in email from all my services, marks them as read, labels them appropriately, and archives them. If I get an email from a service I am interested in, I forward it on to my real email account. This allows me to build up an archive of newsletters and notifications, but I never see them if I don't want to. When I get tired of seeing a notification, I don't cancel it. Instead, I just change the rule. The rule system keeps the interface to all my notifications consistent. This way I don't need to dig through some website trying to figure out how to cancel my subscription.

Potential Problems

What if some spammer gets smart and decides to remove the tag? This problem is easy to solve. Just create a rule that deletes all emails sent directly to my.email@gmail.com.

What if some spammer gets smart and tries to guess which tags I use? This is much harder to protect against, especially since +twitter or +github would be easy to guess. Using unique email channels has been around for years and is still not in widespread use. I don't foresee this becoming largely popular to the general user anytime soon. So, there is little chance that someone will attempt this.

If that is not comforting enough, you can use tags that are not easily guessable. For example, you could use +apple20934 or +i.love.steve.jobs for your unique Apple email channel. This is admittedly security through obscurity, but it makes guessing channels even less likely. It's a similar security problem as passwords. Again, it is highly unlikely that spammers will be guessing email channels anytime soon.

If you know what exactly email address(es) you will receive from, you can have rules that only filter if both the To: and From: fields match your expectations. This almost guarantees safety from spammers, but may not be feasible for all situations. This approach could be foiled by worms or email spoofing, but again it would be hard to guess your rules. The key to security is to make spamming you more effort than it's worth. Spammers have plenty of low hanging fruit to spend their time on.

Advantages
  1. Better spam protection than Gmail or any one service alone can provide.
  2. Specific email handling rules for each service.
  3. Don't need to tell your friends that you made a new email address if your email address is compromised by spammers.
  4. Don't need to hunt down the subscription options to cancel email subscriptions.
Disadvantages
  1. If you want to change the types of email notifications you receive from a service, you still need to go to the website.
  2. It takes a little bit of time to set up a rule when creating a channel for a new service.
  3. It takes a lot of time to change all your existing services to use your new, unique email channel.
Conclusion

Though it does take some time up front to set up, unique email channels are worth it for anyone who is paranoid about spammers or wants to automate how their email is handled. I expect to see similar patterns emerge in other communication systems as the event-driven web and personal cloud networks continue to develop.

Wednesday, April 18, 2012

PaintCode App Review

With the new iPad and its Retina Display, iOS apps are getting even larger due to the various sizes of assets. When a user downloads your app from the store, you want them to get it quickly. You especially don't want them to be forced to download from wifi if you can help it. Fortunately, a new app called PaintCode has been released just in time by PixelCut to help remedy this problem.

Summary

PaintCode is a vector image editor. What makes it special is that PaintCode generates Core Graphics code for both Mac OS X and iOS. The idea is that we can draw many of our graphics rather than include a series of rasters in the app's main bundle. PaintCode also serves as a bridge between graphics artists and developers. The graphics artist can generate the assets using PaintCode, then the developer can take the generated code and tweak it as needed.

Test Run

To really see if PaintCode could fill my needs, I stress tested it with a fairly complicated image: the Siri button. The Siri button touches nearly every feature of PaintCode, including arbitrary shapes, linear/radial gradients, and inside/outside shadows.


Within a few hours, I had all the intricate details worked out. I consider myself an amateur graphics artist, but PaintCode made the process very easy. Most of the controls are intuitive and easy to learn. The provided examples and videos also helped.

I then put the code to the test. I simply dropped the code into a custom UIView. To make things more interesting, I applied some affine transformations.


I found that the transformations worked perfectly with everything except, inside shadows. The inside shadows will translate properly, but won't rotate or scale properly. I am not entirely sure why they don't work. I expect this bug will be fixed in a future release.

Pros

Again, PaintCode made generating vector assets very easy. I tried out the trial of a competing app, Opacity, but I found PaintCode to be much more intuitive. I also appreciate the great attention to aesthetic detail, yet minimalistic style.

Everything in PaintCode is drawn using Core Graphics. So, whatever you see on the canvas is exactly what will appear in your own app.

The generated code may not be perfect, but it's pretty good. The advantage of PaintCode is it does the hard, tedious work. Once the image is finished, a developer can easily tweak details as needed to make the drawing more dynamic.

Cons

Though PaintCode generates some good Core Graphics code, it is not truly resolution independent. You will notice this particularly with the radial gradient on the button. I wanted to alternate colors about once every pixel or two. PaintCode only allowed 21 discrete steps for a gradient. Furthermore, since the number of steps is fixed, changing the scale changes the appearance. Fortunately, this can be remedied by tweaking the generated code. A simple for loop can dynamically change the number of steps as the scale changes.

As any graphics artist knows, vector images are not a silver bullet. There are some relationships that are not 1:1 linear transformations. For example, one object may scale twice as fast as another. The scale could even be x2. This scaling problem can be fixed in code though. Also, when the size changes, details often need to be added or removed. The code could be modified to do this automatically as the scale changes, but this is probably outside the scope of PaintCode and may be more trouble than it is worth.

My Wishlist

If there is anything I could have added to this app, it would be import SVG. Every graphics artist has his or her favorite vector editor. It would be amazing if PaintCode could import an SVG file (or AI file) and convert it to Core Graphics code. I have no doubt such a feature would be a large undertaking, but if PaintCode could do this, it would be worth so much more than $80.

Recommendation

If you have an app that is getting large, you should really look into getting PaintCode and converting some of your assets to Core Graphics. Or if you are trying to draw something in Core Graphics and find debugging too hard, PaintCode will make save you many hours.

Code

If you want a copy of my PaintCode file or Xcode project, you can find them on my GitHub account.

Disclaimer

I received a copy of PaintCode free for the purposes of reviewing. However, I do not receive any compensation if you purchase PaintCode.

Tuesday, March 6, 2012

Hidden iOS Simulator Hotkeys

Apple's iOS Simulator app is a helpful tool in building iOS apps. However, there is more than what appears on the surface. Recently a hack has been discovered to allow iPad Retina Display testing. I have also found a couple hidden features. As far as I know, these hidden hotkeys only work on the iOS 5 simulator.

The first, and least interesting, is the "Toggle Slow Animations" feature. This feature slows down animations making it easier to see the fine details. I've found this useful when "debugging" animations. This feature is normally toggled through the drop-down menu: Debug > Toggle Slow Animations. However, it can also be toggled by double tapping Cmd+Shift. If you ever have slow animations mysteriously turn on, then you may have accidentally activated this hotkey.

The second hotkey is more peculiar. I often use the hotkey Cmd+Shift+4+Space to take screenshots of the simulator. I noticed that sometimes a popup would show up that displays the keyboard localization languages I have turned on. It took a while, but I can almost consistently reproduce it. I first disabled the screenshot hotkeys:  (Apple) > System Preferences > Keyboard > Keyboard Shortcuts > Screen Shots > Uncheck all hotkeys. Then I opened the iOS simulator and used the hotkey Cmd+Shift+4+Space. Sometimes it takes a few tries. Other times I need to open/close an app and try again. Again, this hotkey only appears to work on the iOS 5 Simulator. You may also need to have more than one keyboard language activated.


When the keyboard language popup shows up, you can click on of the languages to change your keyboard language. The effect is not immediately apparent unless you have the keyboard visible while changing languages.

I'm not entirely sure why this hidden feature exists in the simulator. If the multiple keyboards are setup, they can be easily changed using the language key on the keyboard. What is more interesting is Apple likely has many other hidden features.