Strings and Characters in Swift

A Swift string is a series of characters. String is its own type in Swift, not simply an array of characters as it is in C. Further, strings may contain or be composed entirely of Unicode characters, so the length of each character may vary.

Swift string literals are enclosed in double quotes:
“Hello, Frog!
and of course, we can assign a string literal as the value of either a constant or a variable:
let frogSpeech = “ribbit” var frogColor = “green”
The mutability of a string is governed by how it’s defined: if it’s defined with var, it’s mutable; let– defined strings (being constants), are immutable.

Of course, we can use an annotation to declare a String type as well:
let frogIntro1 : String var frogIntro2 : String
The + operator is overloaded to concatenate strings:
frogIntro1 = “Frogs say ” + frogSpeech + ” and are typically ” + frogColor + “.”
will create the string “Frogs say ribbit and are typically green.” There are other types we want to include in the string, we can cast them to the String type (using the String() constructor), for example, the Int 42 is cast as a String before being added in here:
print(“There are ” + String(42) + ” frogs on this lily pad.”)
Swift strings can also interpolate a value of any type: the cast will be performed in place. For example,

if we’ve defined:

var numFrogs = 9

var costOfEachFrog = 3.42

Then the following are all valid strings:

"There are \(numFrogs) on this lily pad."

"Each frog costs $\(costOfEachFrog)."

"The total cost of the frogs on this lily pad is \(Double(numFrogs) * costOfEachFrog)."

Whatever is between the \( and ) is interpolated into the string; this can be either a single variable or constant, or an expression, as in the third string above.

Strings are composed of values of type Character. Each of the characters in a string is a Unicode Scalar value. Unicode is a complex topic; if you want to dive into the specifics of code points and so forth, see the Unicode Standard documentation at For our purposes here, just be aware that the characters in a string may be any character from the Unicode code pointcharacter set, as long as it is in the range U+0000 to U-D7FF or U+E000 to U+10FFFF. This is all simple code points; the surrogate pair code points in the range U+D800 to U+DFFF are not Unicode Scalar values, so they are not eligible to be included in Swift strings (or used as single Swift characters.)

OK, that’s pretty technical. But what does it mean? Well, it means that we can use any character we can get to from the Edit | Emoji & Symbols menu in a String or as a Character type. Simple as that. I can have a string that looks like this:

"Once upon a time there was a frog: [Shally, put an emoji frog here]

This uses the character [Shally, put an emoji frog here] using

the \u{s} syntax, where s is a hexadecimal code point number:

"Once upon a time there was a \u{1F438}"

If we need a single character, we can use the Character data type. Of course, this can be any character from the Unicode scalar set, so all these declarations are valid:

var letter : Character

letter = "A"

let frog : Character = "\u{1F438}" var pi : Character = "π"

// declares letter to be a Character type

// assigns the character “A” to letter

// declares frog and assigns the character to it

// declares pi, annotated as a Character, and assigns // π

The Character type is very selective: characters are single character strings. Because a single character string will be initialized as a String type by default, the :Character annotation must always be provided for Character types (as in the declarations above). It’s also impossible to create an “empty character,” because (again) a Character type must contain a single character!

These declarations are therefore wrong:

var emptyChar : Character = "" let negative : Character = "NO"

In each case, the error given is “Cannot convert value of type ‘String’ to specified type ‘Character’. “” and “NO” are strings, but they cannot be Character types, because neither contains exactly one character.

Because Character types may be one or more bytes long, indexing into strings must be handled differently in Swift than it is in C (where char types are always one byte in length). We can get a collection of all the characters in a string using the string’s .character method, then use a for-in loop to iterate through it like this:

let chars = "Hello!".characters for char in chars {

print(char) }

We’ll talk about the for-in loop when we get to loops, a bit later, but all we’re doing here is printing out each Character in the string “Hello!” (you can see the result in the playground by showing the debug area, by clicking the button in the lower left of the playground interface:

But what if we wanted the fourth character of this string? To do that, we need to understand how String types are indexed.

Every string has an associated index type called String.Index, which gives all indices in the string. The index of the first character in a string given by .startIndex, .endIndex is the index after the last character in the string. We can also get the count of the characters in a string using the .count property of the .characters collection:




// prints “5\n” ,  “0\n” , and “6\n”

We can think of these indices as “anchors” within the string. They anchor us to the first character and to just beyond the last character in the string. For example:
let firstLetter = frogSpeech[frogSpeech.startIndex]
assigns “r” to firstLetter (given that frogSpeech is “ribbit.”) This syntax looks like C type array indexing, and it is very similar (it is, indeed, array indexing, but we cannot index into a string using integers!) This, for example, doesn’t work:
let thirdLettter = frogSpeech[2]
What we can do is start either at the .startIndex or .endIndex and work our way forward or back

through the string. This is done using the .successor() and .predecessor() methods of the .Index, like so:

let secondLetter = frogSpeech[frogSpeech.startIndex.successor()] let lastLetter = frogSpeech[frogSpeech.endIndex.predecessor()]

We could also use looping techniques to index to any character we want in the string. Yay!

Yes, this is clunky. It’s inconvenient. It would be so much better if we could say something like frogSpeech[2] to get the third letter in the string. But remember that unlike C, we’re not dealing with nice neat one-byte characters here. The length of each character in a String type is unknown without getting the .characters collection, and then, it’s only known internally.

Fortunately, we do have another method that can get us quickly to any character in a string: .advancedBy(). We use .advancedBy() in conjunction with .startIndex:

let thirdLetter = frogSpeech[frogSpeech.startIndex.advancedBy(2)]
It's also possible to “advance by” a negative number using the .endIndex as a starting point:
let penultimateLetter = frogSpeech[frogSpeech.endIndex.advancedBy(-2)]

There are many methods of the String type that we’ll use throughout the book. Swift’s String type is also bridged with the NSString type of Objective-C, so we can also use those methods. How to handle this will be covered in the interoperability section of this book.

Before we leave Strings, I want to show you an example of the use of optionals in Swift code (and why they’re so important). The constructors for Swift numeric types can take a String parameter. This form of the constructor returns an optional:

let nine = Int("9") // Optional(9)

let π = Double("3.14159") // Optional(3.14159)

The reason this is an optional is that if the string cannot be evaluated as a number of the type specified, the return value is nil. By the way, we can also use special characters in code. Cool, Huh?
let eight = Int(“eight”) // nil
Since nil is not an Int (or anything else…), the return value is of type Int?. In this way, non-convertible strings can be handled without crashing the application. To get the actual value, we must unwrap the optional, first making sure that it’s not nil:

if let numericValue = eight {


} else {

print("not a number")


Since eight is nil, this will print “not an number\n,” but if we assign nine to numericValue in the first line, it will print “9\n,” because numericValue is an implicitly unwrapped optional (due to the if-let).

Leave a Comment: