I am building a profile page and I am trying to make the profile picture save even after the user signs out. This is my user struct:
struct User: Codable {
var uid: String
var email: String
var firstName: String
var lastName: String
var signUpDate: Date
var bio: String
var interests: [String]
var profilePictureURL: URL?
}
This is my profile page view(the part that is causing the error):
struct ProfileView: View {
@ObservedObject var userViewModel: UserViewModel
@State private var bio = UserDefaults.standard.string(forKey: "bio") ?? "Car enthusiast | Eco-friendly driver | Developer"
@State private var interests = UserDefaults.standard.string(forKey: "interests") ?? "Travel, Coding, Green Living"
@State private var isEditingBio = false
@State private var isEditingInterests = false
@State private var isEditingProfile = false
@State private var selectedImage: UIImage? {
didSet {
if let selectedImage = selectedImage {
if let imageData = selectedImage.jpegData(compressionQuality: 0.8) {
UserDefaults.standard.set(imageData, forKey: "profileImage")
}
}
}
}
init(userViewModel: UserViewModel) {
self.userViewModel = userViewModel
if let imageData = UserDefaults.standard.data(forKey: "profileImage"),
let image = UIImage(data: imageData) {
_selectedImage = State(initialValue: image)
} else {
// Initialize with a default image if no profile image is found
_selectedImage = State(initialValue: UIImage(systemName: "person.circle.fill")!)
}
}
The error is occuring at the second init statement and the error is: Return from initializer without initializing all stored properties
I have tried looking at other solutions on stack overflow but I don't really understand them. I also tried initializing the other values by inputting a user:user parameter and then doing let uid=user.uid and so on and so forth for the other properties. I am confused on how to fix this. Thank you for any help!
Error show in second init
is because you are not intialize userViewModel
in it. So all you need to do is move code from second init
to init(userViewModel:
:
init(userViewModel: UserViewModel) {
self.userViewModel = userViewModel
if let imageData = UserDefaults.standard.data(forKey: "profileImage"),
let image = UIImage(data: imageData) {
_selectedImage = State(initialValue: image)
} else {
// Initialize with a default image if no profile image is found
_selectedImage = State(initialValue: UIImage(systemName: "person.circle.fill")!)
}
}
Also, you should use onChange
modifer to observe change of @State
instead of using didSet
. To interact with UserDefaults
in SwiftUI
you should use @AppStorage too.
struct ProfileView: View {
@ObservedObject var userViewModel: UserViewModel
@AppStorage("bio") private var bio: String = "Car enthusiast | Eco-friendly driver | Developer" // <- change to @AppStorage
@AppStorage("bio") private var interests: String = "Travel, Coding, Green Living" // <- change to @AppStorage
@State private var isEditingBio = false
@State private var isEditingInterests = false
@State private var isEditingProfile = false
@State private var selectedImage: UIImage?
init(userViewModel: UserViewModel) {
self.userViewModel = userViewModel
if let imageData = UserDefaults.standard.data(forKey: "profileImage"),
let image = UIImage(data: imageData) {
_selectedImage = State(initialValue: image)
} else {
// Initialize with a default image if no profile image is found
_selectedImage = State(initialValue: UIImage(systemName: "person.circle.fill")!)
}
}
var body: some View {
...
.onChange(of: selectedImage) { newValue in
if let selectedImage = newValue {
if let imageData = selectedImage.jpegData(compressionQuality: 0.8) {
UserDefaults.standard.set(imageData, forKey: "profileImage")
}
}
}
}
}