Day 2 - First frustration

Aug 28, 2015 at 03:09 pm, by Pierre Liard

This is only the second day, and I had already my first frustration. Nothing really bad actually, but who likes to receive one of these nasty messages: *** Terminating app due to uncaught exception ''NSUnknownKeyException'', reason: ''[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key buttonPress" What in the world does it mean? The consequence of this exception was obvious though: the app refused to launch.

When I left yesterday, the app was just displaying some image and label, but it wasn't interactive. To make it react to the tap or the press of a user, code is of course necessary. Swift uses an interface builder called action and outlet (abbreviated IBAction and IBOutlet). An IBAction creates some code that will run only when a button is tapped, whereas an IBOutlet will change the content of an element containing code in the user interface (UI). For example, by pressing some button, the content of a label will be modified. The way of "creating code" is pretty straightforward, but if a mistake is done during this process, you're likely to encounter some problem. The way you do that is simply by selecting an element in the UI (say a button), hold Ctrl on your mac keyboard, and drag and drop into the view controller:

Interface builder

If later, after having created for example an IBAction, you want to change it to an IBOutlet, it's better to first right click on the element in the UI, click on the little cross to delete the IB link, and then to delete the IBAction in the view controller. It should avoid the message I received earlier.

To make our simple app "How old are you?" interactive, the button "Tell me!" needs to be dragged and dropped into the view controller as an IBAction, and the label and the text field as IBOutlets. So now by typing a number into the text field, and tapping the button, the label "How old are you?" will be replaced by the number in the text field.

Interactive code

This silly app illustrates how it is possible for a user to make an app reacting to a gesture. It seems easy enough, but the appearances are deceiving. Imagine you are about to create an app converting your cat's age into human age (1 cat year equals 7 years of a human life), you will probably decide to apply the same principles as before, but Swift will quickly generate errors when calculating the human age. You may think that it is enough to multiply the cat's age by seven to reach the expected result, but it is without taking in consideration a quirk of the Swift language called "variable unwrapping". Wait a moment: what does this lingo mean? To understand what it is, here is an extract of the code before the unwrapping:

Code warning

The red exclamation point in the margin indicates an error, and that the code won't compile. The code is simple: in the method "findAge" (IBAction), the variable "catAge" is assigned to the text field of the same name. This field has be determined, in the right panel of Xcode, as a number in order for the numeric keypad to pop-up when the user enter a number in the text field. It seems then that the next line of code should be fine: take the value inputted by the user and multiply it by seven. What can be wrong?

The first problem is that the catAgeTextField is a text, or, a string. In coding parley, a string is simply a series of characters. If it is not converted into a whole number or integer, Swift cannot logically perform a computation on a series of characters. It's like trying to multiply a name by seven! So the string needs at first to be converted into an integer as follows:

var catAge = Int(catAgeTextField.text)

This conversion doesn't solve yet the problem. When a user enters a value in the text field, Swift cannot know if there is something in it. It can be a number, as it can be nil.\r\nIn order to signal to Swift that there is a value, an exclamation point has to be added to tell the compiler that " yes, we are sure there is a value in the text field."

var catAge = Int(catAgeTextField.text!)

If the user clicks the button without typing a value in the text field, the system will crash, but if a value has been inputted, Swift won''t compile either. Why? It''s because there is still a third mistake. We told Swift that we are sure there is a value in the text field, but we also need to tell the code that we know for sure this specific value is a number. To do that, we need to add a second exclamation point after the parenthesis:

var catAge = Int(catAgeTextField.text!)!

This technique is named "variable unwrapping". There are quite long explanations on the web, but it''s how I understand it after having listened to Rob's explanations. The logic behind it is to try avoiding crashes because one the inputted values is nil or of an incorrect type (string or integer, for example). It's only when the conversion and the two unwrapping are done that our cat age app compiles without a hitch. However, if the user doesn't input a value in the text field and despite the correct code, the app will crash "beautifully" simply because of a nil value. It was quite a challenge to make work this simple app, but the result is worth of our effort:

Cat Age App completed


Leave a comment

Login to comment a post