I'm having trouble working out how to access an actor from a filter closure. Take this example code:
import Foundation
actor MyActor {
var contents: [String]
init() {
self.contents = []
}
}
let myActor = MyActor()
let list: [String] = []
Task {
list.filter { item in myActor.contents.contains { $0 == item } }
}
I get the syntax error: Actor-isolated property 'contents' can not be referenced from a non-isolated context
. Which makes sense, but I just cannot work out how to provide the correct syntax.
CodePudding user response:
Put the actor's contents in a local let
constant first, then use that local constant in filter
:
Task {
let actorContents = await myActor.contents
let result = list.filter { item in actorContents.contains { $0 == item } }
}
You wouldn't want filter
to use the updated myActor.contents
halfway through, if myActor.contents
changes at some point during the filtering, right? Therefore, make a local copy of it first, and use that.
Also, consider using a Set
for better efficiency:
let actorContents = Set(await myActor.contents)
let result = list.filter { item in actorContents.contains(item) }
CodePudding user response:
Another approach is to move the filtering routine into the actor:
actor MyActor {
var contents: Set<String> = []
func filtering(_ items: [String]) -> [String] {
items.filter { contents.contains($0) }
}
}
Then, that simplifies the call point:
func foo() {
Task {
let filtered = await myActor.filtering(list)
}
}
This moves the synchronization logic to the actor (where it belongs, IMHO).