User Tools

Site Tools


android-labs-s16:ios_tutorial_4

Models, JSON, Tables and more

Introduction

For today's lab, we intend to give you a more holistic view of iOS app development using Swift. This week’s lecture threw some light on Models and data representation like JSON, and XML. This tutorial builds upon those concepts and would also help recap the concepts you guys have already learned. Hopefully, making things crystal clear.

The only way to learn the code and get used to the syntax is the struggle with it a little bit. use the internet, specifically StackOverflow. If you don't know how to do something, or can't get the syntax right (more likely) Google the method name, what you're trying to do, whatever. We are going to create an app which lists the names of people in a table view and on clicking a row, takes you to another scene which shows some more information about that user. In this project we are going to download a json file over the network, parse it, store the data in a model and supply it to the table view. Whoosh! Lot to do, so let’s get started.

Create a new Xcode project, this will be a Single View Application because we're going to do everything from scratch here, not using any of the other templates. Let’s call this “nameApp,” check that it's in Swift and for iPhone.

Now let’s start from scratch and create everything from a blank storyboard. So delete the view controller from the storyboard and it’s corresponding swift file (viewcontroller.swift). Select “Move to trash” when the popup comes.

Keep the appDelegate file, do not delete that as it handles the start up of an iOS application (Remember??? Lifecycle of an app).

The first scene we want to show is a table view where the list of names will be displayed. Drag a Table view controller inside the storyboard from the object library. This is our initial scene, so go to the attributes inspector and make this as the initial view controller (There is a check box).

Now we want to move from this, as in we want to click on one of the rows in this table and move to a view controller which would show me the description corresponding to this name.

So create another view controller, and add a label to it (You might have to zoom out/zoom in to do these tasks). Find a Label and drag it on. Put it somewhere roughly in the middle of the screen in the lower section. You can configure auto layout if you wish to (Now you guys must be expert in it).

At the moment, there are no segues between any of this yet. Let’s create one. Zoom in and do a ctrl + click from the table view controller to the controller which has the label. (Remember drag from the top - prototype cells). Select “show” as the segue type.

We would also like these view controller to be contained inside a navigation controller, because we want to be able to click the back button. Click on the first view controller, come up to editor tab and tell it to embed in navigation controller.

Fine, right now we don't actually have any code files that would tie all this together so let’s get cracking on that.

If we look at the code itself, the only thing we have is an AppDelegate, there aren't any code files that correspond to these different View Controllers. Here I'm just going to double click that bar at the top. And type in “Names,” that will show up in the navigation bar when we're looking at our names list.

Adding Class code

This application is going to show a list of names and some description so let’s go ahead and create a custom class to contain that data.

From Xcode's File menu, add a new file. Under the iOS Source menu pick the empty Swift file, Click Next, I will call this one Name with an uppercase N. The one I'm going to pick is just an empty Swift file.The one I'm going to pick is just an empty Swift file.

I'm just going to verify it's adding it to my current project called nameApp, and click Create. So I'll create this as a new class, and I will call this Name. It’s quite common to use the base class NSObject as it’s parent, but for this example we don’t need it.

And all I'm going to add here are 2 properties, they're all Strings, I'm going to have a name and a description. I am going to define these in a struct. Structs are almost as powerful as classes in Swift, so this will be perfect for our simple app.

So we're creating a struct called Name rather than a class called Name, everything else here is the same.

I can pretty much ignore the Navigation Controller. But none of these have any corresponding code files yet. So I need to add custom view controller classes for each of the scenes. The first view controller is a special view controller, so we want to create a class which gives us maximum benefit.

Go to file menu →New→File, and inside the iOS source section, pick the Cocoa Touch Class. Click Next, and the class I want to create here will be the NamesTableViewController. Now, it's crucial that this is made as the subclass of UITableViewController, not UIViewController, because that will provide some extra functionality that we would not get from UIViewcontroller.

The advantage of inheriting from a TableViewController is we get a lot of default code methods. Feel free to ponder over these functions and try to understand what do they correspond to.

We also need a controller for the second screen. So follow the same process of creating a new file but this time inherit from the normal UIViewController. You can call this so I'm going to make this optional by just adding a question mark at the end.so I'm going to make this optional by just adding a question mark at the end.so I'm going to make this optional by just adding a question mark at the end.so I'm going to make this optional by just adding a question mark at the end.DisplayViewController.

There is one catch, we haven’t yet linked these new classes to their scenes in the storyboard. Without this, the scenes don’t know which code belongs to them. To do that, click on each scene and go over to the identity inspector.

Instead of the scenes using the generic viewController, change it to the classes just created.

Creating Models for our nameApp

Although the navigation controller is our initial view controller, it doesn’t do much. For our app we need to fill up the table view controller with multiple rows of content.

Go to the NamesTableViewController.swift, and create an array of names.

This creates an empty array. We'll start adding to it in a minute.

The second scene (DisplayViewController) doesn’t need to display mulitple Names, but it does need property (description) for a single name object. So, we need to pass the current name instance whose information will be displayed.

So into the DisplayViewController, add a var currentName.

We need not worry about always providing an initial value for this as soon as the ViewController is instantiated, make it optional by adding a question mark, so I'm going to make this optional by just adding a question mark at the end.

Now we intend to programmatically change the label (Remember the IBOutlet mantra we learnt in the first lab). So use the assistant editor and add IBOutlet for the label. Control and drag. Simple. Call this detailsLabel, verify that it's an outlet of UILabel, and click Connect. The displayViewController class should look like this.

The job is not over yet

The first part of the application that needs some data loaded into it is going to be our Table Views. So go into NamesTableViewController, and in viewDidLoad, add some name objects. I know, I know, we said we will get data from JSON. We will, let’s just do it in a simple way first. I'll create a new variable called newName. It should look something like this, pretty intuitive.

So we have the objects in the array, but now we need to load them into a table view. If you haven’t seen the tutorial on Tables, do that now or learn on the go. We need to edit the methods provided as part of the code that came with UITableViewController, primarily numberOfSectionsInTableView and numberOfRowsInSection. Make them look like this.

It just says that we are returning one section, row count and what to display in each cell.

In one of the methods, we have the important cellForRowAtIndexPath. It's currently commented out, so let me uncomment that with the starting and ending comments here. It's dequeueing a reusable cell with the identifier “reuseIdentifier”.

So it is saying that the cell in the storyboard should have that name. To make sure that that is the case, go to storyboard. Take a look at the table view controller. Select a cell and in the utilities panel, in the “Table view cell” section, give the identifier a name “nameCell” and make the change in the tableView function as well.

Build the project and hopefully everything should work. At this moment, we are not passing any data in between the scenes, so let’s do that.

Passing Data

I am not going to spend too much time on this, since we have covered this in detail in the last few labs. Let me just quickly go through the steps. Go to the NamesTableViewController.swift file and un comment the prepareForSegue function and make it look like below.

Alright, now run the app and hopefully it should work perfectly fine. Now, we will bring JSON and NSURLConnection in. But first, a short primer on both of them.

NSURLConnection

NSURLConnection is a long and painful name for the object that handles iOS's internet connectivity. This class contains everything you need to access any remote API, and is commonly used to back model objects. Although not isolated because of MVC, it still relies on delegation to function. Remember that delegation is the act of nominating another object to react to certain changes in state through the implementation of delegate methods. The object that needs functionality calls the delegate methods on the assigned delegate object.

There are two parts to using NSURLConnection.

  1. Create API call and receiving variable, fire API call
  2. Implement delegate methods

The delegate methods are called as NSURLConnection moves about its business. They are extremely boilerplate, and generally you'll find yourself copying and pasting them constantly instead of writing them from scratch.

There are 4 delegate methods:

  1. didReceiveResponse- called when the first bits are received from a request
  2. didReceiveData- called as data flows in
  3. connectionDidFinishLoading- called when the data has finished arriving
  4. connection:didFailWithError- called if something goes back

Implement Delegate Methods

Note that the receiver object has been omitted in the code above (it should be right after the colon). This is the data object that the Connection class loads the data into and you have yet to make it. The circle in the screenshot above shows where it should be as a method parameter for the JSONDeserializer class.

A “receiver” object is simply an object that gets filled by another. In the case of NSURLConnection, we must use an NSMutableData object, which stores changeable binary data.

Making Receiver Object Prepare to declare a new instance variable by first adding curly braces after the class ViewController: UIViewController, NSURLConnectionDataDelegate, NSURLConnectionDelegate { line in ViewController.swift Declare the variable between the braces. The declaration should look like this: var name: type!

The variable should be of type NSMutableData. You may name it whatever you'd like

Initialize the variable in viewDidLoad Ok. We've implemented the methods and created the receiving variable. Two steps lie between us and talking to the internet: manipulating the data object previously created, and firing the API call. Again, the steps detailed below are almost always like this; I'm having you work through them manually not simply to get practice calling methods. The formation of the NSURL and NSURLRequest objects commonly look like this, treat them as one step and don't get boggled down trying to find meaning in the code.

We should be hooked up to the internet. As you can see from the post above, the URL we're headed to is http://pages.cs.wisc.edu/~achink/cs407.json . In order to check the results of your code, go there now and inspect the JSON that is returned.

You might get an error which says that since the channel is insecure, JSON can't be retrieved. Search online for answers. HINT: Something has to be added to the info.plist file

JSON

If you are doing anything on the internet, JSONs are life. JSON stands for JavaScript Object Notation, and is the more-or-less standard language of moving raw data over the open internet.

the left of the console shows a graphical hierarchy of objects.If you are doing anything on the internet, JSONs are life. JSON stands for JavaScript Object Notation, and is the more-or-less standard language of moving raw data over the open internet.

Two things make up a JSON:

Arrays- a set of objects, denoted by square brackets [] Dictionaries- keys that pair with objects, denoted by brackets, with a colon separating the key/value pairs. ex: [key : value] Primitives- strings, integers, booleans, etc Sounds simple, except that the two data structures can be infinitely nested within each other, as you can see from the sample JSON linked above.

When NSURLConnection returns the data, we use NSJSONDeserializer to convert the binary data into a dictionary. To navigate the JSON and extract useful information, you move through constituent dictionaries and arrays by using objectForKey and objectAtIndex, respectively.

For example, to retrieve the dictionary under the key “names,” you would call data.objectForKey(“names”) which returns a dictionary that looks like: {“name”:“John”, “Description”:”HOHO“},

This dictionary has two keys that match two strings.

JSON may look awful to you at first, but understanding them is absolutely essential to interacting with any server, ever.

Conclusion

Some of Raywenderlich tutorials are pretty good on the topic of JSON and Models. Hope you guys enjoyed today's session. The complete app can be found https://github.com/achinkulshrestha/xApp

android-labs-s16/ios_tutorial_4.txt · Last modified: 2016/02/26 14:09 by xuan