Category Archives: iOS

SFO API Swift Implementation

A pattern that we’ve started using at Sabre Labs in our iOS projects is that the view controllers are written in Objective-C and utility classes are written in Swift. We also try to keep as much of the heavy lifting out of the view controllers, so that the VC is responsible for just brokering the information to the view and handling all the necessary delegate methods therein. Anything that a utility class needs to bubble up is handled through a delegate method.

Here is a simple example that hits the SFO API.

First, the header file of the view controller. Note that this has been pulled out of a real project, so I present it here merely as example.

//
//  ViewController.h
//  YourProject
//
//  Created by Barrett Clark on 8/25/14.
//  Copyright (c) 2014 Barrett Clark. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <YourProject-Swift.h>

@interface ViewController : UIViewController <SFOProtocol> {
  SFO *sfo;
}

@end

And now the implementation file:

//
//  ViewController.m
//  YourProject
//
//  Created by Barrett Clark on 8/25/14.
//  Copyright (c) 2014 Barrett Clark. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
            
- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.
  sfo = [[SFO alloc] initWithApiKey:@"sekretkey"];
  sfo.delegate = self;
  [sfo getAirlinesWithOffset:0 limit:5];
  [sfo getDiningWithOffset:0 limit:5];
  [sfo getPassengerServicesWithOffset:0 limit:5];
  [sfo getShoppingWithOffset:0 limit:5];
  [sfo getThingsToDoWithOffset:0 limit:5];
}

#pragma mark SFO Protocol
- (void) didReceiveAirports:(NSArray *)results {
  NSLog(@"Airports: %@", results);
}
- (void) didReceiveDining:(NSArray *)results {
  NSLog(@"Dining: %@", results);
}
- (void) didReceivePassengerServices:(NSArray *)results {
  NSLog(@"Passenger Services: %@", results);
}
- (void) didReceiveShopping:(NSArray *)results {
  NSLog(@"Shopping: %@", results);
}
- (void) didReceiveThingsToDo:(NSArray *)results {
  NSLog(@"Things To Do: %@", results);
}

@end

And finally, the “utility” file. I don’t generally use AFNetworking. The standard library HTTP calls are good enough for me. Perhaps the completion block that is mostly redundant can be streamlined. I welcome your comments.

//
//  SFO.swift
//  YourProject
//
//  Created by Barrett Clark on 8/26/14.
//  Copyright (c) 2014 Barrett Clark. All rights reserved.
//

import Foundation

@objc protocol SFOProtocol {
  optional func didReceiveAirports(results: NSArray)
  optional func didReceiveDining(results: NSArray)
  optional func didReceiveShopping(results: NSArray)
  optional func didReceiveThingsToDo(results: NSArray)
  optional func didReceivePassengerServices(results: NSArray)
}

@objc class SFO: NSObject {
  var delegate: SFOProtocol?
  let queue = NSOperationQueue()
  var apiKey: NSString
  let baseURL = "http://www.flysfo.com/api"
  
  init(apiKey: NSString) {
    self.apiKey = apiKey
    super.init()
  }
  
