Here’s an example using Swift to retrieve and parse JSON data in an iOS app. There are three Swift files. As with other posts, I like to show examples with view controllers created programmatically. I first create a Cocoa class in the Swift Language that only inherits from NSObject. Then change the superclass to UITableViewController for the ListViewController and UIViewController for the WebViewController. This creates the files without creating all of the boiler-plate code. Again, this is a technique seen in The Big Nerd Ranch books and is a way of helping one understand what is really required to instantiate a view controller and the different methods/functions that can be overridden to define the needed custom behavior for the view controller. Also, in a real app, we should create separate connection and handling classes for url requests to better separate the class responsibilities. I will demonstrate that in a later post.
AppDelegate - For brevity, I only show the ‘didFinishLaunchingWithOptions’ function from the AppDelegate.swift file. I have only added the one line below the ‘Override Point’ comment. This creates an instance of ‘ListViewController’ and sets it as the ‘rootViewController’.
// AppDelegate.swift
// SwiftJSONDemo
// Created by Tom Limbaugh on 6/15/14.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
// Override point for customization after application launch.
self.window!.rootViewController = ListViewController(style: .Plain)
self.window!.backgroundColor = UIColor.whiteColor()
self.window!.makeKeyAndVisible()
return true
}
}
ListViewController - At the top of the ‘ListViewController’ class, I create three properties. One for holding the parsed JSON data, one for the url titles and one for the url links associated with those titles. I call the fetchData() function from the override of viewDidLoad(). For this example, we’ll create the url variable using the The White House - Policy Snapshots JSON feed. Next, create an NSURLSession and start a ‘dataTaskWithURL’. Remember that an NSURLSessionTask is created in the ‘paused’ state. Hence, the ‘resume()’ call after the completion block definition, which is one of four calls that control an NSURLSessionTask state. Inside the completion block, we can handle the data associated with the response, converting it to JSON and populating arrays with url titles and links. We’ll use the titles array to populate our tableView and the links array to set a property in the WebViewController which will actually display the web content.
//
// ListViewController.swift
// SwiftJSONDemo
// Created by Tom Limbaugh on 6/5/14.
//
import UIKit
class ListViewController: UITableViewController {
var jsonData = NSArray()
var titles = NSArray()
var links = NSArray()
override func viewDidLoad() {
self.fetchData()
}
func fetchData() {
var url = NSURL.URLWithString("http://www.whitehouse.gov/facts/json/progress/education")
var session = NSURLSession.sharedSession()
session.dataTaskWithURL(url, completionHandler: {(data, response, error) in
// parse data into json
self.jsonData = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSArray
// grab the titles for populating the tableview
self.titles = self.jsonData.valueForKey("url_title") as NSArray!
self.links = self.jsonData.valueForKey("url") as NSArray!
dispatch_async(dispatch_get_main_queue()) {
// reload the tableview
self.tableView.reloadData()
}
}).resume()
}
override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return titles.count
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("UITableViewCell") as? UITableViewCell
if !cell {
cell = UITableViewCell(style: .Default, reuseIdentifier: "UITableViewCell")
}
cell!.textLabel.text = titles.objectAtIndex(indexPath.row) as NSString
return cell as UITableViewCell
}
override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
// Here we can present the view controller to display the contents of the
// link associated with the url_title
var wvc = WebViewController()
wvc.link = links.objectAtIndex(indexPath.row) as NSString
presentViewController(wvc, animated: true, completion: nil)
}
}
WebViewController - The link property for this controller was set in the ‘ListViewController’ function ‘didSelectRowAtIndexPath’. Since we don’t want the user to have to close the app every time they want to view a new policy snapshot, try adding some code to allow the user to dismiss the WebViewController.
//
// WebViewController.swift
// SwiftJSONDemo
// Created by Tom Limbaugh on 6/15/14.
//
import UIKit
class WebViewController: UIViewController {
var wv = UIWebView()
var link = NSString()
override func loadView() {
// Create an instance of UIWebView as large as the screen
wv = UIWebView(frame: UIScreen.mainScreen().applicationFrame)
// Tell web view to scale web content to fit within bounds of webview
// webView.scalesPageToFit(true)
self.view = wv
}
override func viewDidLoad() {
var url = NSURL.URLWithString(link)
var req = NSURLRequest(URL: url)
dispatch_async(dispatch_get_main_queue()) {
self.wv.loadRequest(req)
}
}
func webView() -> UIWebView {
return self.view as UIWebView
}
}
No comments:
Post a Comment