KeyboardSceneDelegate:用户驱动的演示文稿上的动画样式不为空

KeyboardSceneDelegate: Animation styles were not empty on user driven presentation

提问人:Vader20FF 提问时间:10/22/2021 更新时间:10/22/2021 访问量:168

问:

我的应用程序有问题。当我点击TextField,尝试填充数据时,在刚刚显示的工作表中,我的应用程序冻结,控制台上出现四个错误:

> [Assert] Animation styles expected to be empty on user driven
> presentation. Actually contains: (
>     "<<_UIViewControllerKeyboardAnimationStyle: 0x281ee4d00>; animated = YES; duration = 0.35; force = NO>" )
> 
> [KeyboardSceneDelegate] Animation styles were not empty on user driven
> presentation!
> 
> Fit_Vein/ProfileView.swift:69: Fatal error: Unexpectedly found nil
> while unwrapping an Optional value
> 
> Fit_Vein/ProfileView.swift:69: Fatal error: Unexpectedly found nil
> while unwrapping an Optional value

当我从ProfileView转到SettingsView时,就会发生这种情况,然后尝试执行以下选项之一:更改电子邮件,密码或删除帐户并在这些工作表中输入数据。

我的代码:

配置文件视图:

struct ProfileView: View {
    @ObservedObject private var profileViewModel: ProfileViewModel
    @EnvironmentObject private var sessionStore: SessionStore
    @Environment(\.colorScheme) var colorScheme
    
    @State private var image = UIImage()
    
    @State private var shouldPresentAddActionSheet = false
    @State private var shouldPresentImagePicker = false
    @State private var shouldPresentCamera = false
    
    @State private var shouldPresentSettings = false
    
    init(profileViewModel: ProfileViewModel) {
        self.profileViewModel = profileViewModel
    }
    
    var body: some View {
        GeometryReader { geometry in
            let screenWidth = geometry.size.width
            let screenHeight = geometry.size.height
            
            ScrollView(.vertical) {
                HStack {
                    if profileViewModel.profilePicturePhotoURL != nil {
                        AsyncImage(url: profileViewModel.profilePicturePhotoURL!) { image in
                            image
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .clipShape(RoundedRectangle(cornerRadius: 50))
                                .shadow(color: .gray, radius: 7)
                                .frame(width: screenWidth * 0.4, height: screenHeight * 0.2)
                                .onTapGesture {
                                    self.shouldPresentAddActionSheet = true
                                }
                        } placeholder: {
                            Image(uiImage: UIImage(named: "blank-profile-hi")!)
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .clipShape(RoundedRectangle(cornerRadius: 50))
                                .shadow(color: .gray, radius: 7)
                                .frame(width: screenWidth * 0.4, height: screenHeight * 0.2)
                        }
                    } else {
                        Image(uiImage: UIImage(named: "blank-profile-hi")!)
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .clipShape(RoundedRectangle(cornerRadius: 50))
                            .shadow(color: .gray, radius: 7)
                            .frame(width: screenWidth * 0.4, height: screenHeight * 0.2)
                            .onTapGesture {
                                self.shouldPresentAddActionSheet = true
                            }
                    }
                    
                    Spacer(minLength: screenWidth * 0.05)
                    
                    VStack {
                        HStack {
                            Text(profileViewModel.profile!.firstName)
                                .foregroundColor(.green)
                                .font(.system(size: screenHeight * 0.03))
                                .fontWeight(.bold)
                            
                            Spacer()
                            
                            NavigationLink(destination: SettingsView(profile: profileViewModel).environmentObject(sessionStore), isActive: $shouldPresentSettings) {
                                Button(action: {
                                    shouldPresentSettings = true
                                }, label: {
                                    Image(systemName: "slider.vertical.3")
                                        .resizable()
                                        .aspectRatio(contentMode: .fit)
                                })
                                .frame(width: screenWidth * 0.12, height: screenHeight * 0.04)
                                .foregroundColor(colorScheme == .dark ? .white : .black)
                            }
                        }
                        .padding(.top, screenHeight * 0.02)
                        
                        HStack {
                            Text(profileViewModel.profile!.username)
                                .foregroundColor(Color(uiColor: UIColor.lightGray))
                            Spacer()
                        }
                        
                        Spacer()
                    }
                }
                .padding()
                
                VStack {
                    Text("Level 1")
                        .font(.system(size: screenHeight * 0.03))
                        .fontWeight(.bold)
                    
                    RoundedRectangle(cornerRadius: 25)
                        .frame(width: screenWidth * 0.9)
                        .padding()
                        .overlay(
                            HStack {
                                RoundedRectangle(cornerRadius: 25)
                                    .foregroundColor(.green)
                                    .padding()
                                    .frame(width: screenWidth * 0.7)
                                
                                Spacer()
                            }
                        )
                        .shadow(color: .gray, radius: 7)
                    
                    Text("7 / 10 Workouts")
                }
                
                Spacer()
            }
            .sheet(isPresented: $shouldPresentImagePicker) {
                ImagePicker(sourceType: self.shouldPresentCamera ? .camera : .photoLibrary, selectedImage: self.$image)
                    .onDisappear {
                        profileViewModel.uploadPhoto(image: image)
                    }
            }
            .actionSheet(isPresented: $shouldPresentAddActionSheet) {
                ActionSheet(title: Text("Add a new photo"), message: nil, buttons: [
                    .default(Text("Take a new photo"), action: {
                         self.shouldPresentImagePicker = true
                         self.shouldPresentCamera = true
                     }),
                    .default(Text("Upload a new photo"), action: {
                         self.shouldPresentImagePicker = true
                         self.shouldPresentCamera = false
                     }),
                    ActionSheet.Button.cancel()
                ])
            }
        }
    }
}

