Friday
Nov302012

Transitioning Cell-Based to View-Based Table Views in Cocoa

Last year, Apple introduced OS X Lion with support for view-based NSTableView. The next version of Iron Money for Mac requires OS X Lion, and thus I had the opportunity to start using view-based NSTableViews. I didn’t find a quick guide for going from cell-based NSTableViews to view-based NSTableViews, so here’s a quick look at what it takes. Note: this is for uses of NSTableView in Interface Builder without bindings.

In Interface Builder

Making the transition in Interface Builder is pretty easy. Simply select the NSTableView, go to the Attributes Inspector, then change the Content Mode from Cell Based to View Based. This will add NSTableCellViews to your existing columns.

You’ll want to copy the NSTableViewColumn’s identifier (under the Identity Inspector) to the new NSTableCellView’s identifier. You’ll also want to change the new NSTextFieldCells to match the attributes of your old ones.

NSTableViewDelegate: cell values

You will want to replace your instances of - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex with - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row. In the viewForTableColumn method, you’ll use - (id)makeViewWithIdentifier:(NSString *)identifier owner:(id)owner to grab an instance of the view you need, and from there you can customize it. It’ll look something like this:

- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    NSTableCellView *tableCellView = [tableView makeViewWithIdentifier:[tableColumn identifier] owner:self];
    if ([[tableColumn identifier] isEqualToString:@"identifier"]) {
        [[tableCellView textField] setObjectValue:@"object"];
    }
}

NSTableViewDelegate: customizing cells

