Could someone help me understand why my "users" array is coming back empty after I add a "User" to it? Through various print statements, I have come to the conclusion that when I press "save", an instance of "User" is created and appended to the array of Users, however once the sheet is closed, nothing appears in my list and I am back to having an empty array. Also, I know that I say to send back an empty array in my Content View initializer catch statement, however I have tested this, and the catch statement is actually not the reason the array is empty (the do block is not causing any errors).
Also, I know I need to put much of this into separate ViewModels, however I was just planning on moving everything over once I got it working. I also know that there are one or two unrelated mistakes in the code; I was just going to fix those once I figured this out.
Thanks!
Content View:
struct ContentView: View {
@State private var pic: Image?
@State private var users = [User]()
let savePath = FileManager.documentsDirectory.appendingPathComponent("SavedUsers")
@State private var showingAddNewUser = false
var body: some View {
NavigationView {
List {
Section("Users") {
ForEach(users, id:\.name) { user in
HStack {
pic?
.resizable()
.scaledToFit()
.frame(width: 100, height: 100)
Text(user.name)
.font(.headline).fontWeight(.semibold)
}
}
}
}
.navigationTitle("iFace")
.toolbar {
Button {
showingAddNewUser = true
} label: {
Image(systemName: "plus")
}
}
.sheet(isPresented: $showingAddNewUser) {
AddUserView(users: users)
}
}
}
init() {
do {
let userData = try Data(contentsOf: savePath)
users = try JSONDecoder().decode([User].self, from: userData)
for user in users {
let dataPic = user.pic
let uiPic = UIImage(data: dataPic)
self.pic = Image(uiImage: uiPic!)
}
print(users)
} catch {
print(error)
users = []
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
AddUser:
struct AddUserView: View {
@State private var pic: Image?
@State private var name = ""
@State private var showingImagePicker = false
@State private var inputImage: UIImage?
@State var users: [User]
@Environment(\.dismiss) var dismiss
let savePath = FileManager.documentsDirectory.appendingPathComponent("SavedUsers")
var body: some View {
NavigationView {
Form {
Section {
TextField("Name", text: $name)
}
Section {
ZStack {
Rectangle()
.fill(.white)
.frame(width: 350, height: 350)
Text("Please Select an Image")
.fontWeight(.semibold)
pic?
.resizable()
.scaledToFit()
.frame(maxWidth: 350, maxHeight: 350)
}
.onTapGesture {
showingImagePicker = true
}
}
}
.navigationBarTitle("Add")
.toolbar {
Button("Save") {
save()
dismiss()
}
}
}
.sheet(isPresented: $showingImagePicker) {
ImagePicker(image: $inputImage)
}
.onChange(of: inputImage) { _ in loadImage() }
}
func loadImage() {
guard let inputImage = inputImage else { return }
let img = Image(uiImage: inputImage)
pic = img
}
func save() {
do {
if let jpegData = inputImage?.jpegData(compressionQuality: 0.8) {
let newUser = User(id: UUID(), name: name, pic: jpegData)
users.append(newUser)
print(newUser)
let userData = try JSONEncoder().encode(users)
try userData.write(to: savePath, options: [.atomicWrite, .completeFileProtection])
}
print("encoding successful")
print(users)
} catch {
print("encoding error")
}
print(users.count)
}
}
ImagePicker:
struct ImagePicker: UIViewControllerRepresentable {
@Binding var image: UIImage?
class Coordinator: NSObject, PHPickerViewControllerDelegate {
var parent: ImagePicker
init(parent: ImagePicker) {
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
guard let provider = results.first?.itemProvider else { return }
if provider.canLoadObject(ofClass: UIImage.self) {
provider.loadObject(ofClass: UIImage.self) { image, _ in
self.parent.image = image as? UIImage
}
}
}
}
func makeUIViewController(context: Context) -> PHPickerViewController {
var config = PHPickerConfiguration()
config.filter = .images
let picker = PHPickerViewController(configuration: config)
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
}
AddUser:
struct User: Identifiable, Codable {
let id: UUID
let name: String
let pic: Data
}
extension User: Comparable {
static func <(lhs: User, rhs: User) -> Bool {
lhs.name < rhs.name
}
}
FileManager Ext:
extension FileManager {
static var documentsDirectory: URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
}