User Tools

Site Tools


ios-labs-s14:class-02

Introduction

This is part 2 of the iOS Crash Course.

In this section, we will go over the following topics:

  • Miscellaneous Fixes and Tips
  • Objective-C Introduction
  • Subclassing View Controllers
  • Tables

By the end of this tutorial you should have an app one step closer to “functional.” As this is the first lecture that introduces Objective-C, however, expect to take a little bit more time deciphering it. Code has been provided for you to cut and paste in the first few examples, but by the end you'll have to write a few lines of it yourself.

First, a few miscellaneous tweaks.

Git

In the first lecture of the crash course you should have made a basic interface for the sample Instagram app. Since following lectures will build upon this content it would be nice if your code perfectly matches the sample code.

The app has been checkpointed at a finished state after lecture 1 and uploaded to GitHub as a repository. You should clone this repository for lecture 2. If you have never used GitHub or even Git, read about it here (conceptual overview) when you have spare time. This guide details Git's usage from a practical standpoint.

Essentially Git and other revision control/source code management tools allow you tremendous power when working on individual projects or collaborating with others. It protects you from mistakes, allows multiple people to work on the same project safely, and gives developers the ability to track their progress.

Cloning Lecture 1 Project

  1. Open Xcode
  2. Click on Source Control > Check Out
  3. Enter the following URL for “Repository Location”– https://github.com/damouse/cs407_UWMadisonInstagram.git
  4. Save the project
  5. Open the project.

Miscellaneous

The following instructions address a few lapses from the first lecture. All of these steps are optional.

You never learned how to use the debugger or how to diagnose crashes, so a quick overview of a crash is shown.

Finally, you may have noticed some clipping between your storyboard setup and the simulator. Storyboard shows 4 inch view controllers (iPhone 5 and later), but the standard simulator is the 3.5 inch version (pre iPhone 5). Storyboard is absolutely deterministic; if you'd like to fix the clipping you'll have to switch the simulator.

Debugging

  1. Active Threads
  2. The second button from the right toggles the bottom debugging pane
  3. The Console. Upon crashing, the device will print the reason for the crash as well as a stack dump. Scroll up until you see “Terminating app due to uncaught exception….” This is the reason your app crashed.
  4. A visual object inspector, allowing you to look through all variables in memory
  5. Hit the folder button to get back to the project navigator

Changing Simulator Size

  1. To the right of the Play button in the top left corner is the name of your application. To the right of that is a blue icon with the name of the active simulator.
  2. Click this, select “iPhone Retina (4-inch)”

Dealing with an Unresponsive InterfaceBuilder

Have you tried dragging a view onto a controller only to have it snap back to the menu? InterfaceBuilder will only allow you to drag views onto controllers that it thinks are “in focus.” If you can't drag a view in, double click on the controller to zoom in, or use the zoom buttons on the bottom right of the storyboard.


Objective-C

Formally, Objectve-c is a strict object-orientated superset of C. This means is that Objective-C shares largely the same syntax and conventions as C but with an objective-orientated rather than procedural focus. It is used to create both iOS and OSX apps, and was developed by NeXT in the 80s; NeXT was purchased by Apple and while the language is not technically proprietary, it is almost exclusively used for Apple applications.

The language takes a little getting used to. If you've coded in C before the transition to Objective-C will be a little easier. Even if you have no experience in C, however, the learning curve is abrupt, but short. It takes a week or two to become comfortable.

Similarities to C

The easiest way to describe the language is to compare it to C. Again, if you have not programmed in C before this may be a tougher pill to swallow; everything you need to know is still mentioned, don't worry!

Headers and Implementation Files

Objective C makes use of header and implementation files (.h and .m respectively). The header file is where the interface of a class is defined and includes publicly visible variables, methods and import statements. The implementation file is where the implementation of those methods go, where private methods live, and is where the majority of code lives.

An sample empty, auto-generated header file.

An sample empty, auto-generated implementation file.

Objective-C Syntax

Two things differentiate Objective-C from other languages you may be familiar with. The first is obvious: this language has a different syntax than others. The second is a little less subtle: conventions drastically alter the appearance of the code.

Convention- Uncomfortable Verbosity

You've probably noticed by now that methods in objective-c are lengthy. This is a convention. All names in Objective-C should be as long and painfully verbose as needed to describe the function or variable.

