Swift 25 swift actor 紹介

# 初めて
`ストラクト`化された同時性は複数の`Task`を同時に実行するための強いフレトプムを提供してアフリの性能と応答性を非常に上達します。
同時性の短所の一つは複数の`Task`が同一なデータを同時に接近するときに問題が発生することができるし、該当接近には読むと書き`Task`が混在していることでするそのような形の問題をdata raceだと言って、偶に衝突及び推測できないアフリの動作に続けられることがあります。
以前の章には複数の同時な作業の結果を順序的に処理すると関連される問題について解決策を見てみました。
残念だけどその解決策に関連されたすべての作業は**同一な作業グループにに属するに限って**実際に動作する。
もっと　柔軟して同時作業を始める位置に関係なく作動する解決策は Swift Actorを使うことだ。

# 二十五・壱 Ａｃｔｏｒ
## 壱・一 概要
actorは一度に1つの作業だけデータに接近されるように内部変更可能状態に対する非同期接近を制御するスイフトの**プリパランスタイプ**でで、ａｔｔｒｉｂｕｔｅ、ｇｅｎｅｒａｔｏｒ他にはｍｅｔｈｏｄを含まれる点で**ｃｌａｓｓと非常に似ています**。これはプロトコルも遵守して拡張を書できます。Ａｃｔｏｒを宣言しするときの一番大きな違い点は　**'class'の代わりに'actor'だと言う単語が使われること**です。
## 壱・ニ　宣言する
ａｔｔｒｉｂｕｔｅとｍｅｔｈｏｄを含まれる簡単なスイフトクラスは次のように宣言します。
```diff_swift
+ actor BuildMessage3 { // class > actor
        var message : String = ""
        let greeting = "Hello"
        
        func setName(name: String ){
            self.message = "\(greeting) \(name)"
        }
    }
```
ａｃｔｏｒのインスタンスは
```diff_swift
let hello = BuildMessage()
```
だがクラスａｃｔｏｒの一番大きな違い点はこれは非同期関数またはＴａｓｋのクローザー内で同じ非同期コンテキスト内だけで生成とアクセスができるということだ。またａｃｔｏｒ`メソッド`を呼び出しとか属性で接近するときawaitキイワード必ず使用するべきだ
```diff_swift
  func someFunction() async{
            let builder = BuildMessage()
            await builder.setName(name:"Jane Smith")
            let message = await builder.message
            print(message)
        }
```
# 二十五・弍 ｄａｔａ　ｉｓｏｌａｔｉｏｎ
ａｃｔｏｒインスタンスで含まれたデータはアフリの他のコードと隔離されます。この様なｉｓｏｌａｔｉｏｎはインスタンスデータを変更(ここではname変数変形)する`メソッド`が呼び出されるときに、他の所のコードで該当`メソッド`を`呼び出されることを保証します。そうすると複数の作業が同時にデータ変更をやってみることを防止することができます。もちるんこれはメーソド呼び出すなどか属性に対する接近をできないょうに以前の作業を処理されるまで待っているべきで、**ａｗａｉｔ文が必要だことを意味します**。
また、ｉｓｌｏａｔｉｏｎはコードがａｃｔｏｒ可変的な内部属性を直接に変更することを防止します。例えば次の様にBuildMessageインスタンスのmessage属性に新しい値を割合うコードがあったと考えてみよう。
```diff_swift
builder.message = "hello"
```
クラスインスタンスを作業するときには有効するだけど、前のコードはａｃｔｏｒインスタンスで試行するのでえーらが出るだろう
![Screenshot 2023-12-06 at 3.07.26 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/6c6bff9c-4315-0dd0-c198-192a01d8ab5e.png)
デフォルトでａｃｔｏｒ内のすべてのメソッドと可変的な属性はｉｓｏｌａｔeされたと考慮されて、`awaitキーウド`を通じて呼ぶことができます。例えばgreeting文字列を返却するｎｏｎｉｓｏｌａｔｅｄメソッドを`buildMessageａｃｔｏｒ`で追加することができます。
```diff_swift
 var builder = BuildMessage()
    
    func asyncFunction() async {
        let greeting = builder.getGreeting()
        print(greeting)
    }
    
    func sysncFunction() {
        let greeting = builder.getGreeting()
        print(greeting)
    }
```
この新しい`メソッド`は同期、非同期コンテキスト全てでawaitキイワードなくて呼ぶことができます。
`getGreeting()メソッド`は不便的なgreeting属性だけで接近するのせいでこのメーソドをｎｏｎｉｓｏｌａｔｅｄだけで宣言することができます。

# 二十五・参 ｓｗｉｆｔ ａｃｔｏｒ例題
以前の章にはデータ競争を調べてみたしコンファイラが次の様みたいなエラー目せじを発生することができるコードを作成しないすることを学びました。
```diff_swift
Mutation of captured var 'timeStamps' in concurrently-excuting code
```
次の非同期コードを使用してディクショナリーオブジェクトで項目を書こうとする時次の様なエラーが発生しました。
```diff_swift
struct ContentView: View {
    
