Vaya con iOS

In my last article on iOS programming in Swift, I showed you how to add some code to your project that would allow you to add a “Max Length” property to all its text fields, which you could set in code, or better yet, in Xcode’s Interface Builder, as shown below:

max chars text field

For more details, you should take a look at that article, iOS programming trick: How to use Xcode to set a text field’s maximum length, Visual Studio-style.

A key part of what made it work was the @IBInspectable keyword. When applied to a property of an object that can be displayed in Interface Builder, it makes that property available to the Attributes Inspector, which in turn provides a user interface for viewing and changing that property.

That got me thinking: could I apply @IBInspectable to the text field tricks I covered in my April 2015 article, How to program an iOS text field that takes only numeric input or specific characters with a maximum length?

In that article, I covered how to program text fields that accepted only specified characters or accepted all characters except a specified set, and it required making the containing view controller adopt the UITextFieldDelegate protocol and use itself as its own delegate, and then implementing the textField(_:shouldChangeCharactersInRange:replacementString:) method.

Wouldn’t it be nice if it were simpler? Consider the illustration below of an “Allowed Chars Text Field”. It lets me specify the following in Interface Builder:

  1. That characters that are allowed to be entered into the text field, and
  2. The maximum number of characters that are allowed to be entered into the text field.

allowed chars text field

This works if the set of characters that I want to allow into the text field is small. How about the case where I want to do the opposite: prevent the user from entering a small set of specified characters? That would be a “Banned Chars Text Field”, and it would allow me to specify the following in Interface Builder:

  1. That characters that are not allowed to be entered into the text field, and
  2. The maximum number of characters that are allowed to be entered into the text field.

banned chars text field

Let’s make these happen!

Limiting the number of characters that can be put into a text field

In the article iOS programming trick: How to use Xcode to set a text field’s maximum length, Visual Studio-style, we put the following code into a file named TextFieldMaxLengths.swift:

Once again, here are the annotations for the numbered comments in the code:

  1. There are two big things going on in this single line of code, which declares and initializes maxLengths, a dictionary that stores the maximum lengths of text fields:
    • First, there’s the private declaration. In many programming languages, private means “accessible only inside the class”, but in Swift, private means “accessible only inside the source file where they’re defined”. Any code inside TextFieldMaxLengths.swift has access to maxLengths, and any code outside TextFieldMaxLengths.swift does not. By putting maxLengths in the same file as our UITextField extension, we get a place where we can store the maximum lengths of text fields (remember: extensions can only add methods, not properties), and by making it private, we keep other code from messing with it.
    • Then there’s the matter of what to use as the key for the maxLengths dictionary. Swift lets you use anything that conforms to the Hashable protocol as a dictionary key, and UITextField does just that. It makes sense to use the text fields themselves as the keys to the values for their maximum lengths.
  2. Swift extensions let you add new functionality to existing classes, structs, enumerations, and protocols. We’re using an extension to UITextField to add two things:
    • maxLength, a property that lets the programmer set and get the maximum length of a text field, and
    • limitLength, a method called whenever the contents of a text field are changed, and limits the number of characters in that text field.
  3. By marking the maxLength property with @IBInspectable, we make it available to Interface Builder, which then provides an editor for its value in the Attributes Inspector.
  4. Get to know and love the guard statement and the “early return” style of programming; you’re going to see a lot of it in a lot of Swift coding. Here, we’re using guard to filter out cases where no maximum length has been defined for the text field, in which case, we simply return the theoretical maximum string size.
  5. We use addTarget in maxLength‘s setter to ensure that if a text field is assigned a maximum length, the limitLength method is called whenever the text field’s contents change.
  6. Another guard statement. Any case that gets past it is one where the text about to go into the text field is longer than the maximum length.
  7.  Cocoa sometimes likes to make things complicated. This line is the Cocoa way of saying “put the first maxLength characters of prospectiveText into text“. If you’re going to be playing with substrings, you need to get comfortable with Ranges and intervals.

max length text field

Any Xcode project containing the code in TextFieldMaxLengths.swift will have text fields featuring “maximum length” properties that can be set in either Interface Builder or in code.

text2 screenshot

If you’d like to see these “max length” text fields in action, download the Text2 project (the running app is pictured above) and try them out!

AllowedCharsTextField: A text field that allows only specific characters

Let’s build on our new, improved text fields by creating one that accepts only characters from a defined set. You might need a text field that accepts only digits, or punctuation, or the letters A, C, G, and T. We’ll make setting up such a text field easy by creating a subclass of UITextField, which we’ll call AllowedCharsTextField. Since it’s a subclass of UITextField, it inherits all its capabilities, which includes any extensions, including the “max length” one we created.

Use File → New → File… to create a new Swift File. Give it the name AllowedCharsTextField.swift, and once you’ve created it, enter the following code into it:

Here’s what’s happening just after the numbered comments in the code:

  1. Our class inherits from UITextField to get the capabilities of a text field, and it adopts the UITextFieldDelegate protocol to be able to respond to the textField(_:shouldChangeCharactersInRange:replacementString:) method in order to intercept changes to the text field just after they’ve been input by the user, but before they’re committed to the text field.
  2. allowedChars stores the characters that we’ll allow in the text field, and @IBInspectable makes its value editable in Interface Builder. Interface Builder takes the code-cased allowedChars property name and displays it as Allowed Chars in the Attributes Inspector.
  3. This indicates that this class is the UITextFieldDelegate and will implement at least one UITextFieldDelegate method — in this case, textField(_:shouldChangeCharactersInRange:replacementString:).
  4. We disable autocorrection because it has a tendency to bypass the the textField(_:shouldChangeCharactersInRange:replacementString:) method that we use to detect allowed characters. I’ll admit it; this is a quick a dirty fix. That being said, you probably don’t want “autocucumber” in a text field like this anyway. I’m looking into ways to allow autocorrection and still have this text field work as designed.
  5. This method gets called after the user has made changes to the text field, but before they’re committed. It gives us a chance to cancel those changes. The method should return true if we want to accept the changes, and false otherwise.
  6. We’re only concerned about cases where characters are added, so if this string has a length of 0, exit early.
  7. Here’s where the real work is done:
    • ?? is Swift’s nil coalescing operator. It returns the left operand if it’s not nil, otherwise it returns the right operation (e.g.: x ?? y returns x if it isn’t nil, otherwise it returns y).
    • We create prospectiveText, which is the text that would result if we accept the user’s changes.
    • If prospectiveText contains only the allowed characters, we return true; otherwise, we return false.
  8. We’re using an extension of String to give it a containsOnlyCharactersIn function, which returns true if the string contains only the characters in the given string, false otherwise.

That’s all the code we need to create AllowedCharsTextField. To use it, drag a plain ol’ text field onto a view in the storyboard and do the following:

allowed chars 1

1. Select the Identity Inspector.
2. Select the text field.
3. Change its class to AllowedCharsTextField.

By default, the underlying class for a text field in the Storyboard is UITextField. However, the Identity Inspector lets you change the classes of things on the storyboard to other classes related by inheritance. If you got to the Custom Class  menu in the Identity Inspector and expand the Class drop-down menu, you’ll see that you now have two choices: AllowedCharsTextField and UITextField. Changing this value to AllowedCharsTextField marks the text field as an instance of our new AllowedCharsTextField instance instead of a regular UITextField.

You’ll know it’s working in the next couple of steps:

allowed chars 2

4. Select the Attributes Inspector.
5. You can now define allowed characters and maximum length in Interface Builder.

You can also define allowed characters and maximum length in code:

BannedCharsTextField: A text field that bans only specific characters

AllowedCharsTextField works well for text fields where the set of characters that we want to allow into it is relatively small. There may be times when you want the opposite: a text field that accepts all characters, except for a certain few specific ones. Let’s build one in the same way we built AllowedCharsTextField and call it BannedCharsTextField.

Use File → New → File… to create a new Swift File. Give it the name BannedCharsTextField.swift, and once you’ve created it, enter the following code into it:

Here’s what’s happening just after the numbered comments in the code:

  1. Our class inherits from UITextField to get the capabilities of a text field, and it adopts the UITextFieldDelegate protocol to be able to respond to the textField(_:shouldChangeCharactersInRange:replacementString:) method in order to intercept changes to the text field just after they’ve been input by the user, but before they’re committed to the text field.
  2. bannedChars stores the characters that we’ll allow in the text field, and @IBInspectable makes its value editable in Interface Builder. Interface Builder takes the code-cased bannedChars property name and displays it as Banned Chars in the Attributes Inspector.
  3. This indicates that this class is the UITextFieldDelegate and will implement at least one UITextFieldDelegate method — in this case, textField(_:shouldChangeCharactersInRange:replacementString:).
  4. We disable autocorrection because it has a tendency to bypass the the textField(_:shouldChangeCharactersInRange:replacementString:) method that we use to detect banned characters. I’ll admit it; this is a quick a dirty fix. That being said, you probably don’t want “autocucumber” in a text field like this anyway. I’m looking into ways to allow autocorrection and still have this text field work as designed.
  5. This method gets called after the user has made changes to the text field, but before they’re committed. It gives us a chance to cancel those changes. The method should return true if we want to accept the changes, and false otherwise.
  6. We’re only concerned about cases where characters are added, so if this string has a length of 0, exit early.
  7. Here’s where the real work is done:
    • ?? is Swift’s nil coalescing operator. It returns the left operand if it’s not nil, otherwise it returns the right operation (e.g.: x ?? y returns x if it isn’t nil, otherwise it returns y).
    • We create prospectiveText, which is the text that would result if we accept the user’s changes.
    • If prospectiveText contains only the allowed characters, we return true; otherwise, we return false.
  8. We’re using an extension of String to give it a doesNotContainCharactersIn function, which returns true if the string doesn’t contain any of the characters in the given string, false otherwise.

That’s all the code we need to create BannedCharsTextField. To use it, drag a plain ol’ text field onto a view in the storyboard and do the following:

banned chars 1

1. Select the Identity Inspector.
2. Select the text field.
3. Change its class to BannedCharsTextField.

By default, the underlying class for a text field in the Storyboard is UITextField. However, the Identity Inspector lets you change the classes of things on the storyboard to other classes related by inheritance. If you got to the Custom Class  menu in the Identity Inspector and expand the Class drop-down menu, you’ll see that you now have three choices: AllowedCharsTextFieldBannedCharsTextField, and UITextField. Changing this value to BannedCharsTextField marks the text field as an instance of our new BannedCharsTextField instance instead of a regular UITextField.

You’ll know it’s working in the next couple of steps:

banned chars 2

4. Select the Attributes Inspector.
5. You can now define allowed characters and maximum length in Interface Builder.

You can also define allowed characters and maximum length in code:

“Allowed + Banned Chars Text Fields”: A sample project showing text fields with maximum lengths, AllowedCharsTextField, and BannedCharsTextField in action

allowed - banned chars app screenshot

You’re probably raring to try out the code from this article. Here’s a project you can play with that presents a quick-and-dirty single view app with 4 text fields:

  1. A text field a maximum length of 6 characters.
  2. A vowels-only text field with a 5-character maximum length, with the Max Length and Allowed Chars properties set in Interface Builder.
  3. A no-vowels-allowed text field with a 7-character maximum length, with the Max Length and Banned Chars properties set in Interface Builder.
  4. A text field with a 10-character maximum length that accepts only the characters from the word freaky. Its maxLength and allowedChars properties were set in code in the view controller’s viewDidLoad method.

Give it a try, learn what makes it tick, and use it as a jumping-off point for your own projects!

xcode download

You can download the project files for this article (37KB zipped) here.

{ 4 comments }

adding geolocation to our weather app

The next Tampa iOS Meetup has been announced for Wednesday, May 4th at 6:30 p.m.. This one builds on the previous meetup (but if you missed the last one, we’ll get you caught up) and is called Adding geolocation to our weather app.  It takes place at our usual spot: Energy Sense Finance, 3825 Henderson Boulevard (just west of Dale Mabry), Suite 300.

We’ll pick up from where our last meetup, Build a simple weather app (and learn basic network programming along the way), left off. The app required you to specify your location before it would report the weather. But that’s not how most weather apps work: they use geolocation to get your phone’s coordinates and provide them to the weather service. In this meetup, we’ll show you how to harness the power of iOS geolocation through the Core Location framework.

We’ll begin with a quick walkthrough of last meetup’s weather app, just as a reminder for those of you who were there, and as a way for those of you who weren’t to get caught up. Then we’ll get right into the business of adding geolocation capability to our weather app, so that when you run it, it displays the weather for your location.

At the end of this session, you’ll know how to make use of geolocation through Core Location. We’ll make the source code and presentation materials available at the end, to make it easier for you to start your own geolocation projects.

Join us this Wednesday, get to know your fellow Tampa Bay iOS developers, and get ready to learn and have some fun!

Tampa iOS Meetup is a monthly meetup run by local mobile developer/designer Angela Don and Yours Truly. While Tampa has a couple of great iOS developer meetups — Craig Clayton’s Suncoast iOS and Chris Woodard’s Tampa Bay Cocoaheads, we figured that there was room for a third iOS meetup in the Tampa Bay area, and especially one that would stray into other areas of mobile development. So we made one.

The Details

  • What: Tampa iOS’ Meetup’s “Adding geolocation to our weather app” session. Please sign up on our Meetup page so we can plan accordingly!
  • When: Wednesday, May 4, 2016, 6:30 p.m. – 9:00 p.m. We’ll have some snacks at 6:30, with the presentation beginning at 7:00.
  • Where: Energy Sense Finance, 3825 Henderson Boulevard (just west of Dale Mabry), Suite 300. See the map below.
  • What to bring: Yourself, but if you’d like to follow along, bring your Macbook and make sure it’s got the latest Xcode.
  • What to read in advance: If you’re one of those people who likes to do some readings ahead of a presentation, try this example location app written in Swift. We’ll be using our own tutorial material, but this may come in handy.

{ 0 comments }

smartphone weather

Welcome to part two in a series of articles on building your own iOS weather app in Swift!

The previous article in this series showed you how to:

  • Get a key for OpenWeatherMap’s API for current weather data
  • Make a manual API call using your browser
  • Create a basic app to get the data from OpenWeatherMap
  • Tweak the app

In this article, we’ll explain the code that was presented in the previous article and make the next major step in writing our weather app: extracting the data from the JSON returned by OpenWeatherMap.

A deeper look at the code that gets the weather data

In the last installment, I gave you enough code to connect to OpenWeatherMap and retrieve the weather data, but never explained how it works. Let’s fix that oversight.

Our simple weather app makes use of the NSURLSession class along with some classes that go along with it. Together, classes in the NSURLSession family of classes give us an API for downloading and uploading data from the internet, in a number of different ways.

The diagram below shows the classes that our weather app works with, either directly or indirectly:

nsurlsession diagram

Here’s a slightly more in-depth explanation of the classes in the diagram above:

NSURLSession class Instances of NSURLSession are containers — collections of other objects — that provide an API for sending data to and receiving data from a given URL. You use the NSURLSession API to create one or more sessions, which are objects that coordinate one or more tasks, which are objects that actually transfer the data.
Shared session object The shared session object is a pre-made singleton instance of NSURLSession. It’s not as configurable as other NSURLSession instances that you can instantiate yourself, but for simple requests, such as the kind we’re making in our bare-bones weather app, it’s good enough. You access the shared session with NSURLSession‘s sharedSession class method.
NSURLSessionTask class As mentioned in the explanation of NSURLSession above, tasks are the objects within an NSURLSession instance that actually transfer the data. NSURLSessionTask is the base class for tasks.
NSURLSessionDataTask class

You typically don’t instantiate an NSURLSessionTask object, but one of its subclasses, and you do so by calling one of NSURLSession‘s task creation methods. NSURLSessionDataTask is the class for data tasks, which are used to download data from a given server into memory. We’re using an NSURLSessionDataTask instance to request and collect data from OpenWeatherMap.

In addition to data tasks, there are also upload tasks, which are used to upload data to a server, and download tasks, which are used for downloading data from a server into a file (as opposed to memory, which is where data tasks download their data to).

That’s the “big picture” view. Keep it in mind as we look at the code that does the downloading, contained in the getWeatherInfo function in the WeatherGetter class:

I’ve added number comments to the code, which correspond to the explanations below:

  1. We use NSURLSession‘s class method sharedSession to get a reference to the shared session object, and assign that reference to the local variable session.
  2. We construct an URL using the URL for OpenWeatherMap’s current weather API, filling in the blanks with the name of the city that we want the weather for, and our OpenWeatherMap API key.
  3. We want to use a data task to request and retrieve the data from OpenWeatherMap. As mentioned earlier, tasks are created by using one of NSURLSession‘s task-creation methods. In this case, we’re using dataTaskWithURL, which we provide with 2 arguments:
    • The URL created in step 2, and
    • A completion handler that executes once the task is done requesting and retrieving the data. The completion handler will receive three arguments, which we can work with:
      1. data: If the request was successfully made and the data was successfully received, this will contain that received data.
      2. response: The response from the server.
      3. error: If the request was not made successfully or the data was not received successfully, this will contain information about the error.
  4. If the error argument isn’t nil, we assign its value to a local variable also named error, and then display its contents.
  5. If the error argument is nil, it means that no error occurred, and we display both the server response and the data received, in both raw and human-readable formats.
  6. Up until this point, we’ve only defined the data task. This statement activates it.

Turning the weather data into a Swift dictionary

Right now, if the weather request was successfully made and the data was successfully received, we take that data, convert it into a human-readable string, and output it to the debug console…

…and that human-readable string looks something like this:

{"coord":{"lon":-82.46,"lat":27.95},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}],"base":"cmc stations","main":{"temp":295.49,"pressure":1015,"humidity":64,"temp_min":294.15,"temp_max":296.15},"wind":{"speed":2.1,"deg":280},"clouds":{"all":1},"dt":1460163717,"sys":{"type":1,"id":728,"message":0.004,"country":"US","sunrise":1460200241,"sunset":1460245929},"id":4174757,"name":"Tampa","cod":200}

We could simply perform all sorts of string operations to extract the data we need, but why should we? The data is already in JSON format, which maps nicely to data structures in most programming languages, including Swift. There should be a simple way to take that incoming data and turn it into a nice Swift dictionary.

Enter the NSJSONSerialization class, which can convert JSON into Foundation objects (such as arrays and dictionaries), and vice versa. It has a method called JSONObjectWithData that takes two arguments:

  • data: An NSData object containing JSON data, which we happen to have as one of the parameters of our completion handler, and
  • options: Options that specify how the JSON data should be read and how the corresponding Foundation objects should be created.

Let’s change the code so that we no longer turn the data into a string, but instead using NSJSONSerialization‘s JSONObjectWithData method to turn it into a dictionary:

If you run the app now, you’ll see that when put into dictionary form, it’s easy to extract weather data:

Date and time: 1462277829
City: Tampa
Longitude: -82.45999999999999
Latitude: 27.95
Weather ID: 800
Weather main: Clear
Weather description: clear sky
Weather icon ID: 02d
Temperature: 294.659
Humidity: 95
Pressure: 1025.47
Cloud cover: 8
Wind direction: 168.003 degrees
Wind speed: 2.11
Country: US
Sunrise: 1462272456
Sunset: 1462320359

Here’s what the complete WeatherGetter.swift should look like now:

At this point, the WeatherGetter class doesn’t just get the weather data from OpenWeatherMap; it also puts that data into a form that we can process: a Dictionary. We’re still displaying the information in the debug console — we’re still not showing it to anyone who’s not running the app with Xcode.

In the next installment in this series, we’ll take the weather data, now in dictionary form, and make it visible to the user. We’ll also make it possible for the user to enter a city to get the weather for, rather than hard-wire it into the app.

xcode download

You can download the project files for this aricle (41KB zipped) here.

{ 10 comments }

swift tips and tricks meetup

Hey, Tampa Bay iOS developers — here’s your chance to shine! At the next Tampa iOS Meetup (Wednesday, November 18th at 7:00 p.m.), a monthly gathering run by me and my friend Angela, we’re having a “Swift Tips and Tricks” night, where we’ll take turns sharing tips an tricks that we’ve either discovered on our own or found through others while programming in Swift.

Have you ever wanted to present something at an iOS meetup, but it was on a topic or technique that could easily be covered in ten or even five minutes? Well, this meetup is your chance to be an iOS rock star, as short presentations is what it’s all about! Whether you’ve been building apps since the Objective-C days or picked up Swift a couple of weeks ago, you’ve got knowledge to share with your fellow developers, who in turn have knowledge to share with you! Join us for an evening of demos, information exchange, and that buzz that you get when you’re in a room of smart, interesting people, one of whom is you!

Me and Angela at BarCamp Tampa Bay 2015.

In order to help kick off the event, I’ll start by presenting some tips and tricks that I’ve picked up while working on my own apps, and I’m sure Angela will be doing the same. After that, it’s everyone else! We invite discussions and questions throughout the meetup, as it’s the best way to learn.

Here are the event details:

  • What: Tampa iOS meetup, a new gathering in the area that complements the Suncoast iOS Meetup and Tampa Bay Cocoaheads, both worthwhile gatherings. We want to make sure that if you can’t make one local iOS event, there’ll always be another one in the near future!
  • When: Wednesday, November 18th, from 7:00 p.m. to 9:00 p.m.
  • Where: Energy Sense Finance, located at 3825 Henderson Blvd., Suite 300 (just west of South Dale Mabry)
  • If you have a tip or trick that you’d like to present, let us know! Drop us a line in the comments section at the bottom of our Meetup page or email me at joey@joeydevilla.com. We’ll provide a projector, and if you need one, a Mac to present on.
  • We’ll have provide some snacks and drinks. No idea what they’ll be, but I’ll post details as I found out.

{ 0 comments }

burning fuse
swift kick

Sometimes, you want some code to execute after a specified delay. For me, this happens often in user interfaces; there are many cases where I want some notification or other interface element to appear and then disappear after a couple of seconds. I used to use an NSTimer to make it happen, but nowadays, I call on a simple method called delay().

Consider the simple “Magic 8-Ball” app design shown below:

magic 8-ball app

The two functional interface items are the Tap me button and a label that displays a random “yes/no/maybe” answer in response to a button tap. The button should be disabled and the answer should remain onscreen for three seconds, after which the app should revert to its initial state, with the button enabled and the answer label blank.

Here’s the action method that responds to the Touch Up Inside event on the “Tap me” button:

Don’t worry too much about the randomAnswer() method; it simply returns a randomly-selected string from an array of possible answers. The really interesting method is delay(), which takes two parameters:

  • A number of seconds that the system should wait before executing a block of code. In this particular case, we want a 3-second delay.
  • The block of code to be executed after the delay. In our block, we want to blank the label and enable the button.

The block of code that we’re passing to delay() is a closure, which means it will be executed outside the current ViewController object, which in turns means that we’ve got to be explicit when capturing variables in the current scope. We can’t just refer to the button and label as tapMeButton and predictionLabel, but by their fully-qualified names, self.tapMeButton and self.predictionLabel.

Here’s the code for delay():

delay() is just a wrapper for dispatch_after(), one of the functions in Grand Central Dispatch, Apple’s library for running concurrent code on multicore processors on iOS and OS X. dispatch_after() takes three parameters:

  • How long the delay should be before executing the block of code should be,
  • the queue on which the block of code should be run, and
  • the block of code to run.

We could’ve simply used dispatch_after(), but it exposes a lot of complexity that we don’t need to deal with. Matt Neuburg, the author of the O’Reilly book iOS 9 Programming Fundamentals with Swift, found that he was using dispatch_after() so often that he wrote delay() as a wrapper to simplify his code. Which would you rather read — this…

…or this?

Here’s the code for the example “Magic 8-Ball” app, which I’ve put entirely in the view controller for simplicity’s sake:

Resources

zip file iconYou can see this code in action by downloading the zipped project files for the demo project, DelayDemo [220K Xcode 7 / Swift 2 project and associated files, zipped].

If you’d like to learn more about coding for concurrency with Grand Central Dispatch, a good starting place is the tutorial on Ray Wenderlich’s site. It’s a two parter; here’s part 1, and here’s part 2.

I found Matt Neuburg’s delay() method in his answer to this Stack Overflow question.

{ 6 comments }

tapping iphone

A quick recap

A couple of weeks ago, I posted an article that showed how to program an iOS text field that takes only numeric input or specific characters with a maximum length in Swift.

While that article focused on constraining what the user could enter into a text field, its example app has a couple of UI features that you’ll find in many apps:

  • It dismisses the keyboard when the user taps the Return key, and
  • it dismisses the keyboard when the user taps on the background.

Last week, I covered implementing the first of these two features in the article titled How to dismiss the iOS keyboard when the user taps the “Return” key in Swift. The one major takeaway from that article was that the way to dismiss the iOS keyboard after the user is editing a text field is to make the text field resign its role as first responder.

In that article, we dismissed the keyboard when the user tapped the Return key by doing the following:

  • We made the view controller adopt the UITextFieldDelegate protocol,
  • We made that same view controller the delegate for all text fields contained within its view, and
  • We implemented the delegate method textFieldShouldReturn(textField: UITextField), which is called when the Return key is tapped, and provides us a reference to the text field that was being edited when user tapped it:

In this article, we’ll look at how to dismiss the keyboard when the user touches the view in the background while editing a text field.

Dismissing the keyboard when you don’t know which text field is the first responder, but know which view the text field is in

The textFieldShouldReturn(textField: UITextField) method can be implemented to resign the first responder for a specific text field because a reference to that specific text field is passed to it. Unfortunately, we don’t get that information when the user taps on the view, and there’s no method or property in UIView that tells us which of the text field contained within it is the first responder.

In the Apress book Beginning iPhone Development with Swift, they take the “brute force” approach and implement a method that looks like this:

It works, but you need to update the method whenever you add a text field to or remove a text field from the view.

A more flexible approach is to loop through the contents of the view’s subviews property (an array of AnyObject), calling the resignFirstResponder() method for any text fields encountered along the way. I’ve seen code similar to this:

It works — as long as all the text fields in your view are immediate subviews of the view. If your view hierarchy runs deeper, you’ll have to write more code to deal with subviews or subviews. I’ll leave that as an exercise for the reader.

It turns out that there’s a simple and effective way to dismiss the keyboard for a view without knowing which text field is the first responder: call the view’s endEditing(_:) method. This method scours the view’s subview hierarchy, find the text field that is currently the first responder and asks it to resign that status. If its parameter is set to true, it forgoes the pleasantry of asking the text field to resign as first responder and simply makes it resign. If we use this method, our userTappedBackground method becomes very short and sweet:

Now that we have a method that dismisses the keyboard no matter which text field is the first responder, we need to hook it up to an event that gets fired whenever the user taps on the view.

Responding to taps on the view

These next steps will show you how to use Interface Builder to change a view so that it can respond to events, and then connect that view to the userTappedBackground method we just created.

01

1. Go to the storyboard and select the view.

2. Switch to the Identity Inspector. You can do this by either:

  • Clicking on the Identity Inspector icon (shown beside the number 2 in the screenshot above; I think the icon is meant to look like photo ID) in the Inspector Bar at the top of Xcode’s Utilities Area, or
  • Pressing command-option-3 on your keyboard.

3. In the Identity Inspector’s Custom Class section, you’ll find the Class drop-down menu. It indicates the underlying class of any object in the storyboard, and it also lets you change it. If you have the view selected, the Class drop-down menu will display UIView. We’ll change this in a moment, but let’s take a quick detour first.

02

4. With the view still selected, switch to the Connections Inspector. You can do this by either:

  • Clicking on the Connections Inspector icon (indicated by the number 4 in the screenshot above) in the Inspector Bar at the top of Xcode’s Utilities Area, or
  • Pressing command-option-6 on your keyboard.

5. Take a look at the available connections for the view. You can make a couple of different of kinds of connections, but none of them are for events. We need to make event connections available to the view, which we’ll do in the next few steps.

03

6. Switch back to the Identity Inspector.

7. Make sure that the view is still selected.

8. Change the value in the Class drop-down from UIView to UIControl. This changes the view’s underlying class, as you may have guessed, from UIView to UIControl. We’ll see the effect of this change in a moment…

04

9. With the view still selected, switch to the Connections Inspector.

10. Make a note of the available connections for the view. Since the underlying class for the view is now UIControl, it has UIControl‘s connections available to it, which include events.

We want to dismiss the keyboard as soon as the view gets a Touch Down event. We use this event rather than Touch Up Inside (the one we typically use for buttons) because we want to dismiss the keyboard as soon as the user taps the view without first waiting for him/her to release or move his/her finger.

5

11. Drag from the Touch Down event to the View Controller icon above the view.

12. A list of action methods in the view controller (any method prefaced with @IBAction is an action method) will appear. Select userTappedBackground:.

6

13. If you look at the Identity Inspector now, you’ll see that the Touch Down event is now connected to the view controller’s userTappedBackground method, and when you run the app, tapping on the view dismisses the keyboard.

Bonus: Dismissing the keyboard when you don’t even know which view the text field is in

There may come a time when you need to dismiss the keyboard from code that:

  • doesn’t have a reference to the text field that’s currently the first responder and
  • doesn’t even have a reference to the view that contains that text field.

In such a case, use this line of code:

Here’s what happens in this line:

  • UIApplication.sharedApplication() gets a reference to the instance of the app itself.
  • sendAction(_:to:from:forEvent:) sends an action message to a target object within the app. If the target (the to: parameter) is nil, the message — resignFirstResponder in this case — gets sent to whatever object in the app is currently the first responder.

My guess is that this approach is more computationally heavy that calling a view’s endEditing(_:) method, so use that if you have a reference to the view, and use the approach above when you don’t.

Resources

zip file iconYou can see this code in action by downloading the zipped project files for the demo project, ConstrainedTextFieldDemo [83K Xcode project and associated files, zipped].

{ 1 comment }

ios 8 keyboard

It’s been over two years since I published my visual catalog of iOS’ virtual keyboards on the iPhone, which covered iOS 6. At the time, it was the only place you could get a listing of the names of the iOS keyboards and see what they looked like. Even now, I think it’s still the only information source of its kind.

We’re now well into iOS 8’s run, and it’s likely that iOS 9 will be released sometime this year. Since there still isn’t a visual catalog of iOS 8’s built-in keyboards on the iPhone, and since I’m still of the “see a need, fill a need” ethos, I put one together. It starts with a table listing all the built-in keyboard types; you can click on the name to jump to pictures of all the views for the corresponding keyboard.

I hope you find it useful!

iOS 8’s built-in virtual keyboards

UIKeyboardType Based on Emoji entry? The official description, straight from Apple’s documentation
ASCIICapable Typewriter No Use a keyboard that displays standard ASCII characters.
DecimalPad Phone No Use a keyboard with numbers and a decimal point.
Default Typewriter Yes Use the default keyboard for the current input method.
EmailAddress Typewriter Yes Use a keyboard optimized for specifying email addresses. This type features the “@”, “.” and space characters prominently.
NamePhonePad Typewriter and phone Yes Use a keypad designed for entering a person’s name or phone number. This keyboard type does not support auto-capitalization.
NumberPad Phone No Use a numeric keypad designed for PIN entry. This type features the numbers 0 through 9 prominently. This keyboard type does not support auto-capitalization.
NumbersAndPunctuation Typewriter No Use the numbers and punctuation keyboard.
PhonePad Phone No Use a keypad designed for entering telephone numbers. This type features the numbers 0 through 9 and the “*” and “#” characters prominently. This keyboard type does not support auto-capitalization.
Twitter Typewriter Yes Use a keyboard optimized for twitter text entry, with easy access to the @ and # characters.
URL Typewriter Yes Use a keyboard optimized for URL entry. This type features “.”, “/”, and “.com” prominently.
WebSearch Typewriter Yes Use a keyboard optimized for web search terms and URL entry. This type features the space and “.” characters prominently.

iOS 8 features a total of 11 built-in virtual keyboards, all of which are variations on two basic types: the typewriter keyboard and the phone keypad, both pictured below:

typewriter and phonepad - light

Typically, the keyboard isn’t shown until the user taps on a text field or text view. You can specify the type of keyboard for a text field or text view visually in Interface Builder…

choosing keyboards in interface builder

…or you can do so in code using the text field or text view’s keyboardType property and values from the UIKeyboardType enum:

If you don’t specify a keyboard type for a text field or text view, the typewriter-based Default keyboard is used.

Thanks to their growing popularity (first in Japan, and then the rest of the world), many of these keyboards feature a way to enter emoji, which have been available on iOS since version 5, which was released in mid-2011:

emoji-light

All of iOS’ virtual keyboards come in both a light and dark appearance, with the light version being the default:

typewriter and phonepad - dark

As with the keyboard type, you can choose this appearance either visually in Interface Builder (via the Appearance menu) and in code using the text field or text view’s keyboardAppearance property and values from the UIKeyboardAppearance enum.

I haven’t been able to find anything in the Human Interface Guidelines on when the light and dark keyboards should or shouldn’t be used, so let your common sense be your guide, keeping in mind this fact about common sense:

Click the image to enjoy Deadpool’s wisdom at full size.

UIKeyboardType.ASCIICapable

This used to be the default keyboard; now it’s the “no-nonsense alphanumeric keyboard”. It lets you enter letters, numbers, punctuation, and symbols, and nothing else. Use this keyboard if you need the user to enter something that’s completely or primarily letters and don’t want them to enter emoji and especially for data entry in business, productivity, scientific, health, and other “serious” apps.

Primary view (accessed via the ABC key):

ascii-1-light ascii-1-dark

Alternate view 1 (accessed via the 123 key):

ascii-2-light ascii-2-dark

Alternate view 2 (accessed via the #+= key):

ascii-3-light ascii-3-dark

UIKeyboardType.DecimalPad

Use this keyboard if you want the user to enter either whole or fractional numbers. This keyboard provides the decimal separator appropriate for the user’s locale; the screenshots below show my locale settings, English/US. Note that there’s no return key of any sort on this keyboard.

decimalpad-light decimalpad-dark

UIKeyboardType.Default

If you don’t specify the keyboard type, you get this one, which lets the user enter letters, numbers, punctuation and symbol characters, and emoji. This is the most general-purpose keyboard in iOS.

Primary view (accessed via the ABC key):

default-1-light default-1-dark

Alternate view 1 (accessed via the 123 key):

default-2-light default-2-dark

Alternate view 2 (accessed via the #+= key):

default-3-light default-3-dark

Alternate view 3 (accessed via the the 😀 key):

emoji-light emoji-dark

UIKeyboardType.EmailAddress

If you want the user to provide an email address, this is the preferred keyboard.

Primary view (accessed via the ABC key):

email-1-light email-1-dark

Alternate view 1 (accessed via the 123 key):

email-2-light email-2-dark

Alternate view 2 (accessed via the #+= key):

email-3-light email-3-dark

Alternate view 3 (accessed via the the 😀 key):

emoji-light emoji-dark

UIKeyboardType.NamePhonePad

For fields where you want the user to enter data without punctuation — typically names or integers — use the NamePhonePad keyboard. It features typewriter-style input for entering letters, and phone-style input for entering numbers.

Primary view (accessed via the ABC key):

namephone-1-light namephone-1-dark

Alternate view 1 (accessed via the 123 key):

namephone-2-light namephone-2-dark

Alternate view 2 (accessed via the the 😀 key):

emoji-light emoji-dark

UIKeyboardType.NumberPad

This is amother numeric entry keyboard. It lets the user enter digits, but not the decimal separator.

Note that there’s no return key of any sort on this keyboard.

Primary view:

numberpad-light numberpad-dark

UIKeyboardType.NumbersAndPunctuation

Think of this as the ASCIICapable keyboard, but with an emphasis on numeric entry. Like the ASCIICapable keyboard, it lets you enter letters, numbers, punctuation, and symbols, and nothing else.

Use this keyboard if you need the user to enter something that’s primarily numeric but may also include letters, symbols and punctuation, but not emoji. You’ll find it especially useful for numeric data entry in business, productivity, scientific, health, and other “serious” apps. You should also use this keyboard when you want the user to enter numbers in scientific notation.

Primary view (accessed via the 123 key):

numbersandpunc-1-light numbersandpunc-1-dark

Alternate view 1 (accessed via the ABC key):

numbersandpunc-2-light numbersandpunc-2-dark

Alternate view 2 (accessed via the #+= key):

numbersandpunc-3-light numbersandpunc-3-dark

UIKeyboardType.PhonePad

If you want the user to enter a phone number or a touch-tone sequence, this is the preferred keyboard.

Primary view (accessed via the 123 key):

phonepad-1-light phonepad-1-dark

Alternate view 2 (accessed via the +*# key):

phonepad-2-light phonepad-2-dark

UIKeyboardType.Twitter

If you want the user to enter a tweet, this is the preferred keyboard.

Primary view (accessed via the ABC key):

twitter-1-light twitter-1-dark

Alternate view 1 (accessed via the 123 key):

twitter-2-light twitter-2-dark

Alternate view 2 (accessed via the #+= key):

twitter-3-light twitter-3-dark

Alternate view 3 (accessed via the the 😀 key):

emoji-light emoji-dark

UIKeyboardType.URL

If you want the user to enter a URL, this is the preferred keyboard.

Primary view (accessed via the ABC key):

url-1-light url-1-dark

Alternate view 1 (accessed via the 123 key):

url-2-light url-2-dark

Alternate view 2 (accessed via the #+= key):

url-3-light url-3-dark

Alternate view 3 (accessed via the the 😀 key):

emoji-light emoji-dark

UIKeyboardType.WebSearch

This keyboard is very similar to the Default keyboard, with two notable differences:

  • There’s a . key in the bottom row
  • The return key is blue, and by default is labelled Go.

It’s meant for entering both URLs and web search terms, but it’s equally useful for any kind search or even typed commands.

Primary view (accessed via the ABC key):

websearch-1-light websearch-1-dark

Alternate view 1 (accessed via the 123 key):

websearch-2-light websearch-2-dark

Alternate view 2 (accessed via the #+= key):

websearch-3-light websearch-3-dark

Alternate view 3 (accessed via the the 😀 key):

emoji-light emoji-dark

{ 1 comment }