I have a custom struct Information. for the property image(string) I want to insert the path of the document directory where the image is saved. When i try to use the UserDefaults to save the struct array, it is saved successfully and also retrieved. But when i use the path to retrieve the image from the document directory it shows the following error: fatal error: unexpectedly found nil while unwrapping an Optional value. And when I use the if-else block to catch the exception, No image is displayed on the tableview. Below is my code:
struct Information{
var image : String
var content : String?
var url : String?
init(image:String,content:String?,url:String?){
self.image = image
self.content = content
self.url = url
}
init(dictionary : [String:String]) {
self.image = dictionary["image"]!
self.content = dictionary["content"]!
self.url = dictionary["url"]!
}
var dictionaryRepresentation : [String:String] {
return ["image" : image, "content" : content!, "url" : url!]
}
} And my View Controller:
override func viewDidAppear(_ animated: Bool) {
savePath()
loadDefaults()
tableView.reloadData()
}
func saveDefaults()
{
let cfcpArray = information.map{ $0.dictionaryRepresentation }
UserDefaults.standard.set(cfcpArray, forKey: "cfcpArray")
}
func loadDefaults()
{
information = (UserDefaults.standard.object(forKey: "cfcpArray") as! [[String:String]]).map{ Information(dictionary:$0) }
for info in information{
print(info)
}
}
func savePath(){
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
// Get the Document directory path
let documentDirectorPath:String = paths[0]
// Create a new path for the new images folder
imagesDirectoryPath = documentDirectorPath + "/ImagePicker"
var objcBool:ObjCBool = true
let isExist = FileManager.default.fileExists(atPath: imagesDirectoryPath, isDirectory: &objcBool)
// If the folder with the given path doesn't exist already, create it
if isExist == false{
do{
try FileManager.default.createDirectory(atPath: imagesDirectoryPath, withIntermediateDirectories: true, attributes: nil)
}catch{
print("Something went wrong while creating a new folder")
}
}
tableView.reloadData()
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the edited.
guard let selectedImage = info[UIImagePickerControllerEditedImage] as? UIImage
else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
image = selectedImage
dismiss(animated: true, completion: nil)
saveImage()
}
func saveImage(){
// Save image to Document directory
var imagePath = Date().description
imagePath = imagePath.replacingOccurrences(of: " ", with: "")
imagePath = imagesDirectoryPath + "/\(imagePath).png"
path = imagePath
// print(path!)
let data = UIImagePNGRepresentation(image)
let success = FileManager.default.createFile(atPath:path!, contents: data, attributes: nil)
information.append(Information(image:path!, content:" ", url: " "))
saveDefaults()
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "TableViewCell"
/*Because you created a custom cell class that you want to use, downcast the type of the cell to your custom cell subclass, MealTableViewCell.*/
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier , for: indexPath) as? TableViewCell
else{
fatalError("The dequeued cell is not an instance of MealTableViewCell.")
}
let info = information[indexPath.row]
if let data = FileManager.default.contents(atPath: info.image)
{
let decodeimage = UIImage(data: data)
cell.photos.image = decodeimage
}
else{
print("Not displaying image")
}
// cell.photos.image = UIImage(data: data!)
return cell
}
Any suggestions is really appreciated. Thank you.