Why do this? Simply, so that code can be read aloud in a logical way. Method arguments are inter-spaced with the method names, by having long method names and variables, you can read along the line and clearly see whats happening.

So keep your mtri_sk_main and dCV() and strerror in your other languages, here everything should be spelled out in camel case. If this seems too painful to do, and it should, don't worry. Xcode's autocomplete is the only reason this works as a method of coding; it does 90% of the coding for you.

Convention- 2-letter Prefixes

All variables used officially in Objective-C are prefixed with two letters that inform the developer which framework they come from. You don't have to prefix your variables UNLESS you provide your code to other people to use.

The method above uses items and methods from a library called RestKit. The prefix is “RK.”

Syntax- Class Declarations

2_30.jpg

Syntax- Class Instatiation

When declaring an object, Objective-c uses two phrases: “alloc,” and “init”

  1. Alloc-Allocates space in memory
  2. init-Calls the constructor

You may have noticed by now Objective-c uses pointers. if you don't know pointers, don't worry about it now, just emulate the syntax written here.

Syntax- Method Declarations

2_30.jpg 2_31.jpg

Syntax- Messaging/Method Calls

  1. Method type - a “+” means this is a class method. Likewise a “-” denotes an instance method
  2. Return type - In this instance the return type is void
  3. Method Signature Keywords - the separate parts of the method name InsertObject:atIndex. Unlike most of java the method is treated like separate blocks
  4. Argument types - Parameter types that the method are asking for. In this case “id” and “NSUInteger” -
  5. Parameter names -Just the names of the objects you are feeding the method: an id named anObject and an NSUInteger named Index

Nothing too difficult here. Notice how the method declaration reads almost like a coherent sentence: “Insert object anObject at index index.”

In java and many other languges, the most commonly used notation for method calls is the dot notation. For example:

object.doSomething(Stuff, moreStuff);

Objective-C is different in that no methods are ever called. Instead, objects exchange messages. For all intents and purposes, this is a semantic difference, and you can consider methods being called as they are in every other language.

[object doSomethingwith:stuff andThen:moreStuff];

In this example, the method called “doSomethingWith:andThen:” is called on the object called “object.” “stuff” and “moreStuff” are arguments passed into the method.

