UIAlertController as a Replacement for Single Column UIPickerViews displayed in UIActionSheets

Apple deprecated UIActionSheet in iOS 8 and now requires the use of UIAlertController instead. UIAlertController adds some really great new features and I think it is a good step forward but it does break backwards compatibility with some older apps in certain cases. One specific case, that I'm going to address in this post, is the presentation of a UIPickerView in a UIActionSheet.

Displaying a UIPickerView in a UIActionSheet was a quick way to allow the user to select one item from a list of multiple items. This was an especially helpful approach because it allowed for the display of UIPickerViews in the same fashion as the iOS keyboard. Users didn't have to learn a new way to interact with UIPickerViews.

Now that UIActionSheet is deprecated there are a number of approaches available to recreating this interaction.

  1. You could add the UIPickerView to your screen and modify AutoLayout constraint constants to slide the view on and off screen.
  2. If you have the ability to target only iOS 8 and above you could build your own reusable UIViewController and display it modally with the presentation style UIModalPresentationOverFullScreen.
  3. Or, if you only need to display a single column of data for the user to select from you can use the following UIAlertController approach that is quick and easy to implement.

UIAlertController can only display buttons and text fields, but it can display a lot of them! We can use this to our advantage.

The first thing to do is setup an Array that will act as the labels for the buttons in our UIAlertController.:

NSArray *items = @[@"Unfiltered",@"2015",@"2014",@"2013",@"2012"];
self.data = items;

The default behavior of UIAlertController requires that we attach a block to each button that will be executed when it is clicked. We will use this feature to make this work more like a UIPickerView. To do this we want to be able to reference these buttons by index once they are selected in the UIAlertController. UIPickerView has a method called selectedRowInComponent: so let's emulate that. Since we only will have a single column of buttons (that's all UIAlertController supports) we can ignore the component piece. The following example will set the text of a label based on the index of the button pressed.:

-(void)didSelectRowInAlertController:(NSInteger)row {
  self.outputLabel.text = [self.data objectAtIndex:row]; 
}`

Since blocks capture their enclosing scope we can use a counter variable to represent the index of each item in our list of button titles. To do this we can loop through our list of button titles, increment our counter variable by 1 each time, and then attach a block of code to each button that calls our didSelectRowInAlertController: method and passes in our counter variable as a parameter. Here's how this piece looks. I've included the entire viewDidLoad method for clarity. You can find this full project and code on Github.:

-(void)viewDidLoad {
   [super viewDidLoad];
   NSArray *items = @[@"Unfiltered",@"2015",@"2014",@"2013",@"2012"];
   self.data = items;

   int i = 0;

   UIAlertController *alert = [UIAlertController 
     alertControllerWithTitle:@"Filter Data"
                      message:@""
               preferredStyle:UIAlertControllerStyleActionSheet];

   for (NSString *item in items) {
       UIAlertAction* defaultAction = 
       [UIAlertAction actionWithTitle:item
                                style:UIAlertActionStyleDefault
                              handler:^(UIAlertAction * action) {
                                       [self didSelectRowInAlertController:i];
                                      }];

       [alert addAction:defaultAction];
       i++;
   }
   self.filterView = alert;
}

What's nice about this approach is that it is quick, the code is simple, and it is a reusable solution. I also really like that this works like the older UIPickerView approach which may make this a solution that more easily integrates with legacy code bases that require updating.

The biggest drawback to this approach is that you have to use Apple's default UI for the AlertController but I don't see that as a big deal. This is a great time saver so you can get your app shipped.

Here's what it looks like in the simulator.

filter240wide.gif

Lego Duplo Apple Watch Stand

Since the Apple Watch has to be charged every night I figured that using it as a clock on my nightstand would be a good way to get some utility out of the charging process while I sleep.

After messing around with how to best set this I up I searched for Apple Watch stands and found a ton of options that will be shipping soon. Many of these stands are very cool looking but the biggest drawback is that they are all really expensive. While this seems like the perfect time to justify the purchase of a 3D printer I wanted to try and come up with an inexpensive solution. I have already spent enough money on the watch.

After some digging around I was able to replicate The Griffin WatchStand with Lego Duplo blocks and a small amount of 2-sided tape to hold the charger to the angled block at the top of the stand. Since I already owned the blocks this solution cost nothing. I may widen the base and adjust the color scheme a bit but overall this solution has worked well so far.

iOS Device Fragmentation, Responsive Design, and Your Team

On Wednesday, July 23rd I had the pleasure of co-faciliting an iOS discussion with Ben Shive at Venturef0rth in Philadelphia. Many thanks to the awesome people at Venturef0rth for this opportunity! The discussion was very casual and focused on how iOS 8 would impact new and existing app development. Chairs were arranged in a circle, there was no slide deck or projector, and the topics flowed from one to another based on the interests of the group. I really enjoyed the discussion and I hope that it was useful to those in attendance. It was also really great to meet a lot of new people. Philly's tech community is amazing and only growing stronger.

During the discussion I got to thinking about two things related to the rumored addition of new screen sizes to Apple's device line-up and iOS 8 app development in general.

  1. Android developers have been dealing with device fragmentation for a long time. There's a lot to be learned from their experiences. iOS dev teams would be smart to bring in some experienced Android developers for consulting on this matter to more quickly adapt workflows. I also think there's a good opportunity for Android developers looking to expand their skills into iOS development to do so based on this experience. They could be immediately productive on an iOS team by aiding in process improvements and UX design (related to varying screen sizes) while ramping up their iOS dev skills.

  2. Responsive web designers also have a lot of valuable experience to help guide UX and UI design across multiple screen sizes. If you're on an iOS team that primarily builds native apps with Apple's tools you may need to seriously think about bringing in some help in this area. I'd imagine that teams working on HTML 5 based app platforms will be much more well positioned in this area.

One of the biggest take-aways from this discussion, for me, is that iOS teams should seriously consider hiring experienced Android and/or responsive web designers to help consult on existing design and development workflows. There's no reason to build this experience from scratch and your team will be able to more quickly meet the needs of your clients or app's audience.

Date-Only Pebble Watch Face

I wanted to take some time to explore the Pebble SDK and so I built a very basic watch face that only displays the date. Since the Pebble makes it easy to scroll through the installed watch faces I thought it made sense to have one that only displayed the date and could be used as a modal view for a time-only watch face. The date-only view is also nice if your day is dragging and you catch yourself constantly looking at the time.

The code itself is very simple and based on the code from one of the default watch faces that come with the device. The real goal for me when building this watch face wasn't learning the SDK but, instead, setting up and testing the development environment. I'm working on a review of my Pebble experience both as a user and a developer that I hope to post soon. I'm also working on another watch face with the goal of digging a bit deeper into the SDK (but not too deep, I've already spent way too much time hacking around with the watch).

Download the watch face pbw file

Source on Github

The Paradox of Node Module Choice

Update: @ginger_beered points out that I could simply wrap the modules that concern me. This is a great, and simple, solution to my issue. For some reason, this wasn't obvious to me. I still think my post stands. I love the large selection of modules but I need to build more confidence in myself as a Node developer and gain more experience interacting with the community so I'm not wrapping every module I use.

I'm slowly building a web service in Node.js and learning to work with Node as I go. The most interesting part of this process for me has been seeing how the community works and how new developers are on-boarded through documentation and other materials. There are a couple of general observations I've made so far.

  • I don't remember anything about Javascript syntax or library functions. I'm guessing I never actually learned these things very well to begin with. I wrote a lot of client-side Javascript around 13 years ago but I probably did more copy-and-paste coding than anything else at that time.
  • The process of writing Javascript code hasn't really changed too much even though I'm writing server-side. Write some code. Restart the server or clear the REPL module cache. Check the results. Rinse and repeat. There may be better tools for developing Node apps beyond a text editor and the terminal but I haven't looked. I'm not complaining (too much), I'm just spoiled by IDEs.
  • Do I call it Node.js or just Node? Do I capitalize Node?
  • NPM is magical (except when it isn't) in the same way that APT feels magical on Linux. I have no complaints about NPM itself and, despite what I'm about to say, I plan on publishing some of my own modules.

My biggest issue at this point has to do with the sheer quantity of modules available for Node. I want to pick well maintained highly-used modules that will have minimal bugs and maximum performance optimizations (who wouldn't?). Since I plan to build a service that I will charge money to use I'm extra concerned about the reliability and maintainability of my codebase. As a new Node developer I'm having a hard time differentiating the good modules from the bad modules based on my criteria.

"Autonomy and Freedom of choice are critical to our well being, and choice is critical to freedom and autonomy. Nonetheless, though modern Americans have more choice than any group of people ever has before, and thus, presumably, more freedom and autonomy, we don't seem to be benefiting from it psychologically." — quoted from Ch.5, The Paradox of Choice, 2004 via Wikipedia

I'm currently using Express for the core of my app, PG because I'm using Heroku with Postgres, and several other standard built-in Node modules. I don't see myself going much beyond that in terms of community-built modules. I think I've identified a pretty good bcrypt module based upon the number of recent downloads, dependent modules, and Github activity. I hope to have the bcrypt module integrated into my app shortly and I'm curious to see how that goes. Maybe it's just me, but I'm finding it hard to evaluate modules and feel good about my choices with my limited Node experience. I wish choosing every module was as easy as choosing Express.

There are some strong aspects of the Node module ecosystem. It's great that I can fork a module and continue to maintain it as long as I need into the future. I'm happy to contribute bug fixes and updates to modules where I think I can be of help. I love the strong role that Github plays in the Node community and I already mentioned how great of a tool I think NPM is.

With that said, I'm getting older and the idea of needing to maintain a library that falls out of favor is not where I want to focus my energy. I also don't like the idea of needing to constantly refactor my application to accomodate the new module-of-the-month if there isn't some level of stability in a given category. I would rather pick a strong codebase that appears to have a long life ahead of it and put my time and energy into building my product. I would prefer a library system that supports longevity and promotes quality modules with the most potential for stability. Maybe the Node ecosystem does this already and I just don't have the experience to see it yet? Maybe the process I used to choose a bcrypt module is the way I'm supposed to pick all modules? Maybe there is an opportunity for a company to write Node modules that are closed-source, well maintained, well documented, and supported for the long-term? Maybe I just haven't participated in the Node community long enough to trust the community? Maybe I'm missing something obvious? I'm usually missing something obvious.

Node - The Very Beginning

I'm in the process of building a web service that will eventually serve a mobile app I plan on writing. I'm building the service on Heroku using Node.js.

I chose Heroku because I want to explore using a hosted development environment and I really don't want to spend time administering servers when I can be writing code. I chose Node because it seems to be popular and because I want to give Javascript a second chance.

Over 12 years ago I completely wrote off Javascript and promised myself that I would never write another line of it. I really hated the language (but I loved Perl and still do, go figure). A lot has changed in that time. Lately I've been doing a bunch of game scripting in Unity 3D using Javascript and it has been enjoyable. I have also been warming to a more functional style of coding and Javascript gives me a nice, practical, playground to explore that a bit further. In retrospect, what I hated most about Javascript wasn't the language but the amount of work required to deal with cross-browser compatibility issues. Node let's me play with Javascript without the confines of the browser.

I will be posting lessons learned, observations made, and possibly some tutorials as I work my way through the process of building this service and learning a new development stack. Hopefully these posts will be of some use to somebody.

First Lesson

I was in the process of installing the PostgreSQL module pg for use with Heroku. My main development machines are currently OS X. In the process of installing the module I got a bunch of errors related to node-gyp.js

gyp ERR! build error 
gyp ERR! stack Error: not found: make
gyp ERR! stack     at F (/usr/local/lib/node_modules/npm/node_modules/which/which.js:43:28)
gyp ERR! stack     at E (/usr/local/lib/node_modules/npm/node_modules/which/which.js:46:29)
gyp ERR! stack     at /usr/local/lib/node_modules/npm/node_modules/which/which.js:57:16
gyp ERR! stack     at Object.oncomplete (fs.js:297:15)
gyp ERR! System Darwin 12.2.1
gyp ERR! command "node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /someDirectory/SomeWhere/node_modules/pg
gyp ERR! node -v v0.8.19
gyp ERR! node-gyp -v v0.8.4
gyp ERR! not ok 

In the end it turns out I did not have the Apple command line developer tools installed. This might sound like a simple mistake, and it is, but since Xcode has moved to a single application bundle it's pretty easy to forget that the common developer tools aren't readily available to the wider system.

To resolve this issue launch Xcode, then select Preferences -> Downloads -> Components and install the Command Line Tools package.

I realize this might seem like an obvious solution but I'm guessing I'm not the last person that will run into this issue.

Node-vember

In the final month of my sabbatical I want to take some time to refresh my web development skills. I did a lot of LAMPP development from 1999 to 2003 but I haven't done any real web development since.

There are a lot of new web technologies that I could focus on but I like the idea and challenge of Node.js. I think this will be a lot of fun and I'm trying to keep an open mind about the entire process. It has been over 10 years since I have written any type of JavaScript for the web (I've written a bunch in Unity 3D) and even when I was doing so on a regular basis I know that I was doing it wrong. I like that the Node ecosystem will expose me to a lot of new technologies and development paradigms - and, lets be honest, it's what all the cool kids are doing.

iOS 6 and Rotation

The iOS 6 API introduces a new way to handle device rotation. The approach used in all previous APIs has been deprecated. What seems like a small change to the name of a method is actually a lot more problematic once you start to dig in and refactor your code for iOS 6.

While I didn't have as much trouble dealing with this as some developers I did lose a lot of time this week trying to figure out how to best adapt to the new model of handling rotation.

Here's a quick run-down of what I learned.

  • You need to define all of the orientations your app could possibly support at the application level. This means clicking on the appropriate orientations in "Supported Interface Orientations" found under your project settings -> targets -> summary or implementing the method application:supportedInterfaceOrientationsForWindow: in your app delegate. If you choose to implement the delegate method you will need to return the appropriate UIInterfaceOrientationMask combination for your application. You can find the possible mask values defined in UIApplication.h.
  • Once you've defined the global rotation options for your application you can then set the orientations that are supported by each view controller in your application. Apple has deprecated shouldAutorotateToInterfaceOrientation: and now requires you to override supportedInterfaceOrientations: in each of your view controllers that need to handle rotation. This method is similar to the app delegate method in that it needs to return the appropriate UIInterfaceOrientationMask combination for supported orientations. supportedInterfaceOrientations: is only called if shouldAutorotate returns YES.
  • When a view controller returns an orientation from supportedInterfaceOrientations: that value is compared to those values defined at the application level. If the value returned by the view controller is one of the application's supported orientations the device will rotate, otherwise it will not.
  • The only view controller that can cause the application to rotate is the top-most view controller. This is a huge change. You can no longer have child view controllers dictate to the application that a given view should rotate. This is especially tricky if your top-most view is a UINavigationController since it will ALWAYS be the top-most view. In the one application I maintain I wanted my app to support rotation in all supported iPhone directions but the only view controllers I wanted to rotate in all directions were modal view controllers (photo galleries, text editing, and web views). I didn't want the views being managed by the UINavigationController to rotate. To fix this I simply created my own subclass of UINavigationController and overrode the supportedInterfaceOrientations: method to only return the up orientation for those views on the UINavigationController's stack.
  • If your view controller still implements shouldAutorotateToInterfaceOrientation: iOS will convert the values it returns to the appropriate UIInterfaceOrientationMask values. This allows you to support iOS 6 as well as older iOS devices.

I set aside a lot of time this week to deal with issues related to the larger screen of the iPhone 5 and never once gave a thought to rotation...until I rotated my phone and nothing happened. In all honesty, I found layout issues related to the new larger screen to be the easiest issues to resolve. Refactoring to support Apple's new model of rotation was an unexpected challenge.

When Did Small Phones Become Crappy Phones?

Reading this article on Gizmodo by Sam Biddle reminded me of the old sketch on Saturday Night Live where Will Farrell talks into the super-tiny cell phone. The skit itself is not that funny but the part with the tiny phone makes everybody in the scene break character. I really don't like modern SNL but this one part of the skit is pretty good for a laugh.

Design is cyclical. In a couple of years phones will start to get smaller again or we'll end up with new technologies like the Pebble watch or Google's Project Glass to replace the large screens that are popular today.

(via daringfireball.net)