Skip to content
Lesson 4 of 15

Step 1 of 5 · Reading · ~3 min

Learn

Strings and Optionals

Strings

A Swift String is a sequence of characters a human would recognise as characters — not bytes, not UTF-16 code units. That one decision explains almost everything else about the type.

let s = "hello, world"

print(s.count)
print(s.uppercased())
print(s.contains("world"))
print(s.hasPrefix("hell"))
print(String(s.reversed()))

//> 12
//> HELLO, WORLD
//> true
//> true
//> dlrow ,olleh

Interpolation: putting values into text

Write a backslash, then the expression in parentheses:

let name = "Alice"
let age = 30
print("\(name) is \(age) years old")
print("Next year: \(age + 1)")

//> Alice is 30 years old
//> Next year: 31

Any expression works inside the parentheses — arithmetic, method calls, whatever produces a value. This is how you will build essentially every line of output in this course. There is no + needed and no format specifier to remember.

Why count is not free

Because a Character is a whole grapheme cluster, count has to walk the string to work out where each cluster ends. Two strings that look identical can be built from different numbers of underlying scalars and still agree:

print("café".count)
print("cafe\u{301}".count)

//> 4
//> 4

The second string is c, a, f, e, then a combining acute accent — five scalars, four characters. Swift reports what you see. The price is that count is O(n): it is a walk, not a stored length. Calling .count inside a loop over the same string is a real performance bug.

You cannot index a string with an integer

This is the trap that catches everyone arriving from Python or Java.

Does not compile

let s = "hello"
let first = s[0]

Works

let s = "hello"
print(String(describing: s.first))
print(Array(s)[0])
print(s.prefix(2))

//> Optional("h")
//> h
//> he

first returns a Character? because the string might be empty — that is why the first line prints Optional("h") rather than h. Array(s) builds a real array of characters you can index normally, and prefix(2) hands back the leading two.

Because characters occupy different amounts of memory, position 3 is not at a fixed offset — so Swift refuses integer subscripts entirely rather than making them secretly O(n). For exercises, Array(s) or .first / .prefix are almost always enough.

Splitting

split cuts a string on a separator and, by default, throws away empty pieces:

let line = "a,b,,c"
print(line.split(separator: ","))
print(line.split(separator: ",").count)
print(line.split(separator: ",", omittingEmptySubsequences: false).count)

//> ["a", "b", "c"]
//> 3
//> 4

Note what you got back: Substring values, not String. A Substring shares storage with its parent, which is fast but keeps the whole original string alive. Convert with String($0) when you intend to hold on to a piece — and note that Int("42") accepts a Substring directly, so parsing numbers out of a split line needs no conversion at all.

Multi-line strings

Three double quotes open and close a multi-line literal. Indentation is measured relative to the closing delimiter:

let note = """
    first line
    second line
    """
print(note)

//> first line
//> second line

The four leading spaces vanish because the closing """ sits at the same indentation. Indent a line further than the delimiter and those extra spaces are kept.

Strings are values, not references

Assigning a string copies it. There is no shared mutable buffer to accidentally alias:

var a = "hello"
var b = a
b += " world"
print(a)
print(b)

//> hello
//> hello world

Swift only performs the physical copy when one of the two is actually mutated — so this costs nothing in the common case where you never mutate.

Your exercise

Read a name and an age and print one interpolated sentence.

The mistake the grader catches is punctuation drift. The required line is Hi, Alice! You are 25 years old. — comma after Hi, exclamation mark after the name, full stop at the end. Dropping the final full stop, writing Hi Alice! without the comma, or using You're all produce output that looks right to you and fails the character-for-character comparison. Build it with interpolation: print("Hi, \(name)! You are \(age) years old.").

Up nextOptionalsStrings and Optionals

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…