Custom result builder declaration in Swift - Time & Space Complexity
When we create a custom result builder in Swift, it helps us combine multiple pieces of code into one result.
We want to understand how the time it takes to build the result changes as we add more pieces.
Analyze the time complexity of the following code snippet.
@resultBuilder
struct MyBuilder {
static func buildBlock(_ components: String...) -> String {
components.joined(separator: ", ")
}
}
func makeSentence(@MyBuilder content: () -> String) -> String {
content()
}
let sentence = makeSentence {
"Hello"
"world"
"from"
"Swift"
}
print(sentence)
This code defines a simple custom result builder that joins strings together, then uses it to build a sentence.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Joining an array of strings using
joined(separator:). - How many times: The join operation processes each string once, so it runs once over all input strings.
As we add more strings to the builder, the join operation must combine all of them into one string.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Processes 10 strings once |
| 100 | Processes 100 strings once |
| 1000 | Processes 1000 strings once |
Pattern observation: The work grows directly with the number of strings added.
Time Complexity: O(n)
This means the time to build the result grows linearly with the number of components.
[X] Wrong: "The builder runs once per string, so time grows faster than linearly."
[OK] Correct: The builder collects all strings first, then joins them in one step, so it only processes the list once.
Understanding how custom builders combine multiple inputs helps you reason about code efficiency and scalability in real projects.
"What if the builder combined nested arrays of strings instead of a flat list? How would the time complexity change?"
Practice
@resultBuilder in Swift?Solution
Step 1: Understand the role of
A@resultBuilder@resultBuilderis used to customize how multiple code blocks combine into one result, making code cleaner.Step 2: Compare with other options
Options A, B, and D describe unrelated concepts like error handling, data types, and optimization, which are not the purpose of result builders.Final Answer:
To define how multiple code parts combine into a single result -> Option DQuick Check:
Result builder = combine code parts [OK]
- Confusing result builders with classes or structs
- Thinking result builders handle errors
- Assuming result builders optimize memory
Solution
Step 1: Identify correct syntax for result builder
A custom result builder must be declared with@resultBuilderattribute on a struct, and have static methods likebuildBlockreturning a value.Step 2: Check each option
@resultBuilder struct MyBuilder { static func buildBlock() -> String { "" } }correctly uses@resultBuilder, declares a struct, and has a staticbuildBlockmethod returning a String. The other options miss the attribute, use class instead of struct, or have non-staticbuildBlock.Final Answer:
@resultBuilder struct MyBuilder { static func buildBlock() -> String { "" } } -> Option AQuick Check:
Result builder = @resultBuilder + struct + static methods [OK]
- Using class instead of struct for result builder
- Forgetting the @resultBuilder attribute
- Making buildBlock non-static
@resultBuilder
struct IntSumBuilder {
static func buildBlock(_ numbers: Int...) -> Int {
numbers.reduce(0, +)
}
}
func sum(@IntSumBuilder _ content: () -> Int) -> Int {
content()
}
let result = sum {
5
10
3
}
print(result)Solution
Step 1: Understand buildBlock behavior
ThebuildBlockmethod takes multiple Int values and sums them usingreduce(0, +).Step 2: Evaluate the sum call
The closure passed tosumreturns three Int values: 5, 10, and 3. The builder sums them: 5 + 10 + 3 = 18.Final Answer:
18 -> Option BQuick Check:
Sum of 5, 10, 3 = 18 [OK]
- Thinking values concatenate as strings
- Expecting buildBlock to receive an array instead of variadic
- Confusing output with zero or error
@resultBuilder
struct TextBuilder {
func buildBlock(_ components: String...) -> String {
components.joined(separator: ", ")
}
}Solution
Step 1: Check method requirements in result builder
Methods likebuildBlockinside a@resultBuildermust be declared asstaticso they can be called without an instance.Step 2: Analyze the given code
ThebuildBlockmethod is missing thestatickeyword, which causes a compile error.Final Answer:
buildBlock must be static -> Option AQuick Check:
buildBlock method = static [OK]
- Omitting static keyword on buildBlock
- Thinking buildBlock must return Int always
- Believing struct can't be used with @resultBuilder
buildBlock implementations correctly combines multiple (String, Int) tuples into a single dictionary?Solution
Step 1: Understand the goal
The builder should combine multiple key-value pairs into a single dictionary.Step 2: Analyze each option
static func buildBlock(_ pairs: (String, Int)...) -> [String: Int] { Dictionary(uniqueKeysWithValues: pairs) } usesDictionary(uniqueKeysWithValues:)which correctly creates a dictionary from tuples. static func buildBlock(_ pairs: [(String, Int)]) -> [String: Int] { pairs.reduce([:]) { $0 + $1 } } tries to reduce with + which is invalid for dictionaries. static func buildBlock(_ pairs: (String, Int)...) -> [String: Int] { pairs.map { [$0.0: $0.1] } } maps to an array of dictionaries, not a single dictionary. static func buildBlock(_ pairs: (String, Int)...) -> [(String, Int)] { pairs } returns an array of tuples, not a dictionary.Final Answer:
static func buildBlock(_ pairs: (String, Int)...) -> [String: Int] { Dictionary(uniqueKeysWithValues: pairs) } -> Option CQuick Check:
Use Dictionary(uniqueKeysWithValues:) to combine tuples [OK]
- Returning array of dictionaries instead of one dictionary
- Using invalid + operator to combine dictionaries
- Returning array of tuples instead of dictionary
Ready to prove it?
Pass the test and this pattern moves unknown
