RealmSwift
Swift Programming
Data Conversion
iOS Development
Swift Arrays

RealmSwift Convert Results to Swift Array

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Realm queries return Results<T>, a lazy, auto-updating collection that reflects live database state. To convert Results<T> to a Swift Array, use Array(results). This creates a snapshot of the data at that point in time, giving you a standard Swift array with full access to methods like map, filter, sorted, and subscript operations. The tradeoff is that arrays are static copies — they do not auto-update when the database changes, and they load all objects into memory immediately rather than using Realm's lazy loading.

Why Convert Results to Array?

Results<T> is lazy and live — it does not load objects until accessed and auto-updates when the Realm changes. This is efficient but comes with restrictions:

swift
1import RealmSwift
2
3class Task: Object {
4    @Persisted var title: String = ""
5    @Persisted var isCompleted: Bool = false
6    @Persisted var priority: Int = 0
7    @Persisted var createdAt: Date = Date()
8}
9
10let realm = try! Realm()
11let results: Results<Task> = realm.objects(Task.self)
12
13// Results is lazy and auto-updating
14print(results.count)  // Queries the database
15// If another thread adds a task, count changes on next access

Reasons to convert to an Array:

  • Use Swift collection methods not available on Results (e.g., enumerated(), custom sorting closures)
  • Pass data to APIs that require Array
  • Capture a snapshot that does not change
  • Use outside a Realm notification block

Basic Conversion

swift
1let realm = try! Realm()
2
3// Query
4let results: Results<Task> = realm.objects(Task.self)
5    .filter("isCompleted == false")
6    .sorted(byKeyPath: "priority", ascending: false)
7
8// Convert to Array
9let tasksArray: [Task] = Array(results)
10
11// Now you have a standard Swift Array
12print(tasksArray.count)
13print(tasksArray.first?.title ?? "No tasks")
14
15// Array methods work normally
16let titles = tasksArray.map { $0.title }
17let highPriority = tasksArray.filter { $0.priority > 5 }
18let indexed = tasksArray.enumerated().map { ($0.offset, $0.element.title) }

Filtering and Mapping

swift
1let realm = try! Realm()
2let allTasks = realm.objects(Task.self)
3
4// Filter with Realm's query engine (faster, uses indexes)
5let realmFiltered = allTasks.filter("priority > 3")
6let filteredArray = Array(realmFiltered)
7
8// Or convert first, then filter with Swift (more flexible)
9let allArray = Array(allTasks)
10let swiftFiltered = allArray.filter { $0.priority > 3 && $0.title.contains("Bug") }
11
12// Map to different type
13let taskSummaries: [(String, Bool)] = Array(allTasks).map { ($0.title, $0.isCompleted) }
14
15// Reduce
16let totalPriority = Array(allTasks).reduce(0) { $0 + $1.priority }
17
18// Compact map
19let completedTitles: [String] = Array(allTasks).compactMap {
20    $0.isCompleted ? $0.title : nil
21}

Performance: Realm Filter vs Swift Filter

swift
1// PREFERRED — Realm filters use database indexes
2let fast = Array(realm.objects(Task.self).filter("priority > 5"))
3
4// SLOWER — loads ALL objects, then filters in memory
5let slow = Array(realm.objects(Task.self)).filter { $0.priority > 5 }

Always apply Realm's .filter() before converting to an Array to minimize the number of objects loaded into memory.

Sorting

swift
1let realm = try! Realm()
2let tasks = realm.objects(Task.self)
3
4// Sort with Realm (uses database-level sorting)
5let realmSorted = Array(tasks.sorted(byKeyPath: "createdAt", ascending: false))
6
7// Sort after conversion (more flexible sort options)
8let swiftSorted = Array(tasks).sorted { a, b in
9    if a.priority == b.priority {
10        return a.createdAt > b.createdAt
11    }
12    return a.priority > b.priority
13}
14
15// Multiple sort descriptors in Realm
16let multiSorted = Array(tasks.sorted(by: [
17    SortDescriptor(keyPath: "isCompleted", ascending: true),
18    SortDescriptor(keyPath: "priority", ascending: false)
19]))

Thread-Safe Conversion with freeze()

Realm objects are thread-confined by default. Use freeze() to create thread-safe copies:

swift
1let realm = try! Realm()
2let results = realm.objects(Task.self).filter("isCompleted == false")
3
4// Freeze creates thread-safe, immutable copies
5let frozenResults = results.freeze()
6let frozenArray = Array(frozenResults)
7
8// Safe to pass to another thread
9DispatchQueue.global().async {
10    for task in frozenArray {
11        print(task.title)  // Works — frozen objects are thread-safe
12    }
13}

Without freeze() (Causes Crash)

swift
1let tasks = Array(realm.objects(Task.self))
2
3DispatchQueue.global().async {
4    // CRASH: "Realm accessed from incorrect thread"
5    print(tasks.first?.title ?? "")
6}

Using with SwiftUI

swift
1import SwiftUI
2import RealmSwift
3
4struct TaskListView: View {
5    @ObservedResults(Task.self, filter: NSPredicate(format: "isCompleted == false"),
6                     sortDescriptor: SortDescriptor(keyPath: "priority", ascending: false))
7    var tasks
8
9    var body: some View {
10        List {
11            // @ObservedResults provides Results<Task> directly
12            ForEach(tasks) { task in
13                Text(task.title)
14            }
15        }
16    }
17
18    // When you need an Array (e.g., for a chart library)
19    var taskData: [Task] {
20        Array(tasks)
21    }
22}

Struct Mapping (Detached from Realm)

For fully detached data, map Realm objects to plain structs:

swift
1struct TaskDTO {
2    let title: String
3    let isCompleted: Bool
4    let priority: Int
5}
6
7extension Task {
8    func toDTO() -> TaskDTO {
9        TaskDTO(title: title, isCompleted: isCompleted, priority: priority)
10    }
11}
12
13let realm = try! Realm()
14let dtos: [TaskDTO] = Array(realm.objects(Task.self)).map { $0.toDTO() }
15// dtos are plain structs — no Realm dependency, thread-safe, Codable-ready

Common Pitfalls

  • Converting large Results to Array unnecessarily: Array(results) loads every object into memory. For a table with 100,000 rows, this consumes significant memory. Use Realm's lazy Results directly when possible, converting only the subset you need.
  • Accessing Realm objects on the wrong thread without freeze(): Realm objects are thread-confined. Converting to an Array does not make the objects thread-safe — the array elements are still Realm objects. Use .freeze() before passing to another thread, or map to plain structs.
  • Filtering in Swift instead of Realm: Array(allResults).filter { ... } loads every object into memory before filtering. Use results.filter("predicate") to filter at the database level first, then convert the smaller result set to an array.
  • Expecting the array to auto-update: Unlike Results, a Swift Array is a static snapshot. Changes to the Realm database are not reflected in the array. If you need live updates, use Results with Realm's notification system or SwiftUI's @ObservedResults.
  • Modifying Realm objects from an array outside a write transaction: Objects in the array are still managed by Realm. Changing a property like task.title = "new" requires a write transaction (realm.write { task.title = "new" }). Without it, Realm throws an exception.

Summary

  • Use Array(results) to convert Realm Results<T> to a Swift [T] array
  • Apply Realm's .filter() and .sorted() before converting to minimize memory usage
  • Use .freeze() to create thread-safe copies that can be passed across threads
  • Map to plain structs with .map { $0.toDTO() } for fully detached, Codable-ready data
  • Prefer keeping data as Results<T> when possible — it is lazy, auto-updating, and memory-efficient

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.