设置视图:

import SwiftUI

struct SettingsView: View {
    @ObservedObject private var profileViewModel: ProfileViewModel
    
    @StateObject private var sheetManager = SheetManager()
    @State private var shouldPresentActionSheet = false
    
    @Environment(\.dismiss) var dismiss
    
    private class SheetManager: ObservableObject {
        enum Sheet {
            case email
            case password
            case logout
            case signout
        }
        
        @Published var showSheet = false
        @Published var whichSheet: Sheet? = nil
    }
    
    
    init(profile: ProfileViewModel) {
        self.profileViewModel = profile
    }
    
    var body: some View {
        GeometryReader { geometry in
            let screenWidth = geometry.size.width
            let screenHeight = geometry.size.height
            
                
            Form {
                Section(header: Text("Chats")) {
                    Toggle(isOn: .constant(false), label: {
                        Text("Hide my activity status")
                    })
                }
                
                Section(header: Text("Account")) {
                    Button(action: {
                        sheetManager.whichSheet = .email
                        sheetManager.showSheet.toggle()
                    }, label: {
                        Text("Change e-mail address")
                    })
                    
                    Button(action: {
                        sheetManager.whichSheet = .password
                        sheetManager.showSheet.toggle()
                    }, label: {
                        Text("Change password")
                    })
                    
                    Button(action: {
                        sheetManager.whichSheet = .logout
                        shouldPresentActionSheet = true
                    }, label: {
                        Text("Logout")
                            .foregroundColor(.red)
                    })
                    
                    Button(action: {
                        sheetManager.whichSheet = .signout
                        shouldPresentActionSheet = true
                    }, label: {
                        Text("Delete account")
                            .foregroundColor(.red)
                    })
                }
                
                Section(header: Text("Additional")) {
                    Label("Follow me on GitHub:", systemImage: "link")
                        .font(.system(size: 17, weight: .semibold))
                    Link("@Vader20FF", destination: URL(string: "https://github.com/Vader20FF")!)
                        .font(.system(size: 17, weight: .semibold))
                }
            }
            .navigationBarTitle("Settings")
            .navigationBarTitleDisplayMode(.large)
            
            .sheet(isPresented: $sheetManager.showSheet) {
                switch sheetManager.whichSheet {
                case .email:
                    ChangeEmailAddressSheetView(profile: profileViewModel)
                case .password:
                    ChangePasswordSheetView(profile: profileViewModel)
                case .signout:
                    DeleteAccountSheetView(profile: profileViewModel)
                default:
                    Text("No view")
                }
            }
            .confirmationDialog(sheetManager.whichSheet == .logout ? "Are you sure you want to logout?" : "Are you sure you want to delete your account? All data will be lost.", isPresented: $shouldPresentActionSheet, titleVisibility: .visible) {
                if sheetManager.whichSheet == .logout {
                    Button("Logout", role: .destructive) {
                        profileViewModel.sessionStore!.signOut()
                        dismiss()
                    }
                    Button("Cancel", role: .cancel) {}
                } else {
                    Button("Delete Account", role: .destructive) {
                        sheetManager.showSheet.toggle()
                    }
                    Button("Cancel", role: .cancel) {}
                }
            }
        }
    }
}

