Actor isolation
Actor์ isolation์ actor type์ ๊ทผ๋ณธ์ ์ธ ๋์์ด๋ค. Swift language model์์ ์ด๋ป๊ฒ Actor๊ฐ actor ๋ฐ๊นฅ์ชฝ์์ ๋ค์ด์ค๋ ๋น๋๊ธฐ interaction์ ๋ํด ๊ณ ๋ฆฝ์ ๋ณด์ฅํ๋์ง ์๋ํด ์์๋ณด์. ์ฌ๊ธฐ์ ๊ณ ๋ฆฝ์ ์์์ ๋งํ ์ฌ๋ฌ ๋น๋๊ธฐ Task์์ actor์ ํจ์๋ฅผ ํธ์ถํ๋๋ผ๋ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌ๋๋ ๊ฒ์ ๋งํ๋ค.
Protocol
๋ค๋ฅธ ํ์ ๋ค๊ณผ ๋ง์ฐฌ๊ฐ์ง๊ณ actor๋ protocol์ ์ฑํํ ์ ์๋ค.
actor LibraryAccount {
let idNumber: int
var booksOnLoan: [Book] = []
}
extension LibraryAccount: Equatable {
static func ==(lhs: LibraryAccount, rhs: LibraryAccount) -> Bool {
lhs.idNumber == rhs.idNumber
}
}
Equatable protocol์ ์ฑํํ๊ณ , static function์ ๊ตฌํํ๋ค. static function์ด๊ธฐ ๋๋ฌธ์ ๋ด๋ถ์์๋ actor์์ ์ ์๋ instance๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค. ๊ทธ ๋์ ์ ์ธ์๋ก actor type์ ๋ฐ๋๋ค. ๊ทธ๋ฆฌ๊ณ idNumber
์ ์ ๊ทผํ์ง๋ง, ๋ณ ๋ฌธ์ ๋ ์๋ค. immutable state์ด๊ธฐ ๋๋ฌธ์ด๋ค.
actor LibraryAccount {
let idNumber: int
var booksOnLoan: [Book] = []
}
extension LibraryAccount: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(idNumber) // โ actor-isolated method 'hash(into:)' cannot satisfy synchronous requirement
}
}
๊ทธ๋ ๋ค๋ฉด ์ด๋ฒ์๋ Hashable protocol์ ์ฑํํด๋ณด์. ๊ทธ๋ฐ๋ฐ ์ด๋ฒ์๋ compiler๊ฐ ์๋ฌ๋ฅผ ๋ฟ๋๋ค. ์ด๊ฒ ๋ญ๊น?
์ผ๋จ ์์ ๊ฐ์ ๋ฐฉ์์ผ๋ก Hashable์ ์ฑํํ๋ฉด, ์ด๋ ๋ถ๋ช ๋ฐ๊นฅ์์ ํธ์ถ์ด ๊ฐ๋ฅํด์ง๋ค. ๊ทผ๋ฐ, actor์์ ์ ์๋ ํจ์๋ ์๋ฌต์ ์ผ๋ก multi thread์์ ํธ์ถ๋ ์ ์๊ธฐ ๋๋ฌธ์, ์ด๋ฅผ asyncํ๊ฒ ๋ง๋ค์ด์ฃผ์ด์ผ actor๋ฅผ isolation ํ ์ ์๋ค. ๊ทธ๋ฌ๋ฉด actor๋ ๋ด๋ถ์ ์ ์๋ ํจ์์ ๋ํด synchronousํ๊ฒ ๋์ํ๊ธฐ ๋๋ฌธ์ ๋ฌธ์ ๊ฐ ์๋ค. ํ์ง๋ง Protocol์ ์ฑํํ๊ธฐ ๋๋ฌธ์, asyncํ๊ฒ ๋ง๋ค ๋ฐฉ๋๊ฐ ์๋ค. ์ฆ, isolation์ด ๋ถ๊ฐ๋ฅํด์ง๋ค.
extension LibraryAccount: Hashable {
nonisolated func hash(into hasher: inout Hasher) {
hasher.combine(idNumber)
}
}
์ด๋ฐ ๊ฒฝ์ฐ non-isolationํ๊ฒ ๋ง๋ค๋ฉด ๋๋ค. ์ฌ์ค ์ด ํจ์๋ ๊ทธ๋ฐ ์ฒ๋ฆฌ๋ฅผ ํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค. isolation์ ์ค์ multi thread์์ ํธ์ถํ์ฌ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ์ ์ฒ๋ฆฌํด์ฃผ๋ฉด ์ข์ ๊ฒ์ด๋ค. ์ด์ ๊ฐ์ด ์ฌ์ฉํ ์ผ์ด ์๋ ๊ฒฝ์ฐ๋ ๊ณ ๋ฆฝ์ํฌ ํ์๊ฐ ์๋ค.
โ๊ทธ๋ฌ๋ฉด, non-isolated function์์ mutable state๋ฅผ ๋ณ๊ฒฝํ๋ฉด ๋์์ฑ ๋ฌธ์ ๋ฐ์ํ๋ ๊ฒ ์๋?!, ๋ฐ์์ ๋ง ์ฌ์ฉํด๋ ๋๋ค๋ ๋ง์ด์์!โ ๋ง๋ค. ๊ทธ๋์ ์ด๋ ๊ฒ ํ์๋๋ฉด, actor์์ ์๋ mutable state๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์์ผ๋ฉด ์๋๋ค. ์์ ๊ฒฝ์ฐ๋ ๊ด์ฐฎ์๋ฐ, immutable property์ ์ ๊ทผํ๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค.
extension LibraryAccount: Hashable {
nonisolated func hash(into hasher: inout Hasher) {
hasher.combine(booksOnLoan) // โ actor-isolated property 'booksOnLoan' cannot be referenced from outside the actor
}
}
์ด๋ ๊ฒ ๊ณต์ ๋๋ ๋ณ์์ ์ ๊ทผํ๋ฉด ์๋ฌ๋ฅผ ๋ฟ๋๋ค.
Closures
extension LibraryAccount {
func readSome(_ book: Book) -> Int { ... }
func read() -> Int {
booksOnLoad.reduce(0) { book in
readSome(book)
}
}
}
๋จผ์ , Closure๋ ์ผ์ข ์ ํจ์๋ผ ๋ณผ ์ ์๋ค. ์ ํํ๊ฒ ๋งํ๋ฉด ํจ์๊ฐ Closure์ ์ผ์ข ์ด๋ค. ๋ค๋ง, ํน์ ํจ์ ๋ด์์ ์ ์๋ ์๋ ์๊ณ , ๋ค๋ฅธ ํจ์๋ก ๋๊ฒจ ์ถํ์ ํธ์ถ๋ ์๋ ์๋ค๋ ์ฐจ์ด์ ์ด ์๋ค.
์ผ๋จ ํจ์์ ๋ง์ฐฌ๊ฐ์ง๋ก closure ์ญ์, actor-isolated๊ฑฐ๋ non-isolated ๋ ์ ์๋ค. ์์ ์์์์ readSome
ํจ์ ์์ await
๊ฐ ์๋ ๊ฒ์ ์ด์ฐ๋ณด๋ฉด ๋น์ฐํ๋ค. ์๋ํ๋ฉด, reduce๋ผ๋ ํจ์๊ฐ ๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋ ๊ฒ์ด ๋ถ๋ช
ํ๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋น ํด๋ก์ ๋ ๋ฐ๊นฅ์ผ๋ก ํ์ถ(escape) ํ ์ ์๋ค. ์ฆ, ์ด ์์ฒด๋ก actor-isolated ๋์ด ์๋ค.
extension LibraryAccount {
func readSome(_ book: Book) -> Int { ... }
func read() -> Int { ... }
func readLater() {
Task.detached {
await self.read()
}
}
}
์ด๊ฑด ์ด๋จ๊น? ์ด๋ฒ์๋ Task.detached
๋ฅผ ์ฌ์ฉํ๋ค. detached Task๋ actor๊ฐ ์์
์ ์ํํ๋ ๋์ closure๋ฅผ ํตํด concurrentํ๊ฒ ๋์ํ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ด closure๋ actor์ ์์ ์ ์์ผ๋ฉฐ, data race๋ฅผ ์ผ์ผํฌ ๊ฒ์ด๋ค. ์ฆ, ์ด closure๋ not-isolated ๋์ด ์๋ค. read
method๋ฅผ ์คํํ๊ธธ ์ํ ๋, await
๋ก ํ์๋ ๊ฒ์ผ๋ก ์ ์ ์๋ฏ ๋ฌด์กฐ๊ฑด์ ์ผ๋ก ๋น๋๊ธฐ์ ์ผ๋ก ์ํ๋๋ค.
Actor Isolation and Data
์ง๊ธ๊น์ง๋ code๊ฐ actor์ ์์ ์๋๋, ๋ฐ์ ์๋๋๋ฅผ ๊ธฐ์ค์ผ๋ก actor isolation์ ๋ํด์ ์์๋ณด์๋ค. Data์ ํจ๊ป ์์๋ณด์.
Struct
actor LibraryAccount {
let idNumber: Int
var booksOnLoan: [Book] = []
func selectRandomBook() -> Book? { ... } โ
}
struct Book {
var title: String
var authors: [Author]
}
// Actor์ ๋ฐ๊นฅ์ชฝ์ ์์น
func visit(_ account: LibraryAccount) async {
guard var book = await account.selectRandomBook() else {
return
}
book.title = "\(book.title)!!!"
}
์ด์ ์์์ ์ฐ๋ฆฌ๋ Book์ด ์ด๋ค ํ์
์ธ์ง ์ฌ์ค ๋งํ์ง ์์๋ค. ์ด ์ํฉ์์ ์ผ๋จ Struct๋ผ๊ณ ์๊ฐํด๋ณด์. ์ผ๋จ ๊ต์ฅํ ์ข์ ์ ํ์ด๋ค. ์๋ํ๋ฉด libraryAccount
Actor๊ฐ ๊ฐ์ง๊ณ ์๋ instance์ ๋ชจ๋ ์ํ๊ฐ self-contained์ด๊ธฐ ๋๋ฌธ์ด๋ค.(์๋ฆฝ์ ? ์ธ๋ถ์ ์์กด์ด ์๋ค๋ ๊ฑธ ๋งํ๊ณ ์ถ์ ๋ฏ) โ
ํ์ํ ํจ์๋ random์ผ๋ก ์ฑ
์ ์ ํํ๋ ๋ฉ์๋์ธ๋ฐ, ๋ง์ฝ ํด๋น method๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ํญ์ Book์ copy๋ฅผ ๋ฐํ ๋ฐ๋๋ค. ๋ฐํ๋ฐ์ instance์ ๋ํด ๋ณ๊ฒฝ์ ๊ฐํ๋๋ผ๋ actor์ ์ํฅ์ ๋ฏธ์น์ง ์๋๋ค.
Class
actor LibraryAccount {
let idNumber: Int
var booksOnLoan: [Book] = []
func selectRandomBook() -> Book? { ... } โ
}
class Book {
var title: String
var authors: [Author]
}
// Actor์ ๋ฐ๊นฅ์ชฝ์ ์์น
func visit(_ account: LibraryAccount) async {
guard var book = await account.selectRandomBook() else { // ๐
๊ณ์ํด์ reference๋ฅผ ๋์ ธ์ฃผ๊ฒ ๋๋ค.
return
}
book.title = "\(book.title)!!!"
}
๊ทธ๋ฐ๋ฐ ๋ง์ฝ Class๋ผ๋ฉด ์ด๋จ๊น. booksOnLoan
property๋ ์ด์ Book instance์ ์ฃผ์๋ฅผ reference๋ก ๊ฐ๊ณ ์๋ค. ์ฌ์ค ์ด ์์ฒด๋ ๋ฌธ์ ๊ฐ ์๋ค. ๊ทธ๋ฐ๋ฐ, selectRandomBook
ํจ์๋ฅผ ํธ์ถํ๊ฒ ๋๋ฉด ์ด๋ป๊ฒ ๋ ๊น? reference๋ฅผ actor์์ ๋์ ธ์ฃผ๊ธฐ ๋๋ฌธ์, ์ธ๋ถ์์ actor์ mutable state๋ฅผ ๊ฐ๊ฒ ๋๋ค. ์ด๋ data race๋ฅผ ์ผ์ผํฌ ์ ์๋ ์ํฉ์ด๋ค.
Senable Types
์์์ ๋ณด์๋ฏ์ด struct์ ๊ฒฝ์ฐ์๋ concurrentํ ๋์์ด ์ ๋ง์ง๋ง, class์ ๊ฒฝ์ฐ์๋ ์ฌ์ ํ ๋ฌธ์ ๊ฐ ์๋ค. Concurrentํ๊ฒ ๋์ํ๊ธฐ ์ํด์๋ Sendable
ํด์ผ ํ๋ค.
- concurrentlyํ๊ฒ ๊ณต์ ํ๋ ๊ฒ์ ๋ํด ์์ ํ Type์ ๋งํ๋ค.
- ๋ค๋ฅธ actor ๊ฐ์ ๊ฐ์ ๊ณต์ ํ ์ ์๋ค.
- ๊ฐ์ copy ํ๋ค๋ฉด, ํน์ ์ฌ์ฉํ๋ ์ธก์์ ์๋ก ์ํฅ์ ์ฃผ์ง ์๊ณ ์ฌ๋ณธ์ ์์ ํ ์ ์๋ค๋ฉด, ํด๋น type์
Sendable
์ด๋ผ ๋ณผ ์ ์๋ค.
- Value types
- ์ฌ๋ณธ์ ๋ณต์ฌํ์ฌ ์ํธ๊ฐ์ ์ํฅ์ ์ฃผ์ง ์์
- Actor types
- mutable states์ synchronizeํ ๋ฐฉ์์ผ๋ก ์ ๊ทผํ๊ธฐ ๋๋ฌธ
- Immutable classes
Sesndable
๋ ์ ์์ง๋ง ์ถ๊ฐ์ ์ธ ์์ ์ด ํ์ํจ- ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ immutble data๋ง ๊ฐ์ง๊ณ ์๋ค๋ฉด ๊ฐ๋ฅ
- Internally-synchronized class
- ๋ด๋ถ์ ์ผ๋ก syncํ๊ฒ ๋์ํ๋๋ก ๊ตฌํํ ๊ฒฝ์ฐ
- lock
@Sendable
function types
Checking Sendable
์ด๋ฌํ ํน์ง์ Swift Compiler๋ Checkingํ๋ค. ๊ฒฐ๊ตญ, ์์์ ๋ณด์๋ Class์ ์์๋ Compile Error๊ฐ ๋๋ค.
actor LibraryAccount {
let idNumber: Int
var booksOnLoan: [Book] = []
func selectRandomBook() -> Book? { ... } โ
}
class Book {
var title: String
var authors: [Author]
}
// Actor์ ๋ฐ๊นฅ์ชฝ์ ์์น
func visit(_ account: LibraryAccount) async {
guard var book = await account.selectRandomBook() else { // โ call to actor-isolated method 'selectRandomBook' returns non-Sendable type 'Book?'
return
}
book.title = "\(book.title)!!!"
}
Adopting Sendable
๊ทธ๋ผ ์ด๋ป๊ฒ ํด์ Sendable Type์ผ๋ก ๋ง๋ค์ด์ค ์ ์์๊น? ์ผ๋จ Sendable
์ Protocol์ด๋ค.
struct Book: Sendable {
var title: String
var authors: [Author] // โ error: Sendable type ;Book; has non=Sendable stroed property 'authors' of type '[Author]'
}
class Author {
...
}
์ด๋ฅผ ์ค์ํ๊ฒ ๋๋ฉด, swift compiler๋ ๋ด๊ฐ ์์ฑํ type๋ค์ด Sendable
ํ์ง ์ฒดํฌํ๋ค. title์ ๋ฌธ์ ๊ฐ ์์ง๋ง, author๊ฐ ์ด๋ค ํ์
์ธ์ง์ ์ํด Book์ Sendable์ด ๋ ์๋ ์๋ ์ ๋ ์๋ค. ์๋์ ๋ณด๋ class์ด๋ค. ๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ์์
๋ค์ด ์ ๋์ด ์์ง ์์๋ค.(sync, immuable) ๊ทธ ๊ฒฐ๊ณผ, compile error๊ฐ ๋๊ฒ ๋๋ค.
struct Pari<T, U> {
var first: T
var second: U
}
extension Pair: Sendable where T: Sendable, U: Sendable {
}
generic์ ๊ฒฝ์ฐ์๋ ํด๋น Type์ Sendable ์ฌ๋ถ๊ฐ, generic argument์ ์ํด ์ ํด์ง๋ค. ์ด ๋, ๋ด๋ถ์ ๋ค์ด์ค๋ Type ์์ฒด์ constranint๋ฅผ ๊ฑธ์ด, ๋ค์ด์ค๋ Type์ด Sendable
ํ์ง ์์ ๋ Compile error๋ฅผ ๋๊ฒ ํ ์๋ ์๋ค.
@Sendable functions
function ์์ฒด๋ Sendable
ํ ์ ์๋ค. ์ด๋ actors ๋ค์ฌ์ด๋ก ๋์ ธ๋ ์์ ํ๋ค๋ ๊ฒ์ ๋งํ๋ค. ์ด๋ ์ค์ํ๋ฐ, closure์์ Data race๋ฅผ ๋ฐ์์ํค๋ ๊ฒ์ ์ฌ์ ์ฐจ๋จํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์๋ฅผ ๋ค์ด, Sendable
closure์ ๊ฒฝ์ฐ, mutable local ๋ณ์๋ฅผ captureํ ์ ์๋ค. capture ํ์ ๋ด๋ถ์์ ๋ณ๊ฒฝํ๋ค๋ฉด, data race๊ฐ ๋ฐ์ํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ์ด์ ๊ฐ์ด compiler ๋จ์์ ๋ฌธ์ ๋ฅผ ๋ฐ๊ฒฌํ๊ฒ ํด์ค๋ค. ํน์ง์ ๋ค์์ ๊ฐ๋ค.
- mutable capture๊ฐ ๋ถ๊ฐํ๋ค.
- Capture ํ ์ ์๋ ๋
์๋ค์
Sendable
ํด์ผ๋ง ํ๋ค. - Cannot be both sunchronous and actor-isolated
@Sendable closure restrictions
static func detached(operation: @Sendable () async -> Success) -> Task<Success, Never>
struct Counter {
var value = 0
mutating func increment() -> Int {
value = value + 1
return value
}
}
var counter = Counter()
Task.detached {
print(counter.increment()) // Mutation of cpatured var 'counter' in concurrently-executing code
}
Task.detached {
print(counter.increment()) // Mutation of cpatured var 'counter' in concurrently-executing code
์ฐ๋ฆฌ๊ฐ ์์์ ์ฌ์ฉํด๋ดค๋ detached
task๋ฅผ ๋ง๋ค์๋ ๋
์์ Sendable
closure๊ฐ ๋ค์ด๊ฐ๋ค. ์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ ๋๊ฐ์ task์์ ๊ฐ์ method๋ฅผ ๋์์ ํธ์ถ ํ์๋ค. mutable local ๋ณ์๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด data race๋ฅผ ์ผ์ผํฌ ์ํฉ์ด๋ค.
ํ์ง๋ง ์ด ๊ฒฝ์ฐ ์๋ฌ๊ฐ ๋๋๋ฐ, @Sendable
protocol์ ์ค์ํ๋ closure์ ๊ฒฝ์ฐ, mutableํ ๋ณ์๋ฅผ captureํ ์ ์๋ค.
static func detached(operation: @Sendable () async -> Success) -> Task<Success, Never>
extension LibraryAccount {
func readSome(_ book: Book) -> Int { ... }
func read() -> Int { ... }
func readLater() {
Task.detached {
self.read() // โ call to actor-isolated method 'read' must be 'async'
}
}
}
์ด ์์๋ฅผ ๋ณด์. readLater()
๋ actor๋ด์ ์ ์๋ ํจ์์ด์ง๋ง, ๋ด๋ถ์ ์ผ๋ก๋ Task.detached
๋ฅผ ์ฌ์ฉํ์ฌ, actor ์ธ๋ถ์์ ๋์ํ ์ ์๋ค. ๊ฒฐ๊ตญ, Task.detached
์์ ์ฌ์ฉํ๋ closure๋ actor ์ธ๋ถ์์ ์ ๊ทผํ ์ ์์ผ๋ฉฐ, ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ async
ํ๊ฒ ๋์ํด์ผ actor-isolated๋ฅผ ๋ณด์ฅํ ์ ์๋ค. ์ด๋ฐ ๋ถ๋ถ์ compiler๊ฐ ์ก์์ฃผ๊ณ ์๋ค.
Main actor
์ด์ actor์ ๊ด๋ จ๋ ํ๋์ ์์๊ฐ ๋จ์๋ค. ์ด๋ ์์ ์ข ํน๋ณํ ๋ ์์ด๋ค.
Interacting with the main thread
main thread๋ app์์ ์ค์ํ ๋ ์์ด๋ค. UI rendering์ด ์ผ์ด๋๋ฉฐ, user์ interaction event๋ ์ฒ๋ฆฌ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ถ์ UI์ ๊ด๋ จ๋ ์ผ์ main thread์์ ์ฒ๋ฆฌํ๋ค.
func checkedOut(_ booksOnLoan: [Book]) {
booksView.checkedOutBooks = booksOnLoan
}
DispatchQueue.main.async {
checkedOut(booksOnLoan)
}
ํ์ง๋ง, ๋ชจ๋ ์์
์ main thread์์ ํ ํ์๋ ์๋ค. ๊ทธ๋์ ์ฐ๋ฆฌ๋ ๋ณดํต ๋ค๋ฅธ ์์
๋ค์ ํ๋ค๊ฐ DispatchQueue.main.async
๋ฅผ ํตํด์ main thread์์ ํ ๋์์ ๋๊ฒจ์ฃผ๊ณค ํ์๋ค. ๊ทผ๋ฐ ์ ์๊ฐํด๋ณด๋ฉด, ์ด๊ฑด actor๊ฐ ๋์๊ฐ๋ ๋ฉ์ปค๋์ฆ๊ณผ ๋น์ทํ์ง ์์๊น? main thread๋ syncํ๊ฒ ๋์ํด์ผ ํ๋ฉฐ, ํ์ ํ๊ฒ ์ ๊ทผ ๊ฐ๋ฅํด์ผ ํ๋ค.
The Main Actor
์ด๋ฐ ํ์์ฑ์ ์ํด main actor๊ฐ ๋์๋ค.
@MainActor func checkedOut(_ booksOnLoan: [Book]) {
booksView.checkedOutBooks = booksOnLoan
}
await checkedOut(booksOnLoan)
- main thread๋ฅผ ๋ํํ๋ค.
- ํด๋น ํจ์๋ก ๋ค์ด์ค๋ ๋ชจ๋ task๋ฅผ main dispatch queue์์ ์ฒ๋ฆฌํ๋ค.
- main thread์์ ์คํํด์ผ ํ๋ ์ฝ๋๋ ์ฌ๊ธฐ์ ๊ธฐ ํฉ์ด์ ธ์์๋ค. main actor๋ฅผ ์ฌ์ฉํ๋ฉด ์ ์ธํ๋ ๊ฒ์ผ๋ก ํด๊ฒฐ ๊ฐ๋ฅํ๋ค.
@MainActor class MyViewController: UIViewController {
func onPress(...) { ... } // ์๋ฌต์ ์ผ๋ก @MainActor์
nonisolated func fetchLatestAndDisplay() async { ... }
}
type์ @MainActor
๋ฅผ ์ ์ธํ ์๋ ์๋ค. ์ด๋ ๊ฒ ํ๋ฉด, member๋ค๊ณผ subclass ๋ชจ๋ main Actor๋ก ๋์ํ๋ค. UI์ ์ํธ์์ฉํด์ผ ๋งํ๊ฑฐ๋, ๋๋ถ๋ถ์ด main์ ๋์๊ฐ์ผ ํ๋ค๋ฉด ์ ์ฉํ๊ฒ ์ธ ์ ์์ ๊ฒ์ด๋ค. ์ด ๊ฒฝ์ฐ, ๊ฐ๋ณ์ ์ผ๋ก actor ๊ฒฉ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์ง ์์ ๊ฒฝ์ฐ nonsolated
ํค์๋๋ฅผ ํตํด ๋ถ๋ฆฌํ ์ ์๋ค.
๋ง๋ฌด๋ฆฌ
- Actor type์ ์ฌ์ฉํด์ mutable state์ syncํ๊ฒ ์ ๊ทผํ์.
- rerentrancy๋ฅผ ์ํ ์ค๊ณ๊ฐ ํ์ํ๋ค.
- data race๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด value ํ์ ์ ์ฌ์ฉํ์.
- ์ด๋ฅผ ๋ฐฉ์งํ๋ ค๋ฉด
Sendable
protocol์ ์ฑํํ์ฌ checking์ ์ํํ์. @MainActor
๋ฅผ ์ฌ์ฉํด์ ์ด์ ์DispatchQueue.main.async
๋ก ์ํํ๋ ๊ฒ์ ๋ฐ๊ฟ๋ณด์.