In Iron Money for Mac, the amount column displays positive amounts in green and negative amounts in red. - (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex is not used in view-based NSTableViews, so you’ll want to customize the instances of NSTableCellView used in columns for which you’d like to customize their display.

First, create a new subclass of NSTableCellView. In this subclass, you can implement whatever methods you need to customize the display of your view (or the text field inside your view). In the case of Iron Money for Mac, that meant implementing - (void)setBackgroundStyle:(NSBackgroundStyle)style and changing the text field cell’s text color. Here’s an example of what it would look like if you wanted the column’s text to appear in red while it wasn’t selected:

@implementation CustomTableCellView
-(void)setBackgroundStyle:(NSBackgroundStyle)style {
    if (style == NSBackgroundStyleDark) {
        [self.textField.cell setTextColor:[NSColor selectedTextColor]];
    } else {
        [self.textField.cell setTextColor:[NSColor redColor]];
    }
    [super setBackgroundStyle:style];
}
@end

Then, in Interface Builder, you’ll select the appropriate NSTableCellViews and change their Class (under the Identity Inspector) to an instance of your new NSTableCellView subclass.

Wednesday
Oct312012

Designing Budgeting for Iron Money

I have been eagerly anticipating the introduction of budgeting to Iron Money for years. The original private beta had budgeting, and that was over three years ago. Ever since scrapping the private beta and not including budgeting in the first public beta, I knew that introducing budgeting would be one of my most important—and difficult—accomplishments. For years I’ve conceptualized how I think budgeting should work, and now it was time to finish designing how it would work and be integrated into Iron Money.

Starlight

Budgeting systems are very popular among consumers. I think people like to latch on to a system that they can follow, rather than just buy into an app or service and use the tools. Budgeting systems provide a little bit more structure and personality, and I wanted to make sure Iron Money not only allowed for other budgeting “systems,” but also had its own.

So, I defined the basic tenants of budgeting with Iron Money. As much as possible, I wanted it to be fairly hands-off; set it up, tweak it a little bit from month to month, but in general, don’t worry about it. I also think it’s really important to start designing products and services with voice in mind. If this were a voice-activated system, how would it work? If the budgeting system were a human, what would you ask it to do and how would you expect it to work?

I devised a fairly simple system: for each spending category, add an expected amount of spending per month/year. Iron Money will automatically distribute the requested money to each category from the user’s income. If the user doesn’t have enough cash on hand, credit could be used to cover necessary expenses.

That’s it. A simple list of budgets to check to see whether you have enough money to spend or not. Iron Money automatically handles distributing your income and saving up for future budgets. Everything you don’t budget for is counted against Available Funds. The simplicity of this system cannot be overemphasized.

Red

I typically prefer to design new features for iOS first. I find the simplicity required by iOS makes it easier to build the Mac and web apps correctly.

I took a look at the main budgets list. This list shows each budget and how much is available to spend—right now. This is arguably the most important view, especially in the iOS app—it answers the “can I afford to make a purchase right now?” question. In tandem with that question is “how long does this money need to last me,” which could be answered by a little progress bar under each budget; it subtly shows if you’re on track for the month or if it looks like you’re going to blow your budget. It’s tinted green if you’ve spent less than where you should, yellow if you’re over what you should’ve spent, and red if you’re over the budgeted amount.

I Almost Do

One issue I was really unsure about was prioritizing the budget. At first blush, the most simple answer is to not prioritize at all. I debated whether or not prioritization was absolutely necessary and came to the conclusion that some form of prioritization was needed. Iron Money’s budgeting system is based on the idea that there are some categories which must receive their money, and others for which it is optimal if they receive their full amount.

Thus, a binary prioritization scheme was born. Budgets would be separated by needs vs. wants, with needs always receiving their money (even if credit financing is required), while wants will get their money if they can (no credit financing allowed). This distinction provided a nice way of presenting this distinction in the interface; by telling Iron Money whether or not it was appropriate to borrow on credit to meet the budget, the entire budget would be prioritized. Everything after needs would simply be filled by date and percentage.

Percentage budgets are the only exception to this prioritization scheme. When income is made, any budgets with a percentage amount are immediately handled—whether or not they are a need or want. Then, as the time approaches for a “need” budget to be fulfilled, the need budget will steal from any percentage budgets that aren’t marked as need.

State of Grace

There are a number of things that I wanted to do that were cut.

First, I originally planned to have Savings based on each income category. The idea was that a budget could be tied to an income category so it would only pull money from that income category. However, there were a bunch of issues with this, so I had to pull it.

Second, I wanted Iron Money to have a reservation system for budgets. The idea (very similar to how Simple’s Goals feature works) was to have Iron Money set aside money for each of its budgets over time, so it could take money out of Savings and warn the user if they were getting close to not being able to fulfill a budget. This feature was a bit complicated and not as necessary (especially since the warning system could be built without having the reservation system), so it was pulled within the first couple of weeks of building budgeting. It saddens me that this was pulled, since I thought this was one of the primary awesome things about budgeting with Iron Money, but for the sake of simplicity, it was not going to happen in the first release.

Third, I’ve been on the fence as for whether or not a user should be able to set a budget for an “other” category. On one hand, since it’s a category, it should be allowed; on the other hand, “other” spending can be handled by the parent category, and the parent category can handle all other spending (even outside the “other” category). For now, I’ve stayed conservative and only allowed “spending” category to be used as a spending category for budgets.

Fourth, I originally planned for percentage budgets to exist. The idea is simple: when money is made, any budgets with a percentage amount immediately grab funds from the income. Again, simplicity (both in terms of implementation and user experience) won out and this was cut from the original release. This is something I’d really like to add in the future.

Treacherous

This wasn’t something that I had at all thought about before I started figuring out how Available Funds would work. Once I started looking at account types, I realized that Savings should only reflect liquid accounts, and thus it was born.

Everything Has Changed

It took me a couple months to implement budgeting: a few hundred man hours for what might seem like a relatively simple feature.

It was anything but.

A great example of the complexity of creating budgeting is in a simple feature built so that it would work correctly. As soon as a budget occurrence ends, funds are transferred out of the occurrence and to the next occurrence (for a rollover budget) or back to Available Funds. However, since transactions sometimes aren’t added for an occurrence until after it ends (e.g. a purchase at the end of the month that isn’t reconciled by the bank until the next month), Iron Money has to be able to modify the occurrence to reflect the correct amount spent, which also affects the amount that would move to a rollover budget or Available Funds. Depending on how far back the occurrence was, this could cascade and affect one or more occurrences.

To combat this “back from the future” issue, Iron Money monitors when Available Funds doesn’t have the amount required by the occurrence. If it doesn’t, it looks at transfers out from Available Funds and modifies them (by either making the transfer less or deleting the transfer completely).

This also works in unexpected ways with rollover budgets. When a budget has an overage and the overage transaction is deleted, the transfer from the future occurrence to the past occurrence (for the overage) is deleted and a new transfer from the past occurrence to the future occurrence (for the rollover) is created.

I Knew You Were Trouble

When a transaction is added (without splits), it either counts as part of Available Funds or an occurrence. Either way, either liquid funds or credit is used to cover the transaction. Iron Money must keep track of the liquid or credit split in order to reverse or edit it if a transaction is deleted or edited.

Credit/liquid splits are recorded on a per-transaction, per-split basis (because transactions and splits are kept track of separately, occurrence-wise). In-line with the budget occurrence info, the credit/liquid split info is kept: the amount applied as liquid, and the amount applied as credit.

In order to have this information for each transaction, the updater will go through each user’s transactions and figure out the correct allocation. This will be done by getting the accounts, subtracting each transaction from the account to get the starting balances, “adding” the accounts as available funds, then “adding” each transaction so that it’s counted correctly.

The Last Time

Less than a week before launch, I started working on handling income transactions. Yes, just six days before launch, I started working on the second “half” of the budgeting equation.

This proved to be a royal pain in the ass. When only liquid accounts are included in a budget, it’s easy enough: each transaction is liquid and only liquid funds can be affected. However, this completely changes with credit accounts: any income into a credit account with a positive balance can be seen as straight liquid income, but when the income is for an account with a negative balance, that’s actually a reduction of credit debt (and thus should affect the credit funds, not liquid funds); thus, it increases the credit available in Available Funds but not the liquid amount.

Begin Again

The litany of ways in which the budgeting system touches all parts of Iron Money continues to provide numerous issues to fix. Throughout the entire process, I thought of ways in which it might break and focused on testing the sensitive parts and fixing the bugs. I, without a doubt, have missed things that users will run into. However, as time goes on, I’ll continue to fix these issues and refine the system so that it approaches perfection.

Sunday
Sep302012

iOS 6 Interface Conventions

Apple provides the iOS Human Interface Guidelines for designing apps for iOS. The guidelines include general rules to follow while creating an application. However, Apple also uses a number of conventions within their own apps that aren’t included in the HIG but should be followed by developers. Using Apple’s unwritten conventions helps provide consistency in applications, which allows users to bring their background from other apps to new apps and allows developers to use the paradigms with which users are already familiar. This post is a summary of some of the conventions used throughout iOS.

Navigation bars

Navigation bars typically hold a button or two to interact with the current view or to go back to a previous one.

The back button is always displayed in the upper left, and any other buttons are typically placed in the upper right. When a single button is present in the bar, it should be in the upper right, unless it’s a Cancel button (in which case it should be in the upper left).

Add buttons usually go in the upper right, while Edit buttons go in the upper left (unless they are the only one; in which case, like other buttons, they should go in the upper right).

When an Edit button is tapped, any other irrelevant navigation buttons (including back buttons) should fade away as the Edit button changes into a Done button.

In modal views, the Done or Save button should be in the upper right with a cancel button in the upper left.

Table views

When a user taps on a navigation back bar button, any selection in the previous view should fade away as the previous view comes into place.

Rows that present alerts should be centered and look like buttons.

The color of the selected item in a table view should match the color of the checkmark.

Search bars

Search bars should be hidden when a view is displayed but easily accessible when the view is scrolled down. See this in Mail, Messages, Notes, etc.

Exceptions: in Calendar, the search bar always displays in the List view because it’s essentially an infinitely-scrolling list. Additionally, the search bar is always on screen in some apps where searching is a main function (such as looking for a contact in Maps).

Text fields

Text fields within table view rows with a label on the left should be lined up together.

Consistency

Consistency across all iOS apps helps users quickly become familiar with new apps and new features. While the above is only a brief summary of some of the unwritten guidelines, hopefully it provides a good basis for checking whether or not an app is consistent with other iOS apps.

Friday
Aug312012

Wading Through The OAuth 2.0 Specification

OAuth 2.0, the “next-generation” authorization protocol, has been in development for years and met with criticism because of its complexity. As the author of an API that currently uses OAuth 1.0a, I’ve followed along and even contributed to the specification. Now that the specification is almost complete, I’ve decided to go through the specification and extract the useful parts that pertain to Iron Money’s API.

Changes in Terminology

The original community OAuth 1.0 specification used terms that were replaced in RFC 5849, and some terms from OAuth 1.0 RFC have changed in the OAuth 2.0 specification. Below is a list of terms that have changed from the community, to 1.0, to 2.0. Some of these aren’t exact matches, but generally have the same concept.

  • Consumer: client
  • Service Provider: server: resource server & authorization server
  • User: resource owner
  • Consumer Key and Secret: client credentials
  • Request Token and Secret: temporary credentials: authorization grant
  • Access Token and Secret: token credentials: access token

In 2.0, the “resource server” is what actually hosts the resources, while the “authorization server” is used for issuing tokens. Additionally, the request token (temporary credentials) is now part of the authorization grant process.

Furthermore, refresh tokens have been introduced as a way of renewing access tokens. Instead of having access tokens that are valid forever, or expire and require the resource owner to re-authorize, refresh tokens typically do not expire and can be used once an access token is no longer valid to get another valid access token with the same (or lesser) scope (permissions).

Permissions and Scope

OAuth 2.0 now implements a standard way to manage permissions via the “scope” parameter. The resource owner may or may not grant the entire list of requested permissions, so the authorization server responds with an access token and a scope parameter to indicate what scope is covered by the access token (and optional refresh token).

If a refresh token is used to get a new access token, the client may request the same or more limited scope.

State

A recommended part of the authorization process is including the “state” parameter. Useful for protecting against CSRF attacks, the “state” parameter is passed back to the client after the user authorizes it.

Client Registration

There are a few changes to client registration in OAuth 2.0.

First, the protocol no longer requires clients to be registered before making requests. Most APIs require client registration beforehand, but it’s no longer required by the protocol.

Second, clients are now classified by whether or not they can keep a shared secret (confidential vs. public, respectively).

Third, the client credentials (consumer key and secret) are now wrapped up into the “client identifier,” which is issued by the authorization server.

Authorization Grant

OAuth 2.0 provides a few different methods for a resource owner to authorize a client. In simple terms, these “authorization grants” are as follows:

  • Authorization code: very similar to the OAuth 1.0a flow, an authorization code is retrieved after the resource owner authorizes the client. This is handy for both web services and native apps.
  • Implicit: uses browser redirection to authorize an in-browser application.
  • Resource owner password credentials: the user gives their credentials to the client, which then exchanges them for an access token. This is handy for secure clients, such as OS X exchanging a user’s Twitter username & password for an access token.
  • Client credentials: for situations in which the resource owner and the client are the same, the client’s credentials are used for protected requests.

In OAuth 1.0a, fetching temporary credentials (a request token) was required before sending the resource owner to the authorization server for authorization. This is no longer required. Instead, the client redirects the resource owner to the authorization server directly with a list of permissions (scope) requested.

Each authorization grant type has a slightly different flow for authorization. The specification includes handy diagrams showing the process required for each grant type.

Moving an API from OAuth 1.0a to OAuth 2.0

I plan on making OAuth 2.0 the official authorization protocol for Iron Money’s API. Below are the changes that would be required to make this a reality.

First, I would require clients to indicate whether or not they are of the “confidential” or “public” types.

Second, access tokens would no longer be issued with a key and secret. Applications could probably use existing access token secrets as their access token under the 2.0 protocol.

Third, Iron Money’s API permissions would be renovated to support the “scope” parameter.

Fourth, the “implicit” authorization grant type would be handy for supporting in-browser applications.

Implementing a Provider

The OAuth 2.0 specification can seem daunting at first, but considering the flexibility of the protocol, it’s fairly straight-forward once you’re familiar with the terminology.

Sunday
Jul292012

Closing All Apps on iOS

Apple explains that multitasking on iOS “doesn’t slow down the performance of the foreground app or drain battery life unnecessarily”—and they’re right. However, it seems as if it’s entered common “knowledge” among iPad, iPhone, and iPod touch users that closing all the apps in the multitasking bar is required to keep a device operating in its prime. This isn’t true, and here’s a simplified explanation of why it isn’t true.

The Multitasking Bar

The multitasking bar shows a list of recently used apps. “Recently used” is a bit of a misnomer—it actually includes any app launched on the device, unless it has been removed from the list. You can remove a device from the list by holding down on its icon in the multitasking bar and tapping on its red close button. Restarting the device does not remove apps from the multitasking bar.

The multitasking bar does not show a list of running apps.

An App’s Lifecycle

Tapping an app’s icon launches the app. Unless the app has already been launched, the app goes from not running to being launched and in the foreground. The app is free to run as it pleases, responding to your every touch and swipe.

Now, let’s imagine you hit the home button or the sleep/wake button. The app is put into the “background,” where it’s allowed to run for only five seconds (with a few exceptions listed below). Once it’s done in the background, the app is suspended and is no longer allowed to run. Suspended apps don’t use any battery life.

The Background

Apps are allowed to run in the background for very specific tasks. Below are some of the reasons why an app might run in the background.

If the app needs more time to run for a specific task, it’s allowed to ask for more time—up to ten minutes. For example, when Iron Money for iOS enters the background while it’s syncing with IronMoney.com, it requests extra time to finish syncing. Again, the system only gives it ten minutes to finish; after ten minutes, the app is suspended.

If the app is playing audio, it’s allowed to stay in the background until you tell it to stop playing. For example, if you’re listening to music and put your device to sleep, the app will enter the background and continue to play music. If you stop playing music, the app will be suspended. If you start playing music again, the app will move back into the background so it can play music.

Some apps use location in the background. For navigation-like apps that require constant updates of your location, the app is moved into the background and allowed to run for as long as it’s keeping track of your location. A location services arrow will appear in the status bar while an app is tracking your location.

Otherwise, apps that just need general notification updates (e.g. you enter or exit specific regions, or your location has changed significantly) will be moved into the background when a noteworthy location change occurs. The app is not running the entire time—the system intelligently moves the app from being suspended to the background as required. The system will display an outlined location arrow in the status bar when an app is monitoring location changes.

There are a couple of other circumstances in which an app might run in the background, but the pattern is fairly clear: when an app has something to do for you, it’ll be moved into the background to run temporarily. Otherwise, the app will be suspended and won’t be running. In general, unless an app is actively doing something on your behalf, it isn’t running, and thus does not need to be manually closed.

A Perfect World

All of the above requires everything to work as planned. Of course, bugs happen, and things do not work perfectly. If your device is getting unusually warm, or your battery is draining quickly, you might want to manually close the apps you’ve used recently (especially if they use the GPS), or simply restart your device. However, this is a last resort and not something that needs to be done on a regular basis.