Essentually, the usual “(” is replaced with “:” to signify arguments, and methods with more than one parameter generally split the method call name. The general form for a multi-parameter method call usually looks like this:

[object methodPart1 :parameter1 methodPart2 :parameter2];

Look back at the picture of the insertObject:atIndex method. The code to call this method is

[array insertObject:object atIndex:int] 

where array is the object's name.

Syntax-Properties

Properties private instance variables with auto-generated getters and setters.

  1. weak/strong- hold onto the variable strongly in case of “garbage collecting,” or do not
  2. nonatomic- do not create locks for this variable

Example of property usage in a header file.

Commonly Used Data Structures

Most of the data structures in Objective-C are pretty much similar to their counterparts in other languages

NSArray

NSArray class and example implementation.

NSString

An example usage of an NSString.

NSDictionary

Storage object that sorts items based on a “key”. Calling with the key returns the data at that key location.

If you ever find yourself stumped about anything data structure related, Apple has some excellent documentation at https://developer.apple.com/library/mac/navigation/ . StackOverflow should be your first stop for any other issues.

UI Touches

Before we dive into the code for today's lecture, there are a few more touches we have to add to the interface of the app, specifically the table. UITableViews are incredibly common, and can be found in almost any app on the App Store. Their purpose is to display a set of data; because they have to deal with almost any kind of data and they are used so often, there are a few details that have to be taken care of to customize their use.

First, we'll have to add a static UITableviewCell to get a visual representation of the cells we'll use. Dynamic cells are not shown in the storyboard and are spawned at runtime. Strictly speaking, there is no need to make a static cell in this app, however creating static cells allows us to view them in InterfaceBuilder, which is key to later customizing them.

Then, we'll connect that cell to the last view controller that doesn't have a segue. The steps are the same as before, right-click and drag to the view controller.

Finally, we'll set titles on all of the view controllers.

This will be the first experience with the right pane of Xcode, which allows us to customize properties of views, controllers, and files through a simple GUI.

Adding Static Table Cells

  1. Make sure the table is selected in the storyboard. Click on the icon for the Attributes Inspector, it looks like a badge (circled in screenshot below)
  2. Set the Content field circled below from “Dynamic Prototypes” to “Static Cells.”

You should see blank cells appear within the table. You could now customize them by dragging and dropping views onto them like we did with the controllers, but that is out of the scope of this tutorial.

Creating a Table Segue

  1. Click on the first cell in the table
  2. Right-click on it and drag it to the Posts controller, directly to the right
  3. Select “push” from the popup

Remember that a push segue relies on a UINavigationController to maintain the stack of ViewControllers that make up your app.

Changing View Controller Titles

  1. Ensure the original, greeting view controller is selected
  2. Double-click in the middle of the top, grey bar
  3. Enter “UWMadisonInstagram”

Generally, with stock assets and view controllers, we set the titles of controllers to expose which part of the app the user is on. Though not strictly necessary, they will make the structure of the app more clear in the upcoming steps.

Repeat the instructions above for the other view controllers so they match the second screenshot.


Subclassing ViewControllers

There's one big problem with the app as designed so far. If you've been paying attention, you may have anticipated it by now.

Think back to the last lecture, when you connected the “Greeting” button and label on the original view controller. After making an IBOutlet and IBAction in the ViewController.h file, we added code in ViewController.m to respond to the button press.

Now there are 4 view controllers on the screen. In the project navigator, you can see there is only one ViewController class. How do we connect IBConnections from each individual view controller to code? Do they all go to the same source code files? How can we tell which view controller is active?

The answers are: can't, no, subclassing. In Java (or any object-oriented language) you rarely code inside of stock objects: you don't start editing Java String class when you need to change its behavior, you subclass it. In iOS, every controller is a subclass of UIViewController. The object we coded in last time is an auto-generated subclass called ViewController. When a controller appears on the screen, the source code associated with it is instantiated and brought into memory. Although the source code files on the left seem separate from the view controllers in InterfaceBuilder, they are one and the same.

In order to connect all the views we added in the last lecture to code, we have to create new UIViewController subclasses for each controller shown in InterfaceBuilder and then inform InterfaceBuilder which source code it should associate with controllers.

Remember, the app will have 4 ViewControllers:

  • Home- this is the controller you already have on the screen. Users will use this as springboard to access the rest of the app. This will be the first controller to appear. Contains two buttons that transition to Settins and Posts. Since this has already been implemented, we will not add it again and leave the name as ViewController. (Note: this is bad style)
  • Settings- users can set the number of posts to display in the Posts controller here. It will be called SettingsViewController.
  • Posts- display a list of each user and each comment for all the instagram pictures within a scrollable table. When a user touches an entry, transition to the Images controller. Name: PostsViewController
  • Images- display the Instagram image and the comment below it. ImagesViewController.

Note how annoyingly verbose the above names are. It may be revolting at first, but just drink the Kool-Aid, you get used to it.

Creating the SettingsViewController subclass of UIViewController

  1. Go to File > New > File
  2. Ensure the category is “Cocoa Touch” and the template is “Objective-C class.” Click “Next”
  3. Enter “SettingsViewController” in the class field and ensure that “subclass of” is UIViewController. Click next and then create.

This example demonstrates how to subclass a UIViewController specifically for SettingsViewController; change the name and repeat the process for the other view controllers with the names listed above

Note the new source code files visible in the project navigator. Each time you create a view controller the source code files are added to the existing project. One step separates us from actually using the view controllers, however. We must let InterfaceBuilder know that the view controllers placed in the storyboard are the subclasses we just created. Without an explicit assignment InterfaceBuilder cannot tell which new class should be associated with which view controller.

Note: when clicking on the body of a ViewController, Xcode thinks you want to click on the ViewController's views; notice that whatever is highlighted blue is what is currently selected. To select an entire controller, click right at the very top of the rectangle in your storyboard: this is the status bar, and always refers to the controller below it. If you have the Identity Inspector tab open in the right pane and you're working with a stock controller, the “Class” field should read “UIViewController” when you have selected the right thing. If it says “UIView” or anything else, try again.

Change View Controller Classes

  1. Select the storyboard file to bring up InterfaceBuilder
  2. Click on the settings view controller. Select the identity inspector in the right-hand pane
  3. Enter the name of the subclass as pictured.

Repeat these steps for each controller on the storyboard.

Connecting new IBOutlets

Even though the views are present in the view controller's views, the controllers' code still don't have access to the views. These instructions will not be as explicit as last lecture. If you can't remember how to connect IBOutlets, please check the previous lecture.

Connect SettingsViewController Outlets

  1. Select the SettingsViewController in storyboard, open the Assistant Editor, and insure the header file is selected (*.h)
  2. Enter the curly braces and right-click drag from the text field to within the braces. Enter textfieldNumberOfImages as the name

Repeat these steps for Images and Posts view controllers. ImagesViewController is shown below.


Tables

You can't go too far in an iOS project without stumbling over a few tables. They are too useful to ignore, and too complex to replace yourself. Although a table is not the most useful view for this project, it is more simple than the alternative and far more common (the alternative is a UICollectionView.)

Delegation

Delegation is the process of assigning another object to handle the administrative tasks of a given object. Some objects in Objective-C will crash your app if their delegate has not been assigned, tables are one of these. At its most basic, delegation protects MVC and makes your life as a developer much easier. I'll go ahead and spoil something for you: you do not want to mess with UITableView source code.

Instead, we rely on stock UITableViews and customize their behavior by assigning delegate and data source. By doing this, the table will call a known set of methods on the delegate when it has questions about how it should behave. In order to complete the connection, we must implement those methods in the delegate.

Setting a Table Delegate

  1. Select the ImagesViewController in Storyboard. Expose the view controller's heirarchy by clicking the Document Outline button (circled below.) This exposes the explicit heirarchy of views for this controller.
  2. Select the table and right click
  3. Drag from the delegate circle to the yellow ImagesViewController entry in the outline opened on the left. See screenshot.
  4. Repeat last two instructions, but dragging from dataSource instead.

Seem cumbersome? Maybe, but just like last time you've performed all of the steps needed to create tables. Without informing the table what its delegate and dataSource should be, it has no idea where to look for its internal data. Now, the ImagesViewController has to implement the delegate methods so it can appropriately serve that data.

Implementing Table Delegate and Data Source Methods

  1. Open ImagesViewController.m
  2. Copy the code below before the @end in the file. See screenshot.
#pragma mark Table Delegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
    }
    
    return cell;
}