struct DeleteAccountSheetView: View {
    @ObservedObject private var profileViewModel: ProfileViewModel
    @Environment(\.dismiss) var dismiss
    
    @State private var email = ""
    @State private var password = ""
    
    init(profile: ProfileViewModel) {
        self.profileViewModel = profile
    }
    
    var body: some View {
        GeometryReader { geometry in
            let screenWidth = geometry.size.width
            let screenHeight = geometry.size.height
        
            NavigationView {
                VStack {
                    Form {
                        Section(footer: Text("Before you delete your account please provide your login credentials to confirm it is really you.")) {
                            TextField("E-mail", text: $email)
                            SecureField("Password", text: $password)
                        }
                    }
                    
                    Button(action: {
                        withAnimation {
                            dismiss()
                            profileViewModel.deleteUserData() {
                                profileViewModel.sessionStore!.deleteUser(email: email, password: password) {
                                    print("Successfully deleted user.")
                                }
                            }
                        }
                    }, label: {
                        Text("Delete account permanently")
                    })
                    .frame(width: screenWidth * 0.7, height: screenHeight * 0.08)
                    .background(Color.green)
                    .cornerRadius(15.0)
                    .font(.system(size: screenHeight * 0.026))
                    .foregroundColor(.white)
                    .padding()
                }
                .navigationBarHidden(true)
                .ignoresSafeArea(.keyboard)
            }
        }
    }
}


struct ChangeEmailAddressSheetView: View {
    @ObservedObject private var profileViewModel: ProfileViewModel
    @Environment(\.dismiss) var dismiss
    
    @State private var oldEmail = ""
    @State private var password = ""
    @State private var newEmail = ""
    
    init(profile: ProfileViewModel) {
        self.profileViewModel = profile
    }
    
    var body: some View {
        GeometryReader { geometry in
            let screenWidth = geometry.size.width
            let screenHeight = geometry.size.height
        
            NavigationView {
                VStack {
                    Form {
                        Section(footer: Text("Before you change your e-mail address please provide your login credentials to confirm it is really you.")) {
                            TextField("Old e-mail address", text: $oldEmail)
                            SecureField("Password", text: $password)
                            TextField("New e-mail address", text: $newEmail)
                        }
                    }
                    
                    Button(action: {
                        withAnimation {
                            dismiss()
                            profileViewModel.emailAddressChange(oldEmailAddress: oldEmail, password: password, newEmailAddress: newEmail) {}
                        }
                    }, label: {
                        Text("Change e-mail address")
                    })
                    .frame(width: screenWidth * 0.7, height: screenHeight * 0.08)
                    .background(Color.green)
                    .cornerRadius(15.0)
                    .font(.system(size: screenHeight * 0.026))
                    .foregroundColor(.white)
                    .padding()
                }
                .navigationBarHidden(true)
                .ignoresSafeArea(.keyboard)
            }
        }
    }
}


struct ChangePasswordSheetView: View {
    @ObservedObject private var profileViewModel: ProfileViewModel
    @Environment(\.dismiss) var dismiss
    
    @State private var email = ""
    @State private var oldPassword = ""
    @State private var newPassword = ""
    
    init(profile: ProfileViewModel) {
        self.profileViewModel = profile
    }
    
    var body: some View {
        GeometryReader { geometry in
            let screenWidth = geometry.size.width
            let screenHeight = geometry.size.height
        
            NavigationView {
                VStack {
                    Form {
                        Section(footer: Text("Before you change your password please provide your login credentials to confirm it is really you.")) {
                            TextField("E-mail", text: $email)
                            SecureField("Old password", text: $oldPassword)
                            SecureField("New password", text: $newPassword)
                        }
                    }
                    
                    Button(action: {
                        withAnimation {
                            dismiss()
                            profileViewModel.passwordChange(emailAddress: email, oldPassword: oldPassword, newPassword: newPassword) {}
                        }
                    }, label: {
                        Text("Change password")
                    })
                    .frame(width: screenWidth * 0.7, height: screenHeight * 0.08)
                    .background(Color.green)
                    .cornerRadius(15.0)
                    .font(.system(size: screenHeight * 0.026))
                    .foregroundColor(.white)
                    .padding()
                }
                .navigationBarHidden(true)
                .ignoresSafeArea(.keyboard)
            }
        }
    }
}

