我在从 Firebase 获取图像时遇到问题,我创建了一个函数来将图像保存到存储中,并且运行良好,但同时我想向用户显示该图像,但它无法正常工作,因为当我关闭视图并单击返回时,我看到了图像。问题出在哪里,如何解决?
用户个人资料视图:
import SwiftUI
import PhotosUI
public struct UserProfileView: View {
@StateObject private var viewModel = UserProfileViewModel()
public init() { }
public var body: some View {
VStack {
if let imageUrlString = viewModel.user?.profileImagePath, let url = URL(string: imageUrlString) {
AsyncImage(url: url) { image in
image
.resizable()
.scaledToFill()
.frame(width: 150, height: 150)
.clipShape(Circle())
} placeholder: {
ProgressView()
.frame(width: 150, height: 150)
}
} else {
Image(systemName: "person.fill")
.font(.system(size: 90))
.frame(width: 150, height: 150)
}
}
.background {
Circle()
.stroke(lineWidth: 3)
}
PhotosPicker(
selection: $viewModel.selectedPhoto,
matching: .images,
photoLibrary: .shared()
) {
Text("Change photo")
}
.onChange(of: viewModel.selectedPhoto) { newValue in
if let newValue {
Task {
do {
try await viewModel.saveProfileImage(item: newValue)
viewModel.objectWillChange.send()
} catch {
print(error.localizedDescription)
}
}
}
}
}
}
用户配置文件视图模型:
@MainActor
public final class UserProfileViewModel: ObservableObject {
@Inject private var cloudStorageManager: CloudStorageInterface
@Inject private var userManager: UserManagerInterface
@Published var selectedPhoto: PhotosPickerItem? = nil
@Published var imageUrl: URL? = nil
@Published var user: User? = nil
public init() {
Task {
do {
try await getCurrentUser()
} catch {
print(error.localizedDescription)
}
}
}
private func updateUserProfileImagePath(path: String) async throws {
let data: [String : Any] = [
User.CodingKeys.profileImagePath.rawValue : path
]
try await userManager.updateUserData(data: data)
}
func saveProfileImage(item: PhotosPickerItem) async throws {
let user = try await self.userManager.fetchUser()
guard let data = try await item.loadTransferable(type: Data.self) else { return }
guard let image = UIImage(data: data) else { return }
let path = try await cloudStorageManager.saveImage(image: image, userId: user.id)
print("SUCCESS!")
let url = try await cloudStorageManager.getUrlForImage(path: path)
try await updateUserProfileImagePath(path: url.absoluteString)
}
func getCurrentUser() async throws {
self.user = try await userManager.fetchUser()
}
func getProfileImage() async throws {
guard let user = user else { return }
guard let image = user.profileImagePath else { return }
self.imageUrl = try await cloudStorageManager.getUrlForImage(path: image)
}
}
云存储管理器:
final class CloudStorageManager: CloudStorageInterface {
private lazy var storage = Storage.storage().reference()
private var imagesReference: StorageReference {
storage.child("images")
}
private func userReference(userId: String) -> StorageReference {
storage.child("Users").child(userId)
}
func saveImage(data: Data, userId: String) async throws -> String {
let meta = StorageMetadata()
meta.contentType = "image/jpeg"
let path = "\(UUID().uuidString).jpeg"
let returnedMetaData = try await userReference(userId: userId).child(path).putDataAsync(data, metadata: meta)
guard let returnedPath = returnedMetaData.path else {
throw URLError(.badServerResponse)
}
return returnedPath
}
//SAVE
func saveImage(image: UIImage, userId: String) async throws -> String {
guard let data = image.jpegData(compressionQuality: 0.6) else {
throw URLError(.backgroundSessionWasDisconnected)
}
return try await saveImage(data: data, userId: userId)
}
//READ
func getUrlForImage(path :String) async throws -> URL {
try await Storage.storage().reference(withPath: path).downloadURL()
}
}
用户型号:
public struct User: Storable, Hashable {
public let id: String
public let providerId: String?
public let email: String?
public let displayName: String?
public let photoURL: String?
public let topic: String
public let mqttPassword: String
public let isFirstLogin: Bool
public let profileImagePath: String?
public init(
id: String = UUID().uuidString,
providerId: String?,
email: String?,
displayName: String?,
photoURL: String?,
topic: String,
mqttPassword: String,
isFirstLogin: Bool = true,
profileImagePath: String? = nil
) {
self.id = id
self.providerId = providerId
self.email = email
self.displayName = displayName
self.photoURL = photoURL
self.topic = topic
self.mqttPassword = mqttPassword
self.isFirstLogin = isFirstLogin
self.profileImagePath = profileImagePath
}
public init(
from authDataResult: AuthenticationDataResult,
isFirstLogin: Bool = true
) {
self.id = authDataResult.uid
self.providerId = authDataResult.providerId
self.email = authDataResult.email
self.displayName = authDataResult.displayName
self.photoURL = authDataResult.photoURL
self.topic = ""
self.mqttPassword = ""
self.isFirstLogin = isFirstLogin
self.profileImagePath = nil
}
public init(from dao: UserDAO) {
self.id = dao.id
self.providerId = dao.providerId
self.email = dao.email
self.displayName = dao.displayName
self.photoURL = dao.photoURL
self.topic = dao.topic
self.mqttPassword = dao.mqttPassword
self.isFirstLogin = dao.isFirstLogin
self.profileImagePath = dao.profileImagePath
}
public enum CodingKeys: String, CodingKey {
case id
case providerId
case email
case displayName
case photoURL
case topic
case mqttPassword
case isFirstLogin
case profileImagePath
}
}
在 Swift 4 中:
let ref = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
let userRef = ref.child("users").child(uid!)
var myImageView = UIImageView()
userRef.getDocument { (document, error) in
if let document = document, document.exists {
let myData = document.data()
if let profileURL = myData["profileURL"] as? String {
let storageRef = Storage.storage().reference(forURL: profileURL)
myImageView.sd_setImage(with: storageRef,
placeholderImage:UIImage(named: "placeholder.png"))
}
else {
print("profileURL is nil")
}
}
else {
print("Document does not exist")
}
}