Swift
Optional Array
Empty Array
Swift Programming
iOS Development

Optional array vs. empty array in Swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Swift, nil and [] are different states, even though both can mean "there is nothing to iterate right now." nil means the array itself is absent, while an empty array means the value exists and contains zero elements, and that difference becomes important in API design, JSON decoding, and UI state handling.

Understand the Semantic Difference

Use an optional array when absence carries meaning. Use a non-optional array when callers should always receive a collection, even if it is empty.

swift
1var serverTags: [String]? = nil
2
3if serverTags == nil {
4    print("field missing")
5}
6
7serverTags = []
8if serverTags?.isEmpty == true {
9    print("field present but empty")
10}

This distinction matters in patch-style APIs. If a request omits a field, the server may interpret that as "leave the current value alone." If the request sends an empty array, the server may interpret that as "clear all items."

Design Public APIs for the Most Common Caller

Read-oriented APIs usually work best with non-optional arrays because callers can iterate without unwrapping.

swift
struct UserViewModel {
    let roles: [String]
}

Write-oriented or partial-update models often benefit from optional arrays because you need to preserve omission as a separate state.

swift
struct UpdateUserRequest {
    let roles: [String]?
}

That rule keeps read paths convenient and write paths expressive.

Normalize at Boundaries

A useful pattern is to preserve optionality at the network or persistence boundary, then normalize to a concrete array when building UI models.

swift
1struct APIUser {
2    let hobbies: [String]?
3}
4
5struct UserCellModel {
6    let hobbies: [String]
7
8    init(apiUser: APIUser) {
9        self.hobbies = apiUser.hobbies ?? []
10    }
11}

This keeps optional logic near the edge of the system instead of scattering if let checks throughout the view layer.

Codable Makes the Difference Visible

Serialization exposes the semantic difference immediately. An optional array can be missing or null, while a non-optional empty array encodes as an empty list.

swift
1import Foundation
2
3struct Payload: Codable {
4    let optionalItems: [Int]?
5    let items: [Int]
6}
7
8let value = Payload(optionalItems: nil, items: [])
9let encoder = JSONEncoder()
10encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
11
12let data = try encoder.encode(value)
13print(String(data: data, encoding: .utf8)!)

If your backend contract distinguishes omitted fields from explicit empty lists, converting everything to [] too early will lose information you may need later.

Test the Missing, Empty, and Non-Empty States

When the distinction matters, write tests for all three states explicitly.

swift
1func describe(_ items: [Int]?) -> String {
2    guard let items = items else { return "missing" }
3    return items.isEmpty ? "empty" : "has-values"
4}
5
6print(describe(nil))
7print(describe([]))
8print(describe([1, 2, 3]))

That makes future refactors safer because a helper that quietly replaces nil with [] will be caught by tests instead of slipping into production behavior.

Common Pitfalls

  • Treating nil and [] as interchangeable when the business rules clearly distinguish omission from explicit empty input.
  • Returning optional arrays from read-only APIs where callers always need something iterable.
  • Normalizing to [] too early and losing important patch or decoding semantics.
  • Forgetting that JSON contracts may treat omitted fields, null, and empty arrays differently.
  • Force-unwrapping optional arrays in UI code instead of normalizing them once at a boundary.

Summary

  • In Swift, nil means the array is absent and [] means it exists but has no elements.
  • Prefer non-optional arrays for read APIs and optional arrays for partial-update semantics.
  • Preserve optionality at boundaries, then normalize when you build consumer-friendly models.
  • Use Codable behavior to guide how you model missing versus empty values.
  • Test missing, empty, and populated states separately when the distinction matters.

Course illustration
Course illustration

All Rights Reserved.