ProfileViewModel:


import Foundation
import SwiftUI

@MainActor
class ProfileViewModel: ObservableObject {
    @Published var sessionStore: SessionStore?
    private let firestoreManager = FirestoreManager()
    private let firebaseStorageManager = FirebaseStorageManager()
    
    @Published var profile: Profile?
    @Published var profilePicturePhotoURL: URL?
    
    @Published var fetchingData = true
    
    init(forPreviews: Bool) {
        self.profile = Profile(id: "sessionStore!.currentUser!.uid", firstName: "firstname", username: "username", birthDate: Date(), age: 18, country: "country", city: "city", language: "language", gender: "gender", email: "email", profilePictureURL: nil)
    }
    
    init() {
        Task {
            try await fetchData()
        }
    }
    
    func setup(sessionStore: SessionStore) {
        self.sessionStore = sessionStore
    }
    
    func fetchData() async throws {
        if sessionStore != nil {
            if sessionStore!.currentUser != nil {
                print("Fetching Data")
                fetchingData = true
                
                let (firstname, username, birthDate, age, country, city, language, gender, email, profilePictureURL) = try await self.firestoreManager.fetchDataForProfileViewModel(userID: sessionStore!.currentUser!.uid)
                
                self.profile = Profile(id: sessionStore!.currentUser!.uid, firstName: firstname, username: username, birthDate: birthDate, age: age, country: country, city: city, language: language, gender: gender, email: email, profilePictureURL: profilePictureURL)
                
                if profilePictureURL != nil {
                    self.firebaseStorageManager.getDownloadURLForImage(stringURL: profilePictureURL!, userID: sessionStore!.currentUser!.uid) { photoURL in
                         self.profilePicturePhotoURL = photoURL
                    }
                }
                
                Task {
                    fetchingData = false
                }
            }
        } else {
            fetchingData = false
        }
    }
    
    func uploadPhoto(image: UIImage) {
        if self.profile!.profilePictureURL != nil {
            Task {
                try await self.firebaseStorageManager.deleteImageFromStorage(userPhotoURL: self.profile!.profilePictureURL!, userID: self.profile!.id)
            }
        }
        
        self.firebaseStorageManager.uploadImageToStorage(image: image, userID: self.profile!.id) { photoURL in
            self.firestoreManager.addProfilePictureURLToUsersData(photoURL: photoURL) {
                Task {
                    try await self.fetchData()
                }
            }
        }
    }
    
    func emailAddressChange(oldEmailAddress: String, password: String, newEmailAddress: String, completion: @escaping (() -> ())) {
        self.sessionStore!.changeEmailAddress(oldEmailAddress: oldEmailAddress, password: password, newEmailAddress: newEmailAddress) {
            print("Successfully changed user's e-mail address")
        }
    }
    
    func passwordChange(emailAddress: String, oldPassword: String, newPassword: String, completion: @escaping (() -> ())) {
        self.sessionStore!.changePassword(emailAddress: emailAddress, oldPassword: oldPassword, newPassword: newPassword) {
            print("Successfully changed user's password")
        }
    }
    
    func deleteUserData(completion: @escaping (() -> ())) {
        if self.profile!.profilePictureURL != nil {
            self.firestoreManager.deleteUserData(userUID: sessionStore!.currentUser!.uid) {
                print("Successfully deleted user data")
                Task {
                    try await self.firebaseStorageManager.deleteImageFromStorage(userPhotoURL: self.profile!.profilePictureURL!, userID: self.sessionStore!.currentUser!.uid)
                    completion()
                }
            }
        }
    }
}

配置文件模型:

import Foundation
import SwiftUI

struct Profile: Codable, Identifiable {
    var id: String
    var firstName: String
    var username: String
    var birthDate: Date
    var age: Int
    var country: String
    var city: String
    var language: String
    var gender: String
    var email: String
    var profilePictureURL: String?
}
iOS SwiftUI null UISiteDelegate

评论


答: 暂无答案