When compiling for Preview, Xcode actually wraps the string literals in your code with a __designTimeString function. If you click on the stethoscope button, you can see something like this
ContentView.swift:33:13: error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
37 | // ] //preview crashes
38 |
39 | let stringArray1 = [__designTimeString("#1663_3", fallback: "a"), __designTimeString("#1663_4", fallback: "b"), __designTimeString("#1663_5", fallback: "c"), __designTimeString("#1663_6", fallback: "d"), __designTimeString("#1663_7", fallback: "e"), __designTimeString("#1663_8", fallback: "f"), __designTimeString("#1663_9", fallback: "g"), __designTimeString("#1663_10", fallback: "h"), __designTimeString("#1663_11", fallback: "i"), __designTimeString("#1663_12", fallback: "j"), __designTimeString("#1663_13", fallback: "k")] //preview does not crash
| `- error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
40 | }
41 | }
From what I understand from this article, these __designTimeXXX wrappers are basically what allows Xcode to update the preview so quickly when you change something in your code, without recompiling everything.
This obviously makes the whole expression more complicated, and type-checking becomes more consuming. Even so, a __designTimeString function on its own is not enough for the compiler to emit an error. You can try declaring your own __designTimeString function to see this:
// this still compiles for non-Previews
struct ContentView: View {
// ...
func modifiedTest() {
let stringArray1 = [
__designTimeString("a", fallback: "a"),
__designTimeString("b", fallback: "b"),
__designTimeString("c", fallback: "c"),
__designTimeString("d", fallback: "d"),
__designTimeString("e", fallback: "e"),
__designTimeString("f", fallback: "f"),
__designTimeString("g", fallback: "g"),
__designTimeString("h", fallback: "h"),
__designTimeString("i", fallback: "i"),
__designTimeString("j", fallback: "j"),
__designTimeString("k", fallback: "k"),
]
}
}
public func __designTimeString<T>(_ key: Swift.String, fallback: T) -> T where T : Swift.ExpressibleByStringLiteral {
fallback
}
In reality, there are three overloads of __designTimeString. Resolving these overloads makes type-checking even more time-consuming, and is what ultimately led to the compiler giving up. Here I have copied them from the .swiftinterface files.
import os
@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *)
@_semantics("constant_evaluable") @_transparent public func __designTimeString(_ key: Swift.String, fallback: os.OSLogMessage) -> os.OSLogMessage {
fallback
}
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public func __designTimeString<T>(_ key: Swift.String, fallback: T) -> T where T : Swift.ExpressibleByStringLiteral {
fallback
}
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public func __designTimeString<T>(_ key: Swift.String, fallback: T) -> T where T : Swift.ExpressibleByExtendedGraphemeClusterLiteral {
fallback
}
If you add these declarations into your code, the modifiedTest function fails to compile, even when you are not compiling for Previews.
A simple way to fix this is to specify the type of the variable explicitly. This makes the compiler do a lot less type inference, and therefore can type-check the expression within the time limit.
let stringArray1: [String] = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
Another way is to declare your own __designTimeString function.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public func __designTimeString<T>(_ key: Swift.String, fallback: T) -> T where T : Swift.ExpressibleByStringLiteral {
// call the original function by qualifying it with "SwiftUI."
SwiftUI.__designTimeString(key, fallback: fallback)
}
Since the generated __designTimeString calls are all unqualified, you can actually have them resolve to your own implementation.
This reduces the amount of work the compiler has to do (and therefore fixes the error), because the compiler prioritises declarations in the current module. It will not try to find the 3 declarations of __designTimeString in SwiftUI, when the __designTimeString you declared in the current module is already applicable.
[String], to the constant will fix the issue.