  /*
   * Airlines
   * http://www.flysfo.com/api/airlines.json?limit=20&key=[Your API Key]
   */
  func getAirlines(offset: Int = 0, limit: Int = 30) {
    var request = requestForURL(limit: limit, offset: offset, endpoint: "airlines")
    
    let completion = { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
      let res = response as NSHTTPURLResponse!
      if ((error) != nil) {
        println(error.description)
        return
      }
      var error: NSError?
      if (data != nil) {
        var e: NSError?
        var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &e) as NSArray
        self.delegate?.didReceiveAirports!(jsonResult)
      }
    }
    NSURLConnection.sendAsynchronousRequest(request, queue: self.queue, completionHandler: completion)
  }

  /*
   * Dining
   * http://www.flysfo.com/api/dining.json?limit=20&key=[Your API Key]
   */
  func getDining(offset: Int = 0, limit: Int = 30) {
    var request = requestForURL(limit: limit, offset: offset, endpoint: "dining")
    
    let completion = { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
      let res = response as NSHTTPURLResponse!
      if ((error) != nil) {
        println(error.description)
        return
      }
      var error: NSError?
      if (data != nil) {
        var e: NSError?
        var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &e) as NSArray
        self.delegate?.didReceiveDining!(jsonResult)
      }
    }
    NSURLConnection.sendAsynchronousRequest(request, queue: self.queue, completionHandler: completion)
  }

  /*
   * Shopping
   * http://www.flysfo.com/api/shopping.json?limit=20&key=[Your API Key]
   */
  func getShopping(offset: Int = 0, limit: Int = 30) {
    var request = requestForURL(limit: limit, offset: offset, endpoint: "shopping")
    
    let completion = { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
      let res = response as NSHTTPURLResponse!
      if ((error) != nil) {
        println(error.description)
        return
      }
      var error: NSError?
      if (data != nil) {
        var e: NSError?
        var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &e) as NSArray
        self.delegate?.didReceiveShopping!(jsonResult)
      }
    }
    NSURLConnection.sendAsynchronousRequest(request, queue: self.queue, completionHandler: completion)
  }

  /*
   * Things To Do
   * http://www.flysfo.com/api/things-to-do.json?limit=20&key=[Your API Key]
   */
  func getThingsToDo(offset: Int = 0, limit: Int = 30) {
    var request = requestForURL(limit: limit, offset: offset, endpoint: "things-to-do")
    
    let completion = { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
      let res = response as NSHTTPURLResponse!
      if ((error) != nil) {
        println(error.description)
        return
      }
      var error: NSError?
      if (data != nil) {
        var e: NSError?
        var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &e) as NSArray
        self.delegate?.didReceiveThingsToDo!(jsonResult)
      }
    }
    NSURLConnection.sendAsynchronousRequest(request, queue: self.queue, completionHandler: completion)
  }

  /*
   * Passenger Services
   * http://www.flysfo.com/api/passenger-services.json?limit=20&key=[Your API Key]
   */
  func getPassengerServices(offset: Int = 0, limit: Int = 30) {
    var request = requestForURL(limit: limit, offset: offset, endpoint: "passenger-services")
    
    let completion = { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
      let res = response as NSHTTPURLResponse!
      if ((error) != nil) {
        println(error.description)
        return
      }
      var error: NSError?
      if (data != nil) {
        var e: NSError?
        var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &e) as NSArray
        self.delegate?.didReceivePassengerServices!(jsonResult)
      }
    }
    NSURLConnection.sendAsynchronousRequest(request, queue: self.queue, completionHandler: completion)
  }

  private func requestForURL(#limit: Int, offset: Int, endpoint: NSString) -> NSMutableURLRequest{
    let theURL = "\(baseURL)/\(endpoint).json?limit=\(limit)&offset=\(offset)&key=\(apiKey)"
    let url = NSURL(string: theURL)
    var request = NSMutableURLRequest(URL: url)
    request.cachePolicy = .ReloadIgnoringLocalAndRemoteCacheData
    request.timeoutInterval = 30.0
    request.HTTPMethod = "GET"
    request.setValue("application/json", forHTTPHeaderField: "Accept-Encoding")
    return request
  }
}

Leave a Comment

Filed under iOS, programming

Mobile Development

I’ve been excited for the past year or so about RubyMotion, and I was even more excited when they announced support for Android.

Then I went to WWDC.

I already felt like PhoneGap was too much of a disconnect.  Mobile web and PhoneGap are good in a pinch, and there are things that are more easily done in a web form.  However, I’ve had a growing feeling that if you have the ability to make a native app then that is the right answer.  Anything short of making a native app is a shortcut that you’ll eventually regret.

You already don’t control the ecosystem, but if you’re depending on someone’s abstraction of the native implementation then you’re one step removed from the metal.  More importantly, being as close as possible to the metal gives you a more intimate feel for the nuances of that platform.

iOS 8 doesn’t look all that different compared to the bold new look of iOS 7.  But everything is different.  Just slightly enhanced or extended.  Apps can work together seamlessly.  User interfaces are adaptive.  Everything changes, but ever so slightly.

If you’re not right up against that cutting edge, then how can you fully take advantage of everything the operating system gives you?

Leave a Comment

Filed under Android, iOS, programming

iOS Map Comparison

We experiment with a lot of things at work.  Tools.  Technologies.  Workflows.  Recently we were discussing an effective way to do native iOS development with the team.  I love RubyMotion.  I think it makes it faster and easier to create a native iOS app.  There is a learning curve, though.

We are considering doing a project where the app is native, and written is XCode, but the guts of the app are just web views fed by a Rails app.  But before we could really consider that as an option, we needed to know how it would handle mapping.

So I whipped up a quick and dirty RubyMotion app to see.  I used Leaflet for the HTML version, and had the webpage be served from as a resource in the app.

Choose your adventure
Choose your adventure
« 1 of 3 »

I didn’t see anything that scared me off.  You lose the native feel, but I’m not crazy about the MMMapView and it’s annotations.  I’d much rather work with Leaflet and use markers.

So it looks promising.

Here’s a link to the project: https://github.com/barrettclark/MapCompare

Leave a Comment

Filed under iOS, programming, ruby