简体   繁体   中英

image picker/UIImagePickerController show blank screen/NavigationController swift 5

I am trying to get answer from this question answer link but failed:(

iOS UIImagePickerController showed blank page

Then I try below code but still show blank screen without image list:( I think don't fire the delegation function You can also check from GitHub

https://github.com/MdAshfaqurRahmanIOS/image-picker-3

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    var imagePicker = UIImagePickerController()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        imagePicker.delegate = self
    }
    @IBAction func buttonAction(_ sender: UIButton) {
        imagePicker.sourceType = .photoLibrary
        imagePicker.allowsEditing = true
        present(imagePicker, animated: true)
    }
}
extension ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let image = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerEditedImage")] as? UIImage {
            imageView.image = image
        }
        picker.dismiss(animated: true, completion: nil)
    }
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }
}

Add this info.plist
key =>>>> Privacy - Photo Library Usage value =>> please access photogallery

Console log

  • 2020-12-17 22:49:11.928762+0600 image-picker-3[1309:51223] [lifecycle] [u B37332A2-92E0-4D65-981B-0DBBDB4534D9:m (null)] [com.apple.mobileslideshow.photo-picker(1.0)] Connection to plugin interrupted while in use. 2020-12-17 22:49:11.944027+0600 image-picker-3[1309:51223] [lifecycle] [u B37332A2-92E0-4D65-981B-0DBBDB4534D9:m (null)] [com.apple.mobileslideshow.photo-picker(1.0)] Connection to plugin invalidated while in use. 2020-12-17 22:49:12.003410+0600 image-picker-3[1309:51015] UIImagePickerController UIViewController create error: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service on pid 0 named com.apple.mobileslideshow.photo-picker.viewservice was interrupted, but the message was sent over an additional proxy and therefore this proxy has become invalid." UserInfo={NSDebugDescription=The connection to service on pid 0 named com.apple.mobileslideshow.photo-picker.viewservice was interrupted, but the message was sent over an additional proxy and therefore this proxy has become invalid.}

在此处输入图像描述 在此处输入图像描述 在此处输入图像描述 在此处输入图像描述

Try to follow my programmatically example below, first add your button and delegates to your controller and import Photo framework:

import UIKit
import Photos

class YourViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

lazy var takePicButton: UIButton = {
    let button = UIButton()
    button.backgroundColor = .red
    button.setTitle("Present img picker", for: .normal)
    button.setTitleColor(.white, for: .normal)
    button.titleLabel?.font = .systemFont(ofSize: 16, weight: .semibold)
    button.layer.cornerRadius = 14
    button.clipsToBounds = true
    button.addTarget(self, action: #selector(handlepickPicture), for: .touchUpInside)
    button.translatesAutoresizingMaskIntoConstraints = false
    
    return button
}()

now in viewDidLoad add button and set constraints:

override func viewDidLoad() {
    super.viewDidLoad()
    
    view.addSubview(takePicButton)
    takePicButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20).isActive = true
    takePicButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20).isActive = true
    takePicButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20).isActive = true
    takePicButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
}

After that set your func to present image picker controller:

var imagePicker = UIImagePickerController()

@objc fileprivate func handlepickPicture() {
    
    imagePicker.delegate = self
    imagePicker.sourceType = .photoLibrary
    imagePicker.view.tintColor = .white
    imagePicker.mediaTypes = ["public.image"]
    imagePicker.allowsEditing = true
    imagePicker.navigationBar.barTintColor = .black
    
    checkPermission()
}

check the permission, don't forget to set your info.plist privacy usage description (like you):

fileprivate func checkPermission() {
    let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
    switch photoAuthorizationStatus {
    case .authorized:
        print("Add Photo")
        if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum){
            print("Access is granted by user")
            self.present(imagePicker, animated: true, completion: nil)
        }
        print("Access is granted by user")
    case .notDetermined:
        PHPhotoLibrary.requestAuthorization({
            (newStatus) in
            print("status is \(newStatus)")
            if newStatus ==  PHAuthorizationStatus.authorized {
                /* do stuff here */
                DispatchQueue.main.async {
                    self.present(self.imagePicker, animated: true, completion: nil)
                }
                print("success")
            }
        })
        print("It is not determined until now")
    case .restricted:
        // same same
        print("User do not have access to photo album.")
        goToSetting()
    case .denied:
        // same same
        print("Text tapped...")
        goToSetting()
        print("User has denied the permission.")
    case .limited:
        goToSetting() // the function show an alert to enable Authorization manually
        print("User has denied the permission.")
    @unknown default:
        fatalError()
    }
}