    func doSomething() async{
        var timeStamps: [Int: Date] = [:]
        
        await withTaskGroup(of: Void.self){group in
            for i in 1...5 {
                group.addTask {
                    timeStamps[i] = await takesTooLong()
                }
            }
        }
    }
```
その様の問題を避けるための一つのオプションで以前の章で実装した方法はfor-awaitルーフを使用者して非同期作業の結果を順次的に処理することだ。だがその章で見た様にactorを使用して解決することができることである。

Xcodeで　ConcurrencyDemo ふろジェクトをロードしてContentView.swifファイルを編集して次のａｃｔｏｒ宣言を追加してtimeStampsデクショナりカップシュル化してデータを追加できることの`メソッド`を追加してみましょう。
```diff_swift
actor TimeStore{
    var timeStamps: [Int:Date]=[:]
    func addStamp(task: Int, date: Date) {
        timeStamps[task]=date
    }
```
ａｃｔｏｒを宣言したので今から `doSomething()メソッド`を修正して`addStamp()メソッド`を通じて新しいタイムスタンプを追加することができます。
# 二十五・肆　ＭａｉｎＡｃｔｏｒ紹介
24章でまメーインスレッド「メインキーユウ」に対して説明しまして、UIレンダリング処理と使用者いべーんとに対する応答をどう担当するかを説明しました。また、メーインスレッドでｔｈｒｅａｄ・ｂｌｏｃｋｉｎｇ作業を実行するときの危険とそうすることは実行しているプログラミングのとまる原因になることについても説明しました。前で見たより`ストラクト`はメーインスレッドで分離される他のスレッドで作業実行することは簡単で強いメカニズムを提供します。また説明しないものはメーインスレッドだけであるUIアプデートを実行されることです。

ｓｗｉｆｔではメインスレッドはｍａｉｎＡｃｔｏｒで表現されます。これをｇｌｏｂａｌＡｃｔｏｒだと言います。なぜならメーンスレッドで実行するコードをプログラム全体でアクセスできることだからです。

アプリを開発するとき、メーンａｃｔｏｒで実行するを欲しなコードがあるかもしれない.特に該当コードが何らかの形でUIをアプデートしなければならない場合だ。その場合`@mainActor`属性を使用してコードを表現されることができる。この属性は関連作業がメーンＡｃｔｏｒで実行されるべきだとを指しるためターフ・メソッド・インスタンス・関数・クローザーで使用されることができます。例え、メーインスレッドで動作する様にクラスを構成することもできます。
```diff_swift
+@MainActor
class TimeStore {
    var timeStamps: [Int: Date] = [:]
    
    func addStamp(task: Int, date: Date){
        timeStamps[task] = date
    }
}
```
他の方法で単一の値とか属性をメーインスレッドで従属で表示することができます。
```diff_swift
-
class TimeStore {
+   @MainActor var timeStamps: [Int: Date] = [:]
    
    func addStamp(task: Int, date: Date){
        timeStamps[task] = date
    }
}
```
もちろん、timeStampsデックショナリはメーンＡｃｔｏｒで割り当てられたので他のスレッドで接近できません。前のaddStamp()メソッドからデックショナリで新しい日付を追加しようすると、次の様なエラーが発生するだろう。![Screenshot 2023-12-06 at 8.56.04 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/4fc25df2-2527-4b8b-4ee0-1b1e1455e2ca.png)
その問題を解決するとaddStamp()メソッドも@MainActor属性を使用者して表紙されるべきです。

```diff_swift
class TimeStore {
    @MainActor var timeStamps: [Int: Date] = [:]
    
+   @MainActor func addStamp(task: Int, date: Date){
        timeStamps[task] = date
    }
}
```
`mainActor`の`runメソッド`はメーンスレッドで作業を実行する様に非同期コード内で呼び出すことができます。
```diff_swift
func runExample() async {
    await MainActor.run{
        
    }
}
```
# 要約
非同期コード作成の核心部分はデータ競争を避けることです。データ競争は二つ以上の作業が同一なデータで接近して該当作業が書き作業を実行するときで発生します。此れは同時作業が同一なデータのお互い違うバージョンを照会して作業されるデータ不一致の原因になります。

データ競争を避けるための有用な道具はSwiftのＡｃｔｏｒターフです。これは構文面で動作の面でSwiftのクラスと似ているだけどカップシュル化されたデータはアフリ内の他のコードとは別居している点が違う。もしかしてインスタンスデータを変更するＡｃｔｏｒのメソッドが呼びだされると、該当メソッドがコードの上で他のところで呼び出される様にされる前にメソッドが完全に実行されることを保証する。これは複数の作業が同時に同一なテータを変更されない様に防止する。Ａｃｔｏｒメソッド呼び出すと属性に対する接近はawaitキーウドを使って呼び出レルベキです。

メーンＡｃｔｏｒは非同期コード内でメーンスレッドに対する接近を提供する特別なＡｃｔｏｒです。`@MainActor属性は関連された作業がメーンスレッドで実行されるべきだとを表すためターフ、メソッド、インスタンス、ファンション、くろーさを表示される様に使われることができます。