This sample shows one use of using @isolated(any) with non-async functions and closures.
struct ValidationHelper {
// Non-async function that preserves caller's isolation
static func validateAndUpdate<T>(
_ value: T,
validator: (T) -> Bool,
onValid: @isolated(any) () -> Void,
onInvalid: @isolated(any) () -> Void
) {
if validator(value) {
onValid()
} else {
onInvalid()
}
}
}
struct LoginForm: View {
@State private var email = ""
@State private var isEmailValid = false
@State private var showError = false
var body: some View {
VStack {
TextField("Email", text: $email)
.onChange(of: email) { _, newEmail in
ValidationHelper.validateAndUpdate(
newEmail,
validator: { $0.contains("@") },
onValid: {
// Synchronous closure on MainActor
isEmailValid = true
showError = false
},
onInvalid: {
// Synchronous closure on MainActor
isEmailValid = false
showError = true
}
)
}
if showError {
Text("Invalid email").foregroundColor(.red)
}
}
}
}
extension Array {
// Non-async function with isolated closure parameter
func forEachWithIndex(_ action: @isolated(any) (Int, Element) -> Void) {
for (index, element) in self.enumerated() {
action(index, element)
}
}
func conditionalForEach(
where predicate: (Element) -> Bool,
perform action: @isolated(any) (Element) -> Void
) {
for element in self {
if predicate(element) {
action(element)
}
}
}
}
struct TodoListView: View {
@State private var todos = ["Buy milk", "Walk dog", "Write code"]
@State private var completedCount = 0
@State private var urgentTodos: [String] = []
var body: some View {
VStack {
Text("Completed: \(completedCount)")
List {
ForEach(todos.indices, id: \.self) { index in
Text(todos[index])
}
}
Button("Process Todos") {
todos.forEachWithIndex { index, todo in
// Synchronous closure on MainActor
if todo.contains("!") {
urgentTodos.append("Priority: \(todo)")
}
}
todos.conditionalForEach(
where: { $0.count > 5 },
perform: { _ in
// Synchronous closure on MainActor
completedCount += 1
}
)
}
}
}
}