Categories
Uncategorized

My Marc Andreessen regret and his profile in The New Yorker

marc andreessen in the new yorker

Click the photo to read Marc’s profile in The New Yorker.

My Marc Andreessen regret

I have only a few regrets in my colorful career, and one of them not figuring out a way to turn the time Marc Andreessen reached out to me into something bigger.

In the fall of 2005, when I was just about to get married for the first time, I received an email from a “pmarca” from a domain I’d never heard of before. In the body, some guy claiming to be Marc Andreessen said that he was looking for a developer evangelist for a new company that was still in stealth mode. I initially dismissed it as a prank, but then thought better of it, and soon discovered that yes, it was the Marc Andreessen, and that company turned out to be Ning. A few email back-and-forths turned into a fantastic and fun phone interview with Gina Bianchini (Ning’s co-founder, and now entrepreneur in residence at Andreessen Horowitz) about becoming their North American developer relations guy, which included the possibility of moving to California to help them out with their venture.

A couple of weeks later, the possibility of that job had diminished greatly, as Marc and Gina had to get their burn rate under control. Marc suggested that I could take on the task of writing some example Ning apps, but I had so much going on between my job at Tucows and being newly-married to a wife who’d just moved to town and knew almost nobody. I figured that I didn’t have the bandwidth for the extra work — at least not without compromising the then-current job or the marriage. Those of you who know me know that the Tucows position is several jobs ago, and I’m now married to someone else, and every now and again, I kick myself for not finding a way to stay in the back of Marc’s mind for his later efforts.

Takeaways from Marc’s profile in The New Yorker, Tomorrow’s Advance Man

marc andreessen - vision and hallucination

Found at OnePowerfulWord.com. Click the picture to see the source.

The May 18, 2015 edition of The New Yorker features Tomorrow’s Advance Man, a profile of Marc Andreessen that also provides a look into his venture capitalist firm Andreessen Horowitz, VCs in general, and the money that stokes the machinery of Silicon Valley.

A quick cut/paste/save/wc says that it weighs in at a hefty 13,442 words and 67 minutes’ reading according to Read-O-Meter. Don’t let the tl;dr demon scare you away; it’s a worthwhile read. Spread it out over a couple of lunches or coffee sessions if you need to, because there are some insights that you’ll find useful if you’re the tech industry (as most of this blog’s readers are).

My top takeaways from the article are:

  1. Don’t take it from me, take it from Kevin Kelly: “If you are going to deal with VCs, this profile of Marc Andreessen with fill in the blanks. Long but worth it.”
  2. I knew about Andreessen Horowitz’ short name for itself — a16z — derived from the fact that there are 16 letters between the starting “A” and the closing “z”. It borrows from the term i18n, which shortens the word internationalization in the same manner. What I didn’t know was the short name that A16z’s competitors preferred: AHo, as in “a-hole”.
  3. Want to get media attention? Be noisy on Twitter. Marc tweets more than 100 times a day because “Reporters are obsessed with it. It’s a like a tube and I have loudspeakers installed in every reporting cubicle around the world.” If you’d like to see examples, see A16z’s list of Marc’s top tweetstorms of 2014.
  4. Reading between the lines — a strength that many technically-oriented people lack, and even the most-people savvy forget how to do so in stressful situations — is doubly important when dealing with VCs. They speak euphemistically, often using understatement as a weapon, writes the article’s author, Tad Friend. “You’re definitely going to get funded!” means “But not by us.” “Who else is in?” means “Besides not us.” And “I’m not sure I would ever use your product myself” means “So long!”
  5. Marc grew up far from any major tech center, growing up in Wisconsin in an atmosphere of “antiquity, superstition, frustration, and penury”. Tad Friend writes that his vision of the future came from television, with Star Trek and the decidedly less cerebral (but still inspiring) Knight Rider. Even today, he still seems to get some inspiration from TV, as the references to the TV series Halt and Catch Fire, which Marc and Tad watched together, indicate.
  6. He’s an optimist who thinks big, and in order to get his attention, you’d better be ready to do the same: “We’re not funding Mother Teresa. We’re funding imperial, will-to-power people who want to crush their competition. Companies can only have a big impact on the world if they get big.”
  7. The real problems are never the technical ones. The people issues are always waaaay more complex.
Categories
Uncategorized

Some days, it feels like this…

welcome to my world

…and I think I’m gonna need a bigger shovel.

Adapted from Pete Cheslock’s graphic, which I found I found via Leigh Honeywell.

Categories
Swift Kick

My “How to work with dates and times in Swift” articles (so far)

dates and times in swift

My articles on working with dates and times in Swift have steadily been getting more readers, so I thought I’d gather all the links to them in one place and make them easier to find. I’m also in the process of gathering the content of these articles and pulling them together into a date/time utility module, which I’ll post on GitHub. I’ll let you know when that happens!

In the meantime, my “How to work with dates and times in Swift” articles (so far):

A very brief introduction to date formatting in Swift and iOS: The oversight in a mostly-good book on Swift programming led me down the path of writing articles about dates and times in Swift, starting with this one, where I look at NSDateFormatter.

How to work with dates and times in Swift, part one: An introduction of Cocoa’s date and time classes, and how they work together. This article covers UTC (Coordinated Universal Time), and the key classes: NSDate, NSCalendar, NSDateComponents.

How to work with dates and times in Swift, part two: Calculations with dates: Now that we’ve got the basics, it’s time to do some date arithmetic: comparing two dates to see which one is the earlier and later one, finding out how far apart two dates are, and adding and subtracting from dates.

How to work with dates and times in Swift, part three: Making date arithmetic more Swift-like: Cocoa’s date and time classes have an Objective-C heritage, which in the Swift context, feel kind of clunky. In this article, I look at ways — and by ways, I mean helper functions and class extensions — to make date calculations feel more like Swift.

How to work with dates and times in Swift, part four: A more Swift-like way to get the time interval between two dates: This quick article shows you how to make an operator overload that makes getting the time interval between two dates more like subtraction.

Click the chart to see it at full size.

Categories
Uncategorized

Telecom history lessons: RIP Joseph Lechleider, and HP’s history of telecom in 3 minutes

RIP Joseph Lechleider, who came up with the idea behind ADSL

If you have one of these — often called a “DSL modem”, but it’s more likely to be a DSL router — in your home or office…

dsl modem

…then you have this engineer to thank:

joseph lechleider

This is Joseph Lechleider, who used to be an engineer at Bellcore, Bell Telephone’s research wing formed after it was broken up into the “Baby Bells”. In the late 1980s, he came up with a clever solution to a problem that came with trying to send high-speed electronic signals over ordinary copper wire and into this familiar connection:

rj-11

Electricity and magnetism are bound together in interesting ways, and this connection turns up when you send a current through a wire. The current induces a magnetic field around the wire:

current and magnetic field in a wire

The tight connection between electricity and magnetism means that the reverse is true as well: put a wire into a magnetic field, and you’ll induce a current in it.

This behavior made it difficult to send high-speed signals through copper wires, which to this day often make up the “last mile” between your wireline carrier and you. The magnetic fields induced by sending signals at very high speeds create a lot of interference, which mangles the data being carried, which slows down the rate at which you receive actual usable data.

Lechleider’s solution to this problem was both simple and clever: why not make it so that downloading (getting information from the network to you) was faster than uploading (sending information from you to the network)? This arrangement reduced the interference between the upload and download channels and offered more than twice the bandwidth that transmitting and receiving at the same rate did. His idea got incorporated into what we now know as ADSL (the “A” is for asymmetric), a key part of DSL service

The “receive data much faster than you transmit it” solution is an engineer’s dream: it’s clever, and it’s cheap, because it doesn’t require much change to existing infrastructure. It meant that phone companies didn’t have to spend a lot of money to provide broadband service, and it’s how DSL became popular. As recently as the end of 2012, it was the primary means of access for almost 60% of the world’s wireline broadband subscribers.

Lechleider died at home in Philadelphia on April 18th from cancer of the esophagus. We didn’t want his contribution to telecommunications to go unnoticed.

For your work in changing wireline broadband — as well as the way we live, work, and play — we thank you, Mr. Lechleider.

HP’s history of telecom in just three minutes

telecom history in just 3 minutes

this article also appears in the GSG blog

Categories
Uncategorized

iOS 8’s built-in virtual keyboards on the iPhone: A visual catalog

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:

vowelsOnlyTextField.keyboardType = UIKeyboardType.ASCIICapable
noVowelsTextField.keyboardType = UIKeyboardType.Default
digitsOnlyTextField.keyboardType = UIKeyboardType.NumberPad
numericOnlyTextField.keyboardType = UIKeyboardType.NumbersAndPunctuation
positiveIntegersOnlyTextField.keyboardType = UIKeyboardType.DecimalPad

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

Categories
Programming

How to program an iOS text field that takes only numeric input or specific characters with a maximum length [Updated]

Check out this update (May 24, 2016)!

update

The material in this article is still applicable, but you’ll also want to read a newer one titled A better way to program iOS text fields that have maximum lengths and accept or reject specific characters, which shows you how to make text fields that let you specify the following in Interface Builder or using less code:

  • The maximum number of characters that a text field will accept
  • The only characters that can be entered into a text field
  • The only characters that can’t be entered into a text field

I’m already using that material in a couple of projects, and I think you’ll find it handy, too. Check it out!

 

 

 

And now, the original article…

Constraining text fields

constrained text fields demo app

Click the image to see it at full size.

Update, August 26, 2015: I’ve updated this article so that its code works with Swift 2. It compiles under the latest version of Xcode 7, beta 6.

swift kickA little while back, I published an article that covered constraining text fields so that they accepted only values that evaluated to numeric ones, and limited them to a specified maximum number of characters (don’t bother looking for it; it redirects to this article now). This article expands and improves on it by showing you how to create iOS text fields that:

  • accept only numeric values,
  • accept only characters that appear in a specified string,
  • accept any characters except those that appear in a specified string, and
  • combine any of the features listed above

zip file iconIn order to demonstrate this, I’ve created a quick sample app, ConstrainedTextFieldDemo. You can download it here [90K Xcode project and associated files, zipped]. When you run it, you’ll the screen pictured above. It contains a set of text fields, each one with its own set of constraints:

  1. A text field that accepts only vowel characters (upper- and lowercase), and no more than 6 of them.
  2. A text field that accepts any character except vowels, and no more than 8 of them.
  3. A text field that accepts digits only, and no more than 3 of them.
  4. A text field that accepts only numeric values, as long as they’re 7 characters or fewer in length. Note that this field allows numbers in scientific notation.
  5. A text field that accepts only positive integers up to 5 characters in length.

In this article, I’ll walk you through the app and show you how to create your own constrained text fields in iOS. Better still, I’ll give you the project files so that you can experiment with the app.

Cut to the code (and the storyboard, too)!

Before we get into the explanations, let me cut to the chase and just give you the code.

For the purposes of discussing constrained text fields, we need to consider only two files:

  1. The view controller, ViewController.swift, and
  2. a set of string utility methods contained in StringUtils.swift.

Here’s ViewController.swift:

//
//  ViewController.swift
//

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

  // MARK: Outlets
  
  @IBOutlet weak var vowelsOnlyTextField: UITextField!
  @IBOutlet weak var noVowelsTextField: UITextField!
  @IBOutlet weak var digitsOnlyTextField: UITextField!
  @IBOutlet weak var numericOnlyTextField: UITextField!
  @IBOutlet weak var positiveIntegersOnlyTextField: UITextField!
  
  
  // MARK: View events and related methods
  
  override func viewDidLoad() {
    super.viewDidLoad()
    initializeTextFields()
  }

  // Designate this class as the text fields' delegate
  // and set their keyboards while we're at it.
  func initializeTextFields() {
    vowelsOnlyTextField.delegate = self
    vowelsOnlyTextField.keyboardType = UIKeyboardType.ASCIICapable

    noVowelsTextField.delegate = self
    noVowelsTextField.keyboardType = UIKeyboardType.ASCIICapable
    
    digitsOnlyTextField.delegate = self
    digitsOnlyTextField.keyboardType = UIKeyboardType.NumberPad
    
    numericOnlyTextField.delegate = self
    numericOnlyTextField.keyboardType = UIKeyboardType.NumbersAndPunctuation
    
    positiveIntegersOnlyTextField.delegate = self
    positiveIntegersOnlyTextField.keyboardType = UIKeyboardType.DecimalPad
  }
  
  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }
  
  // Tap outside a text field to dismiss the keyboard
  // ------------------------------------------------
  // By changing the underlying class of the view from UIView to UIControl,
  // the view can respond to events, including Touch Down, which is
  // wired to this method.
  @IBAction func userTappedBackground(sender: AnyObject) {
    view.endEditing(true)
  }
  
  
  // MARK: UITextFieldDelegate events and related methods
  
  func textField(textField: UITextField,
                 shouldChangeCharactersInRange range: NSRange,
                 replacementString string: String)
       -> Bool
  {
    // We ignore any change that doesn't add characters to the text field.
    // These changes are things like character deletions and cuts, as well
    // as moving the insertion point.
    //
    // We still return true to allow the change to take place.
    if string.characters.count == 0 {
      return true
    }
    
    // Check to see if the text field's contents still fit the constraints
    // with the new content added to it.
    // If the contents still fit the constraints, allow the change
    // by returning true; otherwise disallow the change by returning false.
    let currentText = textField.text ?? ""
    let prospectiveText = (currentText as NSString).stringByReplacingCharactersInRange(range, withString: string)
  
    switch textField {
    
      // Allow only upper- and lower-case vowels in this field,
      // and limit its contents to a maximum of 6 characters.
      case vowelsOnlyTextField:
        return prospectiveText.containsOnlyCharactersIn("aeiouAEIOU") &&
               prospectiveText.characters.count <= 6

      // Allow any characters EXCEPT upper- and lower-case vowels in this field,
      // and limit its contents to a maximum of 8 characters.
      case noVowelsTextField:
        return prospectiveText.doesNotContainCharactersIn("aeiouAEIOU") &&
               prospectiveText.characters.count <= 8
        
      // Allow only digits in this field, 
      // and limit its contents to a maximum of 3 characters.
      case digitsOnlyTextField:
        return prospectiveText.containsOnlyCharactersIn("0123456789") &&
               prospectiveText.characters.count <= 3
        
      // Allow only values that evaluate to proper numeric values in this field,
      // and limit its contents to a maximum of 7 characters.
      case numericOnlyTextField:
        return prospectiveText.isNumeric() &&
               prospectiveText.characters.count <= 7
        
      // In this field, allow only values that evalulate to proper numeric values and
      // do not contain the "-" and "e" characters, nor the decimal separator character
      // for the current locale. Limit its contents to a maximum of 5 characters.
      case positiveIntegersOnlyTextField:
        let decimalSeparator = NSLocale.currentLocale().objectForKey(NSLocaleDecimalSeparator) as! String
        return prospectiveText.isNumeric() &&
               prospectiveText.doesNotContainCharactersIn("-e" + decimalSeparator) &&
               prospectiveText.characters.count <= 5
        
      // Do not put constraints on any other text field in this view
      // that uses this class as its delegate.
      default:
        return true
    }
    
  }
  
  // Dismiss the keyboard when the user taps the "Return" key or its equivalent
  // while editing a text field.
  func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true;
  }
  
}

I gave the outlets for the text fields sensible names, but I thought that it might be helpful to show you an annotated storyboard that points out which outlet belongs to which text field:

constrained text fields screenshot

The code in the view controller calls on some string utility methods that I decided to put into their own module: the StringUtils.swift file:

//
//  StringUtils.swift
//

import Foundation

extension String {
  
  // Returns true if the string has at least one character in common with matchCharacters.
  func containsCharactersIn(matchCharacters: String) -> Bool {
    let characterSet = NSCharacterSet(charactersInString: matchCharacters)
    return self.rangeOfCharacterFromSet(characterSet) != nil
  }
  
  // Returns true if the string contains only characters found in matchCharacters.
  func containsOnlyCharactersIn(matchCharacters: String) -> Bool {
    let disallowedCharacterSet = NSCharacterSet(charactersInString: matchCharacters).invertedSet
    return self.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
  }
  
  // Returns true if the string has no characters in common with matchCharacters.
  func doesNotContainCharactersIn(matchCharacters: String) -> Bool {
    let characterSet = NSCharacterSet(charactersInString: matchCharacters)
    return self.rangeOfCharacterFromSet(characterSet) == nil
  }
  
  // Returns true if the string represents a proper numeric value.
  // This method uses the device's current locale setting to determine
  // which decimal separator it will accept.
  func isNumeric() -> Bool
  {
    let scanner = NSScanner(string: self)
    
    // A newly-created scanner has no locale by default.
    // We'll set our scanner's locale to the user's locale
    // so that it recognizes the decimal separator that
    // the user expects (for example, in North America,
    // "." is the decimal separator, while in many parts
    // of Europe, "," is used).
    scanner.locale = NSLocale.currentLocale()
    
    return scanner.scanDecimal(nil) && scanner.atEnd
  }

}

Let’s take a closer look at the code…

The delegate pattern and text fields

The delegate pattern in general

the delegate pattern

The Delegate pattern is a fundamental part of iOS app development. You’ll encounter it often when programming user interfaces, including those times when you want to your program to react to what the user does with text fields.

The delegate pattern involves two categories of object:

  • A delegator, which needs to perform a task, but doesn’t have some needed information, resources, or logic to do so. It gets that needed information, resources, or logic from…
  • A delegate. While it typically can’t do what the delegator does, it has the information, resources, or logic that the delegator needs to perform its task.

My pet analogy for the delegate pattern is pictured above: an airplane and air traffic control. Unlike the driver of a car, who’s controlled only by traffic signals and pretty much free to choose any destination and route s/he pleases, the pilot of a plane has to delegate a lot of those choices to air traffic control. The airplane, which does the actual flying, is the delegator, and air traffic control, which gives clearance for takeoff and landing and tells the plane the heading, speed, and altitude at which it should fly, is the delegate.

The delegate pattern in iOS

If you look at the delegate pattern in Wikipedia, you’ll see that there are a number of ways to implement it. Here’s how it’s done in iOS (and Cocoa), whether you’re doing it in Objective-C or Swift:

delegate pattern in iOS

There are three things in play:

  • The delegator, which keeps a reference to the delegate, which will end up having the task delegated to it,
  • The delegate, which implements the methods and properties used to accomplish the delegated task, and
  • The protocol, which connects the delegator and delegate by:
    • giving the delegator a way to send messages to the delegate, and
    • giving the delegate a way to perform actions on behalf of the delegator.

The delegate pattern with iOS’ text fields

Let’s make the above diagram a little more specific and talk about delegation in terms of iOS’ text fields:

delegation with text fields

iOS text fields — that is, instances of the UITextField class — participate in a delegate pattern as delegators. They’ve got the power to control what happens when the user starts and stops editing their contents and what characters can be typed into them, but they offload the logic that handles those tasks to another object: the delegate.

A specific protocol, the UITextFieldDelegate protocol, connects the text field and its delegate together. A protocol is simply a set of declarations of class members — instance properties, instance methods, type methods, operators, and subscripts. These instance properties, instance methods, type methods, operators, and subscripts are implemented in the delegate (implementing a protocol’s members is called adopting the protocol), and the delegator calls on these implemented members.

The protocol: UITextFieldDelegate

Let’s look at the UITextFieldDelegate protocol. You can actually check it out for yourself; the simplest way is to control-click or right-click on any occurrence of UITextField in your code and then click on Jump to Definition in the contextual menu that appears:

getting to uitextfielddelegate

You’ll be taken to UITextField.h, a header file that allows Swift to connect to the Objective-C code on which UITextField is built. It contains the declarations for all the publicly-accessible parts of UITextField, including the UITextFieldDelegate protocol. You’ll find it near the end of the file. I’ve reproduced it below:

protocol UITextFieldDelegate : NSObjectProtocol {
    
    optional func textFieldShouldBeginEditing(textField: UITextField) -> Bool // return NO to disallow editing.
    optional func textFieldDidBeginEditing(textField: UITextField) // became first responder
    optional func textFieldShouldEndEditing(textField: UITextField) -> Bool // return YES to allow editing to stop and to resign first responder status. NO to disallow the editing session to end
    optional func textFieldDidEndEditing(textField: UITextField) // may be called if forced even if shouldEndEditing returns NO (e.g. view removed from window) or endEditing:YES called
    
    optional func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool // return NO to not change text
    
    optional func textFieldShouldClear(textField: UITextField) -> Bool // called when clear button pressed. return NO to ignore (no notifications)
    optional func textFieldShouldReturn(textField: UITextField) -> Bool // called when 'return' key pressed. return NO to ignore.
}

The delegate: ViewController

In order to become a delegate, a class has to adopt the protocol. If you’re familiar with languages like C# and Java, “adopting a protocol” is similar to “implementing an interface”: we add the protocol to a class’ definition, as if we’re inheriting it. In this case, we’ll have the view controller adopt the protocol:

class ViewController: UIViewController, UITextFieldDelegate {

This says that the ViewController class inherits from the UIViewController class and adopts the UITextFieldDelegate protocol. Having the view controller act as the delegate makes sense: it controls the user interface, and the text fields are part of the user interface.

Just as you have to implement the methods in an inherited interface in C# and Java, you have to implement the methods in an adopted protocol in Swift. There is a difference, however: in Swift, you can choose not to implement methods marked as optional.

You may have noticed that all the methods in the UITextFieldDelegate protocol are optional. This means that a delegate that adopts the protocol can implement as many or as few of its methods as necessary. For the purposes of our app, we’re implementing two of them in ViewController:

  • textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool: The text field calls this whenever the user tries to change the contents of a text field, whether by typing in or deleting a character, or by cutting or pasting. The method should return true if the change is to be accepted, and false to reject the change and keep the contents of the text field the way they are. We’ll use it to limit the types of character that can be entered into the view’s text fields and set a maximum the number of characters that can be entered for each field.
  • textFieldShouldReturn(textField: UITextField) -> Bool: The text field calls this whenever the user taps the Return key or its equivalent on the keyboard. We’ll use it to dismiss the keyboard when the user taps Return.

We’ll talk about the implementation of these methods in the next section. We have to take care of the delegators first.

The delegators: the text fields

We’ve got a protocol, and we’ve got a delegate that adopts it. Now we need to set up the delegators, which in this case, are the text fields — we need to tell them who their delegates are. We do this by setting each text field’s delegate property in the initializeTextFields method of the ViewController class:

  // Designate this class as the text fields' delegate
  // and set their keyboards while we're at it.
  func initializeTextFields() {
    vowelsOnlyTextField.delegate = self
    vowelsOnlyTextField.keyboardType = UIKeyboardType.ASCIICapable

    noVowelsTextField.delegate = self
    noVowelsTextField.keyboardType = UIKeyboardType.ASCIICapable
    
    digitsOnlyTextField.delegate = self
    digitsOnlyTextField.keyboardType = UIKeyboardType.NumberPad
    
    numericOnlyTextField.delegate = self
    numericOnlyTextField.keyboardType = UIKeyboardType.NumbersAndPunctuation
    
    positiveIntegersOnlyTextField.delegate = self
    positiveIntegersOnlyTextField.keyboardType = UIKeyboardType.DecimalPad
  }

By setting all the text fields’ delegate properties to self, we’re saying that this class is their delegate. Any events arising from editing the text fields will be handled by this class.

Constraining the text fields

The magic that constrains a text field so that it’s vowels-only, numbers-only and so on happens inside the protocol method with the very long signature, textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool. This method needs to be coded so that it returns true if we want the user’s changes to be accepted (which then updates the text field), or false if we don’t want the user’s changes to be accepted (which leaves the text field unchanged).

Here’s its code:

  func textField(textField: UITextField,
                 shouldChangeCharactersInRange range: NSRange,
                 replacementString string: String)
       -> Bool
  {
    // We ignore any change that doesn't add characters to the text field.
    // These changes are things like character deletions and cuts, as well
    // as moving the insertion point.
    //
    // We still return true to allow the change to take place.
    if string.characters.count == 0 {
      return true
    }
    
    // Check to see if the text field's contents still fit the constraints
    // with the new content added to it.
    // If the contents still fit the constraints, allow the change
    // by returning true; otherwise disallow the change by returning false.
    let currentText = textField.text ?? ""
    let prospectiveText = (currentText as NSString).stringByReplacingCharactersInRange(range, withString: string)
  
    switch textField {
    
      // Allow only upper- and lower-case vowels in this field,
      // and limit its contents to a maximum of 6 characters.
      case vowelsOnlyTextField:
        return prospectiveText.containsOnlyCharactersIn("aeiouAEIOU") &&
               prospectiveText.characters.count <= 6

      // Allow any characters EXCEPT upper- and lower-case vowels in this field,
      // and limit its contents to a maximum of 8 characters.
      case noVowelsTextField:
        return prospectiveText.doesNotContainCharactersIn("aeiouAEIOU") &&
               prospectiveText.characters.count <= 8
        
      // Allow only digits in this field, 
      // and limit its contents to a maximum of 3 characters.
      case digitsOnlyTextField:
        return prospectiveText.containsOnlyCharactersIn("0123456789") &&
               prospectiveText.characters.count <= 3
        
      // Allow only values that evaluate to proper numeric values in this field,
      // and limit its contents to a maximum of 7 characters.
      case numericOnlyTextField:
        return prospectiveText.isNumeric() &&
               prospectiveText.characters.count <= 7
        
      // In this field, allow only values that evalulate to proper numeric values and
      // do not contain the "-" and "e" characters, nor the decimal separator character
      // for the current locale. Limit its contents to a maximum of 5 characters.
      case positiveIntegersOnlyTextField:
        let decimalSeparator = NSLocale.currentLocale().objectForKey(NSLocaleDecimalSeparator) as! String
        return prospectiveText.isNumeric() &&
               prospectiveText.doesNotContainCharactersIn("-e" + decimalSeparator) &&
               prospectiveText.characters.count <= 5
        
      // Do not put constraints on any other text field in this view
      // that uses this class as its delegate.
      default:
        return true
    }
    
  }

This method takes three parameters:

  • textField: the text field that either had a character added to or removed from it.
  • range: the range of the characters within the text field that are to be replaced.
  • string: the replacement string.

Does the change add characters?

The first thing the method does is see if the change adds characters to the text field:

if string.characters.count == 0 {
  return true
}
  • If the user has typed a character or pasted non-empty text into the text field, string is non-empty and has a length greater than zero. In this case, we’ll want to do more processing.
  • If the user has deleted a character, cut text, or simply moved the insertion point, string is empty and has a length of zero. In this case, we don’t want to do any more processing; removing characters means we don’t have to see if we want to disallow any added character or if the maximum number of characters for the text field has been exceeded. We’ll just exit the method, returning true so that the change still happens, whether it’s a deletion, a cut, or moving the insertion point.

What will the text field look like after the change?

We want to figure out what the text field would contain if the change were allowed. We’ll call that the prospective text, which we’ll assign to a local constant called prospectiveText. We can figure out what the prospective text is by using NSString‘s stringByReplacingCharactersInRange method on the contents of textField.text.

Here’s where we run into a problem:

  • In order to use NSString‘s stringByReplacingCharactersInRange method, we need to convert a Swift String into an NSString.
  • The type of a text field’s text property type isn’t String, but String?. That’s because a text field’s value can either be:
    • a string when it contains at least one character, or
    • nil when it’s empty
  • String can be cast into NSString; String? can’t.

To get around this problem, we’re going to create a String constant called currentText, which we’ll fill as follows:

  • If the text field isn’t empty — that is, if its value isn’t nil — we’ll simply assign currentText the value of textField.text.
  • If the text field is empty — that is, if its value is nil — we’ll assign currenttext the value "", the empty string. There’s a difference between nil (which denotes no value) and the empty string (which is a value, just one that has a length of 0 characters).

Here’s the code:

 let currentText = textField.text ?? ""
 let prospectiveText = (currentText as NSString).stringByReplacingCharactersInRange(range, withString: string)

As we’ll see shortly, having prospectiveText lets us set a maximum number of characters that can be put into a text field.

Taking care of business

Now that we’ve dealt with cases where the change to the text field deletes characters and have created prospectiveText, we can now start constraining text fields. This is handled in the switch statement, which we use to separate the constraining logic for each text field:

switch textField {
    
      // Allow only upper- and lower-case vowels in this field,
      // and limit its contents to a maximum of 6 characters.
      case vowelsOnlyTextField:
        return prospectiveText.containsOnlyCharactersIn("aeiouAEIOU") &&
               prospectiveText.characters.count <= 6

      // Allow any characters EXCEPT upper- and lower-case vowels in this field,
      // and limit its contents to a maximum of 8 characters.
      case noVowelsTextField:
        return prospectiveText.doesNotContainCharactersIn("aeiouAEIOU") &&
               prospectiveText.characters.count <= 8
        
      // Allow only digits in this field, 
      // and limit its contents to a maximum of 3 characters.
      case digitsOnlyTextField:
        return prospectiveText.containsOnlyCharactersIn("0123456789") &&
               prospectiveText.characters.count <= 3
        
      // Allow only values that evaluate to proper numeric values in this field,
      // and limit its contents to a maximum of 7 characters.
      case numericOnlyTextField:
        return prospectiveText.isNumeric() &&
               prospectiveText.characters.count <= 7
        
      // In this field, allow only values that evalulate to proper numeric values and
      // do not contain the "-" and "e" characters, nor the decimal separator character
      // for the current locale. Limit its contents to a maximum of 5 characters.
      case positiveIntegersOnlyTextField:
        let decimalSeparator = NSLocale.currentLocale().objectForKey(NSLocaleDecimalSeparator) as! String
        return prospectiveText.isNumeric() &&
               prospectiveText.doesNotContainCharactersIn("-e" + decimalSeparator) &&
               prospectiveText.characters.count <= 5
        
      // Do not put constraints on any other text field in this view
      // that uses this class as its delegate.
      default:
        return true
    }

The cases for each text field are listed in the order in which they appear onscreen. Let’s look at them one by one:

The “Vowels only” text field

In this text field, we want the user to be able to enter only vowels — the upper- and lower-case versions of the letters a, e, i, o, and u. We also want to limit its contents to a maximum of 6 characters. Here’s the code that does this:

      // Allow only upper- and lower-case vowels in this field,
      // and limit its contents to a maximum of 6 characters.
      case vowelsOnlyTextField:
        return prospectiveText.containsOnlyCharactersIn("aeiouAEIOU") &&
               prospectiveText.characters.count <= 6

This code makes use of the String extension method containsOnlyCharactersIn, which I defined in StringUtils.swift. It returns true if the String contains only characters in the provided parameter.

If both conditions in the return statement evaluate to trueprospectiveText contains only vowels and has 6 characters or fewer — the method returns true, the change to the text field is allowed, and the text field is updated. If both conditions don’t evaluate to true, the method returns false, the change to the text field is not allowed, and the text field’s contents remain the same.

The “Anything BUT vowels” text field

In this text field, we want the user to be able to enter any character except vowels and limit its contents to a maximum of 8 characters. Here’s the code that does this:

      // Allow any characters EXCEPT upper- and lower-case vowels in this field,
      // and limit its contents to a maximum of 8 characters.
      case noVowelsTextField:
        return prospectiveText.doesNotContainCharactersIn("aeiouAEIOU") &&
               prospectiveText.characters.count <= 8

This code is similar to the code for the “Vowels only” text field. The major difference is that it makes use of another String extension method defined in StringUtils.swift: doesNotContainCharactersIn, which returns true if the String doesn’t contain any of the characters in the provided parameter.

The “Digits only” text field

In this text field, we want the user to be able to enter only digits, and no more than three of them at most. Here’s the code that does this:

      // Allow only digits in this field, 
      // and limit its contents to a maximum of 3 characters.
      case digitsOnlyTextField:
        return prospectiveText.containsOnlyCharactersIn("0123456789") &&
               prospectiveText.characters.count <= 3

This code is almost the same as the code for the “Vowels only” text field.

The “Numeric values only” text field

Here’s an interesting one: a text field that accepts only user input that evaluates to a proper numeric value. That means it will accept the following characters:

  • The digits 0 through 9
  • The (negative) symbol
  • The decimal separator, which is either . or , depending on the user’s locale settings
  • The letter e, which is used for numbers specified in scientific notation

Even when limiting the user to these characters, it’s possible for non-numeric values to be entered. Here are a couple of example non-numeric values that we don’t want the user to be able to enter:

  • More than one decimal separator, such as 1.2.3 or 1,2,3, depending on the user’s locale settings
  • The unary minus being placed anywhere other than the start, such as 4-5

We also want to limit the text field to a maximum of 7 characters.

Here’s the code:

      // Allow only values that evaluate to proper numeric values in this field,
      // and limit its contents to a maximum of 7 characters.
      case numericOnlyTextField:
        return prospectiveText.isNumeric() &&
               prospectiveText.characters.count <= 7

This code makes use of the String extension method isNumeric, which I defined in StringUtils.swift. It returns true if the String contains a value that evaluates to a numeric value. It’s powered by NSScanner, a class that’s handy for going through strings and extracting useful data from them, and its scanDecimal method, which returns true if it finds a value that can be evaluated as an NSDecimal value.

If both conditions in the return statement evaluate to trueprospectiveText evaluates to a numeric value and has 7 characters or fewer — the method returns true, the change to the text field is allowed, and the text field is updated. If both conditions don’t evaluate to true, the method returns false, the change to the text field is not allowed, and the text field’s contents remain the same.

The “Positive integers only” text field

This is a more strict version of the “Numeric values only” text field. It requires that anything entered into it needs to evaluate as a proper numeric value, but it also requires that the value be a positive integer and not be stated in scientific notation. It has a maximum length of 5 characters. Here’s the code:

      // In this field, allow only values that evalulate to proper numeric values and
      // do not contain the "-" and "e" characters, nor the decimal separator character
      // for the current locale. Limit its contents to a maximum of 5 characters.
      case positiveIntegersOnlyTextField:
        let decimalSeparator = NSLocale.currentLocale().objectForKey(NSLocaleDecimalSeparator) as! String
        return prospectiveText.isNumeric() &&
               prospectiveText.doesNotContainCharactersIn("-e" + decimalSeparator) &&
               prospectiveText.characters.count <= 5

In order to disallow negative numbers, we use the String extension method doesNotContainCharactersIn to block out characters. We disallow scientific notation by using the same method to block out e characters. The tricky part is disallowing the decimal separator, which can be either . or , depending on the user’s locale. We identify it with NSLocale.currentLocale().objectForKey(NSLocaleDecimalSeparator), which we add to the parameter for doesNotContainCharactersIn.

Any other text fields that might be on the screen

Finally, we handle the default case: any other text fields that might be on the screen, which we won’t constrain:

      default:
        return true

Other UI goodies

This app has a couple of UI features that I’ll cover in a subsequent article:

  • specifying the keyboard for a specific text field,
  • dismissing the keyboard when the user taps the Return key or its equivalent, and
  • dismissing the keyboard when the user taps on the view

It’s all in the code, so if you’d like to jump in and learn how it works on your own, go right ahead!

Resources

zip file iconIn case you missed it, here are the zipped project files for the demo project, ConstrainedTextFieldDemo [90K Xcode project and associated files, zipped].

Categories
Uncategorized

“Research journal, day 12: The locals have accepted me as one of their own.”

fitting in

Found via AcidCow. Click the photo to see the source.