INTRODUCING FEEDBINKIT

Comment

INTRODUCING FEEDBINKIT

RSS isn’t dead! In fact, it’s alive and well, with many new services filling the now-defunct Google Reader’s niche of syncing subscriptions, entries, and read/unread status. My personal preference among the crowd of newcomers is Feedbin. It has a simple revenue model ($3/month or $30/year), an open-source core, and a RESTful API for implementing client reading apps.

Having a RESTful API means we can interact with the service relatively easily. However, because of the limitations of existing programming paradigms, this still involves a fair amount of legwork; and in turn, with Objective-C, a large amount of fragile, stringly-typed code. The release of Apple’s new Swift programming language presents an opportunity to revisit this approach, and hopefully improve it.

The status quo: Accessing RESTful APIs with Objective-C

Apple’s Foundation framework provides a robust set of classes for implementing HTTP networking. In Velos client applications, we typically use AFNetworking to abstract away mundane tasks like authentication, and translating JSON data to simple object types. We also use a home-grown pattern for lightweight mapping of simple object types to full model objects. For a relatively simple API call – getting a list of the user’s subscriptions – this would look something like:

@implementation FeedbinClient (Subscriptions)
// the main FeedbinClient implementation handles authentication, etc
 
- (AFHTTPURLRequest *)readAllSubscriptionsWithCompletion:(void (^)(NSArray *subscriptions, NSError *error)) {
    return [self GET:@"/subscriptions.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSMutableArray *subscriptions = [[NSMutableArray alloc] initWithCapacity:[responseObject count]];
    for (NSDictionary *subscriptionJSON in responseObject) {
        Subscription *subscription = [[Subscription alloc] initWithDictionary:subscriptionJSON];
        if (subscription) {
            [subscriptions addObject:subscription]
        }
    }
    completionBlock(subscriptions, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    completionBlock(nil, error);
}];
 
@end
@implementation NSDictionary (ValueForKeyOfClass)
 
- (id)valueForKey:(NSString *)key ofClass:(Class)aClass {
    id value = [self valueForKey:key];
    if ([value isKindOfClass:aClass]) {
        return value;
    } else {
        return nil;
    }
}
 
@end
@implementation Subscription // : ModelObject
// ModelObject implements -initWithDictionary:, which calls super and then -updateWithDictionary:
 
- (void)updateWithDictionary:(NSDictionary *)attributes {
    NSNumber *identifier = [attributes valueForKey:@"id" ofClass:[NSNumber class]];
    if (identifier) {
        self.identifier = [identifier unsignedIntegerValue];
    }
 
    NSString *createdAt = [attributes valueForKey:@"created_at" ofClass:[NSString class]];
    if (createdAt) {
        NSDateFormatter *dateFormatter = ...; // code to create/access an ISO 8601 date formatter
        self.createdAt = 
    }
}
 
@end

This code is not only inelegant, but error-prone: What if we call -valueForKey: instead of our -valueForKey:ofClass:? What if the response JSON is a dictionary, not an array? What if we mistype the URL for the endpoint? Additionally, we’ve left out a good deal of the manual authentication, type-checking, and error-checking that would be necessary in production-quality code.

A better tomorrow: Accessing RESTful APIs in Swift

By comparison, here’s the equivalent code in Swift:

public class Subscription: MapperProtocol {
    public class func map(mapper: Mapper, object: Subscription) {
        object.identifier       <= mapper["id"]
        object.createdAt        <= (mapper["created_at"], ISO8601DateTransform<NSDate, String>())
        object.feedIdentifier   <= mapper["feed_id"]
        object.title            <= mapper["title"]
        object.feedURL          <= (mapper["feed_url"], URLTransform<NSURL, String>())
        object.siteURL          <= (mapper["site_url"], URLTransform<NSURL, String>())
    }
}
public extension FeedbinClient {
    public func readAllSubscriptions() -> Future<[Subscription]> {
        return request(SubscriptionRouter.ReadAll()) { _, _, responseString in
            return Mapper().map(responseString, to: Subscription.self)
        }
    }
}

What happened here? First, using AFNetworking’s sister library Alamofire we’ve moved the routing logic to an enumeration:

enum SubscriptionRouter: URLRequestConvertible {
    static let baseURLString = "https://api.feedbin.com/v2/"
 
    case ReadAll()
    case ReadAllSince(sinceDate: NSDate)
    case Create(NSURL)
    case Read(Subscription)
    case Update(Subscription)
    case Delete(Subscription)
 
    var method: Alamofire.Method {
        switch self {
        case .ReadAll:
            return .GET
        case .ReadAllSince:
            return .GET
        // ...
    }
 
    var path: String {
        switch self {
        case .ReadAll:
            return "/subscriptions.json"
        case .ReadAllSince(let sinceDate):
            return "/subscriptions.json?since=\(sinceDate)"
        // ...
        }
    }
 
    // MARK: URLRequestConvertible
 
    var URLRequest: NSURLRequest {
        let URL = NSURL(string: SubscriptionRouter.baseURLString)
        let mutableURLRequest = NSMutableURLRequest(URL: URL!.URLByAppendingPathComponent(path))
        mutableURLRequest.HTTPMethod = method.rawValue
 
        return mutableURLRequest
    }
}

This separates the logic of creating a request for a specific API endpoint from the site of the request, additionally ensuring that we don’t munge (or leave out) any parameters.

Next, we’ve defined a method on FeedbinClient called request. It takes a value type conforming to URLRequestConvertible, like the router enum shown above, and returns a generic future. Using this method, we only need to provide a responseHandler closure for mapping the data ourselves:

public class FeedbinClient: Alamofire.Manager {
    internal func request(URLRequest: URLRequestConvertible, responseHandler: (request: NSURLRequest, response: NSHTTPURLResponse?, responseString: String) -> T?) -> Future {
        let promise = Promise()
 
        if self.credential == nil {
            promise.error(NSError())
            return promise.future
        }
 
        let request = self.request(URLRequest).responseString { (request, response, responseString, error) -> Void in
            if let responseString = responseString {
                let value = responseHandler(request: request, response: response, responseString: responseString)
                if let value = value {
                    promise.success(value)
                    return
                }
            }
 
            promise.error(error ?? NSError())
        }
 
        return promise.future
    }
}

Finally, ObjectMapper provides type-safe, bidirectional translation between JSON types and model objects. We extended the project to support mapping arrays, in addition to individual JSON dictionaries.

Is Swift worth it?

We’ve barely scratched the surface of what’s possible with Swift. Most of the time spent on FeedbinKit was trying to figure out how to translate existing Objective-C idioms to Swift, then rewriting them to take advantage of new language features. The benefits, though, are clear: cleaner code that works correctly the first time you write it.

Swift is still an immature language. Version 1.1 added failable initializers, a welcome feature that nonetheless could add a new wrinkle of complexity to existing code. Apple has made clear that we should expect similar changes in the future as the language continues to evolve and stabilize. This might outweigh the benefits in some cases, but certainly not very many.

Conclusion

FeedbinKit is now open-source under the MIT license on our GitHub page. There are a few rough edges, and we could use a lot more test cases, but if you’re curious how a few familiar patterns can be translated, please dive in.

Comment

A SECTIONED GRID FOR ANDROID

1 Comment

A SECTIONED GRID FOR ANDROID

Tablets give you a lot of real estate to play around with. Google has created several features specifically to help developers take advantage of the extra screen space, most obviously the Fragment system. However, one of the most widely-used Android components, the ListView, has not been optimized for the wider screens you encounter on a tablet.

Here at Velos, we’ve often found that presenting information in a grid format can look really sharp on tablet devices. You can present many grid items in a single row, which lets the user see a lot of information before they need to start scrolling. Since grids with fewer columns present nicely on handsets as well, it’s also a good way to maintain consistency between handset and tablet while still taking advantage of each device’s strengths.

There is a pretty significant limitation with the standard Android GridView, though: it cannot be sectioned. Like with the ListView, there’s no API-level ability to add sections that divide up the items within your collection. Designers still enjoy specifying them, though, and for good reason: section headers help give users crucial context and help them more easily navigate through a large body of information.

We had previously tackled the section header limitation for basic scrolling lists, but what about grids? Imagine that we want to create an app that presents the books in a user’s library. To make it easier to browse, we’ll put each author in a separate section. That way, you can quickly scroll down to find your author, and then look through the rows to find your particular book. (It’s tricky to find an author who’s buried between two other, more prolific writers.) The app might look something like this on a tablet:

Sectioned grid displayed on a tablet.

A phone could use a list, or just fewer columns, like so:

Sectioned grid displayed on a phone.

This isn’t supported with any native Android UI components (at least, not to the best of my knowledge), but proved to be relatively simple to implement. The key is to forget about overriding GridView, and instead build this as a complex ListView. From the ListView’s perspective, each row is a single item; we can then enhance the Adapter subclass to manage the logic of translating to the specific item in each row.

When you take this approach, your Activity and ListView are very simple. All the grunt work needed to define sections, determine how many items fit within each section, where to display the headers, and so on, can be handled within the Adapter subclass.

We have created a reusable component that does exactly this, called SectionableAdapter. A SectionableAdapter overrides two important methods. getCount() handles the conversion between the actual number of items to display and the number of rows required to display them. For example, in the first screenshot above, the screen is displaying 17 items, split across 3 different sections, for a total of 4 rows. To do this, we keep track of how many cells we can fit in each row.

@Override
public int getCount()
{
    int totalCount = 0;
    for (int i = 0; i < sectionsCount; ++i)     {         int count = getCountInSection(i);         if (count > 0)
            totalCount += (getCountInSection(i)-1) / colCount + 1;
    }
    if (totalCount == 0)
        totalCount = 1;
    return totalCount;
}

Secondly, getView() similarly manages the translation between the list row, and the items within that row. From Android’s perspective, “David Mitchell” is a single list item; internally, we expand the 5 data items to draw within that row.

You can subclass SectionableAdapter and set it on your ListView to create your own sectioned grid. You just need to provide a few pieces of information.

  1. Create an XML layout file for each row within your grid. This will probably include an optional section header at the top, and one or more cell items below. You’ll likely want to create at least two versions of this file, one for handset and one for tablet, and you may even want to create different tablet versions to optimize for both 7″ and 10″ screens, or for tablets in portrait orientation.
  2. Tell the adapter the resource IDs you have defined for the header and to hold your cell items. SectionableAdapter will then manage all the bookkeeping around this: determining whether the header should be made visible, counting the number of columns in your grid, etc.
  3. Implement the abstract methods that tell the adapter how many sections you want to support, how many items are in each section, and what header to use for each section. These are completely under your control, and depending on how you source your Adapter data source they may be statically defined, loaded from the network, driven by user input, etc.
  4. Finally, implement the bindView() method. This is basically equivalent to the standard getView() method, except the adapter has already taken care of the boilerplate tasks like recycling views, inflating new views if necessary, and so on. All you need to do now is populate your item’s UI, and attach any click handlers or other controls you want to support.

Also of note: if you still want sectioned data, but want to present it in a list instead of a grid, that is supported by SectionableAdapter as a degenerate case where you provide a single column. This might be a useful approach if you are using fragments and don’t have much horizontal space on a tablet.

This class has served us very well so far. If you’d like to give it a whirl yourself, or check out the full code, head on over to our GitHub repository.

1 Comment

HARLEM SHAKE FOR IOS

Comment

HARLEM SHAKE FOR IOS

You thought it was over didn’t you? You thought that surely this meme was done by now.

Well it’s not. Introducing Harlem Shake for iOS.

Here’s another example using MusidID:

It’s super easy to use. Just give it a view to do the initial ‘dance’ like so:

harlemShake = [[VLMHarlemShake alloc] initWithLonerView:lonerView];

Then when you want craziness to ensue:

[harlemShake shakeWithCompletion:^{
NSLog(@"COMPLETE");
}];

Please don’t ship this. And before you say anything, we know this is incredibly dumb. We promise we’ll release some real open source soon enough.

Enjoy!

Comment

iOS Development Best Practices

There are a lot of ways to successfully develop an iOS application from the ground up. Working in a team can be difficult, especially if everyone has a different idea of how to accomplish the tasks at hand. Here are some general best practices for developing an iOS app.

Register for GitHub.

Using version control of some kind is not optional. I suggest using GIT with GitHub as it adds several tools to help with collaboration such as a news feed of activity, wiki and simple bug tracker.

Define some SCM best practices.

First, start your project off on the right foot with a proper git ignore file, which GitHub provides here. Next set some guidelines for commit messages. Since you're using a bug tracker (see below), define how commits that fix bugs should be expressed. Here's an example of a good commit message.

Fix for interaction being disabled for an entire view hierarchy on iOS 4.X whereas iOS 5.0 only disables interaction on the view being animated. Now the cancel button is tappable on iOS 4.X. Fixes #243.

Now here's a bad commit message.

Fix for #243.

Make sure your team knows that you need a detailed commit message and a reference to the bug number using a unified format. Some bug trackers can parse bug numbers and assign commits to the actual bug, making a descriptive commit even more important.

Set up a bug tracker.

This part might seem optional or unnecessary on small projects. It's not. Having a bug tracker helps keep your developers focused on remaining tasks and helps management define releases.

At the very least, use GitHub Issues. But consider something a little more full-featured such as JIRA.

It's a good idea to set up best practices for your bug tracker too. Here are a couple of my personal best practices.

Everything goes in the bug tracker. No matter how trivial or silly a bug is, put it in the bug tracker. Don't mention it to a developer over lunch and think that it will get fixed. It might, but it probably won't.

Don't mix up severity and priority and use both. Severity is how severe a bug is. Does it cause a crash? Does it delete user data? Does it set the user's house on fire? Priority is how important a bug is to finish. This can (and should) factor in severity, but all Severity 1 bugs aren't necessarily the highest priority. If you have a crasher, but you can only reproduce by doing 16 tasks in a particular order, it's probably not the highest priority. Conversely, a typo would be of the lowest severity. But if it's your product name on your splash screen, that should be high priority.

Use the features of the tracker. Add a build number to your bugs. Make sure that your bugs have target versions associated with them. Attach screenshots and include steps to reproduce. These all might seem obvious, but you'd be surprised how much time is wasted working off of incomplete bugs.

Use assignment and bug state in a structured way. When a bug first gets put into the system, it gets assigned to a QA manager. QA then verifies the bug exists and cleans up the bug description and steps to reproduce. After verification, QA assigns it to an engineer. When the engineer is done, the bug is marked as fixed (not closed) and assigned back to QA. When the bug is verified fixed, it is closed.

Register for TestFlight.

TestFlight allows you to distribute iOS builds over the air to groups of testers. It's magic. TestFlight also supports distribution groups. Meaning you can choose where your builds go. Set up a "Continuous" distribution group for the automated builds. It should only include your development team and perhaps your QA. These builds are bleeding edge, so sometimes they are bug-filled.

Adding new testers to TestFlight is a breeze. Once a tester registers for TestFlight and installs a simple configuration profile, you immediately have access to her device identifier. So your new tester process will go something like this:

  1. Invite them to your team on TestFlight.
  2. Put them in a distribution group that makes sense.
  3. Add the device to your provisioning portal.
  4. Generate a new provisioning profile.
  5. Add the profile to the build machine (see below).

Setup a build machine.

Your build machine sits there, listens for updates on GitHub, builds the latest source tree and pushes the new build to TestFlight. It is the hub that stitches all these pieces together.

Continuous integration is a valuable tool for development. Being able to discover bugs as soon as they develop is required for a quality software product. If bugs are only caught near the end of a development cycle, be prepared to blow right past the due date.

Several tools can help with this battle against bugs. Jenkins is a continuous integration tool that can kick off builds as soon as commits hit your repository. Tests can be run as part of the build and developers can be held personally responsible for failures introduced.

After a successful build, TestFlight can be used to push new builds directly to your testers. Automated, bleeding edge builds can be sent to your internal QA, and select builds can be promoted to your clients or external beta testers.

I won't go into details, but if you'd like a good tutorial on setting up Jenkins + TestFlight, check out this tutorial.

Develop.

Ah, the hard part. Definitely integrate the TestFlight SDK into your app. It brings a couple cool features to the table:

  • Crash reporting. This is the killer feature. TestFlight will collate and symbolicate your crash logs for you.
  • The TFLog() calls for the sessions. In development, just define NSLog as TFLog.
  • A list of activity in your application. By using "checkpoints" you can see when users are doing particular tasks.
  • Update notifications. When your build server kicks out a new build, users of the old build will get an in-app notification of the build.

So that's a high-level overview of best practices when developing a project on iOS. I use these steps even when I'm working by myself. When working in a small or large team, being able during the debug cycle to iterate on a bug and get a build to the testers within minutes, is incredibly valuable. Once you work on a project like this, going back to ad-hoc builds and disorganized bug reporting will be unthinkable.