Swift のアーキテクチャパターンまわりの新しい記事を眺めてると、
@Observable には、明示的に @MainActor をつけましょう。
その親 View にも @MainActor をつけるのが推奨されます。
などと書いてるのを多く見かける。
「全部 UI スレッドでは?」
などと思いながら、あれこれやってみました。
import SwiftUI
@MainActor
struct TestWebRequest: View {
  @State private var responseBody = ""
  //private let url = URL(string: "https://wttr.in/?format=3")!
  //private var background = Background()
  private var viewModel = TestViewModel()
  var body: some View {
//    Text("\(responseBody)")
//    Text("\(background.responseBody)")
    Text("\(viewModel.responseBody)")
//      .onAppear { // OK
//        responseBody = try! String(contentsOf: url)
//      }
//      .onAppear {
//        // Passing argument of non-sendable type '(any URLSessionTaskDelegate)?'
//        // outside of main actor-isolated context may introduce data races
//        Task {
//          let (data, _) = try! await URLSession.shared.data(from: url)
//          responseBody = String(data: data, encoding: .utf8)!
//        }
//      }
//      .task {
//        // Passing argument of non-sendable type '(any URLSessionTaskDelegate)?'
//        // outside of main actor-isolated context may introduce data races
//        let (data, _) = try! await URLSession.shared.data(from: url)
//        responseBody = String(data: data, encoding: .utf8)!
//      }
//        .onAppear {
//          Task {
//            responseBody = await Background.request(url: url)
//          }
//        }
//      .task {
//        responseBody = await background.request(url: url)
//      }
//      .task {
//        responseBody = await background.request(url: url)
//      }
      .task {
        //await background.request(url: url)
        await viewModel.request()
      }
  }
}
@MainActor
@Observable
final class TestViewModel {
  var responseBody = ""
  private let background = Background()
  func request() async {
    responseBody = await background.request()
  }
}
//class Background: @unchecked Sendable {
final class Background: Sendable {
  private let url = URL(string: "https://wttr.in/?format=3")!
  func request() async -> String {
    let (data, _) = try! await URLSession.shared.data(from: url)
    return String(data: data, encoding: .utf8)!
  }
}
//actor Background {
//  private let url = URL(string: "https://wttr.in/?format=3")!
//
//  nonisolated func request() async -> String {
//    let (data, _) = try! await URLSession.shared.data(from: url)
//    return String(data: data, encoding: .utf8)!
//  }
//}
#Preview {
  TestWebRequest()
}
【Swift】Strict Concurrency Checking の設定 https://t.co/wmXyJ8ipOv #Qiita
— chanzmao (@maochanz) June 25, 2024
 
こうなりますか。

そろそろ消えてほしかった ViewModel。
いや、それとも、

おすすめ定番パターンを Apple はアナウンスしてもよくない ?
いろいろ混乱します。
【Swift 6 concurrency】 新しい @Observable クラスの書き方を知らないやつwww https://t.co/0iEizwFcpp #Swift #ios #プログラミング初心者
— chanzmao (@maochanz) July 6, 2024
 
 
		 
           
          