#pragma mark - Tableview Data Source
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

There's one more (rather unfortunate) step left in assigning the table cells to the table. In order for the table to save memory, it doesn't delete cells that no longer appear on the screen, it simply reuses them again. In order to reuse the right cell, a reuse identifier must be set.

Setting a Reuse Identifier

  1. Open storyboard. Go to the Attributes Inspector.
  2. Select the static table cell
  3. In the Identifier field, enter “cell”

Now we're ready to test the table! If you run it now, you should see nothing, just 10 blank cells. To test, we're going to set the fields of the cell with some obvious dummy data. Here you're going to have to do a spot of coding yourself. There are two lines you must add, one to set the text of the main label and one to set the text of the sublabel (both are subviews of the table cell.) I won't write it out for you, but I'll give you a few hints. These lines should be put right before return cell in the cellForRowAtIndexPath method. See screenshot below for result.

  1. The two labels you must access are called textLabel and detailTextLabel
  2. You can access each using the dot operator on the cell object
  3. You used the method needed to change the text of a label in the previous lecture. The code is in ViewController.m or on the previous tutorial page
  4. The method above takes an NSString as an argument. You create string literals using @“texthere”

Make each row of the table display some data you set using the above lines to prove everything works. For extra credit:

  1. Set each row's label's dynamically. indexPath shows the current index and column, indexPath.row shows the current index as an integer
  2. Remember, you'll have to pass a string to the label's text changing method. To include a number within the string, you'll have to create another string using NSString's class method called stringWithFormat:

Testing the Table

  1. Enter the lines of code above and run the app. It should like like the screenshot (note: extra credit shown.)


Conclusion

That's all for part two! You should have learned just a bit of Objective-C, but more importantly grown a little more comfortable with it. In the next lecture we will connect to the Instagram Server, parse the response, and load the data into the app.

ios-labs-s14/class-02.txt · Last modified: 2014/02/05 11:52 by mbarboi