Listings Sillman/Swift-Tutorial, Teil 2

Listing 1: Child-Tasks via async let erstellen
func loadPhotos() async -> [Photo] {
    async let firstPhoto = loadPhoto("FirstPhoto")
    async let secondPhoto = loadPhoto("SecondPhoto")
    async let thirdPhoto = loadPhoto("ThirdPhoto")

    let photos = await [firstPhoto, secondPhoto, thirdPhoto]
    return photos
}

func loadPhoto(_ name: String) async -> Photo {
    async let photoData = loadPhotoData(name)
    async let photoMetadata = loadPhotoMetadata(name)
    return await Photo(data: photoData, metadata: photoMetadata)
}

--

Listing 2: SwiftUI-View mit Modifier task(_:_:)
struct PhotosView: View {
    @State private var photos: [Photo]?

    var body: some View {
      List(photos) { photo in
          PhotoCell(photo)
      }
      .task {
          photos = await PhotoManager().loadPhotos()
      }
    }
}

--

Listing 3: Boolean Task.isCancelled prüft Task-Abbruch
func loadPhoto(_ name: String) async -> Photo? {
    async let photoData = loadPhotoData(name)
    async let photoMetadata = loadPhotoMetadata(name)
    if Task.isCancelled {
      deletePhotoData(name)
      return nil
    }
    return await Photo(data: photoData, metadata: photoMetadata)
}

--

Listing 4: Eine mit throws deklarierte Funktion
func loadPhoto(_ name: String) async throws -> Photo? {
    async let photoData = loadPhotoData(name)
    async let photoMetadata = loadPhotoMetadata(name)
    let photo = await Photo(data: photoData, metadata: photoMetadata)
    guard photo.isValid else {
      throw PhotoError.invalidData
    }
    return photo
}

--



Listing 5: ask.checkCancellation() prüft auf mögliche Taskabbrüche
func loadPhotos(withNames names: [String]) async throws -> [Photo] {
    var photos = [Photo]()
    for name in names {
      try Task.checkCancellation()
      let photo = try await loadPhoto(name)
      photos.append(photo)
    }
    return photos
}

--

Listing 6: Der Button versucht eine Methode aufzurufen
struct DownloadButton: View {
    var body: some View {
      Button("Download photos") {
          await PhotoManager().loadPhotos()
          // Fehler: Kein Aufruf einer asynchronen Funktion möglich.
      }
    }
}

--

Listing 7: Der angepasste Button
struct DownloadButton: View {
    var body: some View {
      Button("Download photos") {
        Task {
          await PhotoManager().loadPhotos()
        }
      }
    }
}

--

Listing 8: Die Methode increase erhöht das Ergebnis um eins
class Calculator {
    var result = 0

    func increase() -> Int {
      result = result + 1
      return result
    }
}

let calculator = Calculator()

Task {
    print(calculator.increase())
}

Task {
    print(calculator.increase())
}

--

Listing 9: Compiler gibt einen Fehler aus
struct Calculator {
    var result = 0

    mutating func increase() -> Int {
      result = result + 1
      return result
    }
}

var calculator = Calculator()

Task {
    print(calculator.increase())
    // Fehler: Wertänderung in parallel laufendem Code nicht möglich.
}

Task {
    print(calculator.increase())
    // Fehler: Wertänderung in parallel laufendem Code nicht möglich.
}

--

Listing 10: Ausnahmen definieren
@MainActor class PhotoViewController: UIViewController {
    // Ausführung auf dem Main-Thread
    func updateImage(withPhoto photo: Photo) { ... }

    // Ausnahme von @MainActor
    nonisolated func fetchPhotos() async { ... }
}

