0

I have saved my camera captured photo to Photos and then trying to access it. I am able to successfully save it using PHPhotoLibrary and once saved I get a path like this file:///var/mobile/Media/DCIM/100APPLE/IMG_0048.JPG. Now I need to load this path inside an UIImageView

I tried the below code

let data = try! Data(contentsOf: URL(fileURLWithPath: "file:///var/mobile/Media/DCIM/100APPLE/IMG_0048.JPG"))
let image = UIImage(data: data)
imageView.image = image

but my app crash saying

Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=260 "The file “IMG_0048.JPG” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/file:/var/mobile/Media/DCIM/100APPLE/IMG_0048.JPG, NSUnderlyingError=0x280c545a0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

I tried using kingfisher library but it does not load the image as well using imageView.kf.setImage(with: URL(fileURLWithPath: imageUrl)) but image is not getting displayed

Another way which I tried was using below code, I am extracting image name from the path and then sending to load function

var documentsUrl: URL {
        return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    }
    
    private func load(fileName: String) -> UIImage? {
        let fileURL = documentsUrl.appendingPathComponent(fileName)
        do {
            let imageData = try Data(contentsOf: fileURL)
            return UIImage(data: imageData)
        } catch {
            print("Error loading image : \(error)")
        }
        return nil
    }

and then using

imageView.image = load(fileName: "IMG_0048.JPG") but it does not display the image as well

BraveEvidence
  • 53
  • 11
  • 45
  • 119
  • You had the image data before saving to Photos, so it's not neccessary to load it back I think – Quang Hà Apr 11 '23 at 09:32
  • I am capturing the image in separate view controller and displaying it in some other view controller. Sending Image data via view controller is bad practice so I am just sending the path as its lightweight as compared to data – BraveEvidence Apr 11 '23 at 09:42
  • It's not bad practice, it's faster than storing to disk and re-loading it to memory. Using delegate pattern you can transfer data between View Controllers. – Quang Hà Apr 11 '23 at 09:45
  • If you still want to 'store and load', you should write it to the App's Document folder. The path in the Document folder is accessible, whereas /var/mobile/ is non-accessible. – Quang Hà Apr 11 '23 at 09:48

1 Answers1

1

All of your approaches are wrong. They are requesting a local data using local url and your url is from Photos, which need to use PHPhotoLibrary. I assume you are using UIImagePickerController to take a photo, you can use PHAsset to request image data

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    let phAsset = info[.phAsset] as! PHAsset
    PHPhotoLibrary.requestAuthorization { status in
        if status == .authorized {
            let imageManager = PHImageManager.default()
            imageManager.requestImageData(for: phAsset, options: nil) { data, _, _, _ in
                let image = UIImage(data: data!)
                // Your image
            }
        } else {
            // Access to the photo library is not authorized.
        }
    }
}

As @JeremyP's answer, after save a photo, you should save the localId instead of fullSizeImageURL and use this code to retrieve the photo

func getPhotoInLibrary(localIdentifiers: String, completion: @escaping (UIImage?) -> Void) {
    let result = PHAsset.fetchAssets(withLocalIdentifiers: [localId], options: nil)
    guard let asset = result.firstObject else {
        completion(nil)
        return
    }
    PHImageManager.default().requestImageData(for: asset, options: nil) { data, _, _, _ in
        if let data = data {
            let image = UIImage(data: data)
            completion(image)
        } else {
            completion(nil)
        }
    }
}
  • This won't help me. I am not using UIImagePickerController as I need to customise the captured image from camera so I am using AVCapturePhotoOutput,AVCaptureSession etc and once image is captured I am using PHPhotoLibrary to save it to photos which works as well then I need to load the image to an image view which does not work – BraveEvidence Apr 11 '23 at 08:26
  • How can you get that url? @BraveEvidence – Kevin Nguyen Apr 11 '23 at 08:40
  • Check this https://stackoverflow.com/a/61504980/9552485 – BraveEvidence Apr 11 '23 at 08:59
  • @BraveEvidence in the code you linked `localId` is the id of the image in the Photo library. You can use that id to find its `PHAsset` instead of using the image picker. – JeremyP Apr 11 '23 at 09:13
  • requestImageData is deprecated in iOS 13 – BraveEvidence Apr 11 '23 at 09:58
  • you can use `func requestImage(for asset: PHAsset, targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?, resultHandler: @escaping (UIImage?, [AnyHashable : Any]?) -> Void) -> PHImageRequestID` @BraveEvidence – Kevin Nguyen Apr 11 '23 at 10:00