write the function to set authorization manually:

fileprivate func goToSetting() {
    let title = "Oooooops!"
    let message = "Hi man, for use this App press Go To settings and enabled access to Pohto Gallery... Check read and write option and relaunch the App!"
    
    let alertController = UIAlertController(title: "", message: "", preferredStyle: .alert)
    
    let subview = (alertController.view.subviews.first?.subviews.first?.subviews.first!)! as UIView
    subview.backgroundColor = UIColor(white: 0, alpha: 0.2)
    
    alertController.setValue(NSAttributedString(string: title, attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 18, weight: .heavy),NSAttributedString.Key.foregroundColor : UIColor.red]), forKey: "attributedTitle")
    alertController.setValue(NSAttributedString(string: message, attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 14, weight: .regular),NSAttributedString.Key.foregroundColor : UIColor.white]), forKey: "attributedMessage")
    
    let cancelAction = UIAlertAction(title: "Cancel", style: .destructive) { (_) in
        print("Action cancelled")
    }
    
    let goToSettingPermission = UIAlertAction(title: "Go To setting", style: .default) { (action) in
        UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
    }
    
    alertController.addAction(goToSettingPermission)
    alertController.addAction(cancelAction)
    
    self.present(alertController, animated: true, completion: {
    })
}

this is the result, on dx the alert for manual authorization, on left the picker controller

在此处输入图像描述

If you don't see the preview photos, try to run app with another simulator device.

You can use it by taking these photos into a collectionView like this "I've made it using RxSwift:

import UIKit
import RxSwift
import Foundation
import Photos

private let reuseIdentifier = "ImageCell"

class ImagesCollectionViewController: UICollectionViewController {
    
//MARK: - vars
private var images = [PHAsset]()
private var selectedPhotoSubject = PublishSubject<UIImage>()
var selectedPhoto: Observable<UIImage> {
    return selectedPhotoSubject.asObservable()
}

//MARK: - LifeCycle
override func viewDidLoad() {
    super.viewDidLoad()
    linkPhotosLibrary()
    self.title = "Pick an Image"
    
}
//MARK: - PhotoLibrary
private func linkPhotosLibrary() {
    PHPhotoLibrary.requestAuthorization { [weak self] status in
        if status == .authorized {
            
            let assets = PHAsset.fetchAssets(with: PHAssetMediaType.image,options: nil)
            assets.enumerateObjects { (object, count, stop) in
                self?.images.append(object)
            }
            self?.images.reverse()
            DispatchQueue.main.async {
            self?.collectionView.reloadData()
            }
        }
        
    }
}

// MARK: - UICollectionViewDataSource

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return images.count
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! ImageCell
    
    let asset = images[indexPath.row]
    let manager = PHImageManager.default()
    
    manager.requestImage(for: asset, targetSize: CGSize(width: 200,height: 200), contentMode: .aspectFit, options: nil) { image, _ in
        
        DispatchQueue.main.async {
            cell.imageViewOutlet.image = image
        }
    }
    
    return cell
}

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    
    let selectedAsset = images[indexPath.row]
    PHImageManager.default().requestImage(for: selectedAsset, targetSize: CGSize(width: 500, height: 500), contentMode: .aspectFit, options: nil) { [weak self] image , info in
        guard let info = info else {return}
        let isDegradedImage = info["PHImageResultIsDegradedKey"] as! Bool
        // as we will call this function 2 times one for the small image in the collection and one here that's why we use it as this will tell us if the image is thumbnail or original image
        if !isDegradedImage {
            
            if let image = image {
                self?.selectedPhotoSubject.onNext(image)
                self?.dismiss(animated: true, completion: nil)
            }
        }
        
    }
}

}

or you can use it normally:

    var myGallery: GalleryController!

    func showGalleryImages () {
        
        self.myGallery = GalleryController()
        self.myGallery.delegate = self
        Config.tabsToShow = [.imageTab, .cameraTab]
        Config.Camera.imageLimit = 100
        
        self.present(self.myGallery, animated: true, completion: nil)
        
    }
    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM