Wednesday, February 10, 2016

Swift tips: "Formatting optionals in a String" and "Cleaner localization using Swift"

FORMATTING OPTIONALS IN SWIFT STRINGS

Q: How do you format a String with optional (possibly nil) values but in a concise way?

A: Use  \(variable ?? "")

Let's say you have the following Person class.

Note:  This is just an example.  In real code,  you might use CNContact and it's built in formatting functions (that handle localization) but that's not the point of this tip.  It's to show you how to handle any case.

A person has a required first and last name and an optional middle name:

class Person {
  var firstName:String!
  var middleName:String?
  var lastName:String!

  func fullName() -> String {
    return "\(firstName) \(middleName) \(lastName)"
  }

}

APP:

var p = Person()
p.firstName = "Charlotte"
p.middleName = "Ann"
p.lastName = "Smith"

print(p.fullName())

OUTPUT:

Charlotte Optional("Ann") Smith


That's not what we wanted!

So let's say we  force unwrap the optional middleName using !

  func fullName() -> String {
    return "\(firstName) \(middleName!) \(lastName)"
  }

OUTPUT:

Charlotte Ann Smith


The problem is that if her middle name was "nil", the app would crash!


SOLUTION:

  func fullName() -> String {
    return "\(firstName ?? "") \(middleName ?? "") \(lastName ?? "")"
  }

The ?? operator checks if the variable not nil, and uses it.  If it it's nil, it uses the empty string "".



CLEANER LOCALIZATION USING SWIFT

Any developer who has localized/internationalized (i8n) their iOS app will tell you that their code is harder to enter and read because of the localization function names.

e.g.

NSLocalizedString("SUBMIT_BUTTON_TITLE", comment:"The title for the order form submit button.")

Many times, the comment isn't needed but in some cases it can help the translator decided between different contexts/connotations.  Unfortunately, you still have to supply that second argument when it's not needed.

How about if it was just:

i8n("SUBMIT_BUTTON_TITLE", "The title for the order form submit button.") 

or 

i8n("SUBMIT_BUTTON_TITLE")

You can simply your source code by adding these utility functions to your app.  It is NOT a class.  They are global functions.  Just put them in a .swift file by themselves or with other global functions.  e.g.  GlobalFunctions.swift

import Foundation

public func i8n(str:String) -> String {
    return NSLocalizedString(str, comment: "")
}

public func i8n(str:String,_ comment:String) -> String {
    return NSLocalizedString(str, comment: comment)
}