From 4e59d8591efcb62e3f64aba1bdee538a86380ad3 Mon Sep 17 00:00:00 2001 From: khetiSubrat Date: Mon, 11 Aug 2025 22:20:27 +0530 Subject: [PATCH] Support Swift6 version to Birthday sample app. --- .../Services/GoogleSignInAuthenticator.swift | 4 +- .../Services/UserProfileImageLoader.swift | 56 +++++++++++-------- .../ViewModels/AuthenticationViewModel.swift | 6 +- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index de227f08..e12d79a2 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -29,7 +29,7 @@ final class GoogleSignInAuthenticator: ObservableObject { /// Signs in the user based upon the selected account.' /// - note: Successful calls to this will set the `authViewModel`'s `state` property. - func signIn() { + @MainActor func signIn() { #if os(iOS) guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { print("There is no root view controller!") @@ -98,7 +98,7 @@ final class GoogleSignInAuthenticator: ObservableObject { /// `addScopes(_:presenting:)` request. /// - note: Successful requests will update the `authViewModel.state` with a new current user that /// has the granted scope. - func addBirthdayReadScope(completion: @escaping () -> Void) { + @MainActor func addBirthdayReadScope(completion: @escaping () -> Void) { guard let currentUser = GIDSignIn.sharedInstance.currentUser else { fatalError("No user signed in!") } diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/UserProfileImageLoader.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/UserProfileImageLoader.swift index d54e20a0..fd08085f 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/UserProfileImageLoader.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/UserProfileImageLoader.swift @@ -22,38 +22,50 @@ typealias GIDImage = NSImage import Combine import SwiftUI -import GoogleSignIn +@preconcurrency import GoogleSignIn /// An observable class for loading the current user's profile image. -final class UserProfileImageLoader: ObservableObject { +@MainActor final class UserProfileImageLoader: ObservableObject { private let userProfile: GIDProfileData - private let imageLoaderQueue = DispatchQueue(label: "com.google.days-until-birthday") + private var imageLoadingTask: Task? /// A `UIImage` property containing the current user's profile image. /// - note: This will default to a placeholder, and updates will be published to subscribers. @Published var image = GIDImage(named: "PlaceholderAvatar")! /// Creates an instance of this loader with provided user profile. /// - note: The instance will asynchronously fetch the image data upon creation. - init(userProfile: GIDProfileData) { - self.userProfile = userProfile - guard userProfile.hasImage else { - return + init(userProfile: GIDProfileData) { + self.userProfile = userProfile + guard userProfile.hasImage else { + return + } + imageLoadingTask = Task { + await loadProfileImage() + } } - imageLoaderQueue.async { - #if os(iOS) - let dimension = 45 * UIScreen.main.scale - #elseif os(macOS) - let dimension = 120 - #endif - guard let url = userProfile.imageURL(withDimension: UInt(dimension)), - let data = try? Data(contentsOf: url), - let image = GIDImage(data: data) else { - return - } - DispatchQueue.main.async { - self.image = image - } + private func loadProfileImage() async { + #if os(iOS) + let dimension = 45 * UIScreen.main.scale + #elseif os(macOS) + let dimension = 120 + #endif + + guard let url = userProfile.imageURL(withDimension: UInt(dimension)) else { + return + } + + do { + let (imageData, _) = try await URLSession.shared.data(from: url) + if let image = GIDImage(data: imageData) { + self.image = image + } + } catch { + print("Image download failed:", error) + } + } + + deinit { + imageLoadingTask?.cancel() } - } } diff --git a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift index 3ad14289..15bee104 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift @@ -46,7 +46,7 @@ final class AuthenticationViewModel: ObservableObject { } /// Signs the user in. - func signIn() { + @MainActor func signIn() { authenticator.signIn() } @@ -66,8 +66,8 @@ final class AuthenticationViewModel: ObservableObject { /// Adds the requested birthday read scope. /// - parameter completion: An escaping closure that is called upon successful completion. - func addBirthdayReadScope(completion: @escaping () -> Void) { - authenticator.addBirthdayReadScope(completion: completion) + @MainActor func addBirthdayReadScope(completion: @escaping () -> Void) { + authenticator.addBirthdayReadScope(completion: completion) } }