Swift iOS -UIImagePicker's Photo Library Is Presented On Simulator But Crashes (won't present) On Actual Device While Running Xcode

淺唱寂寞╮ 提交于 2019-12-10 17:13:16

问题


I'm on Swift 3, iOS 10.3, and Xcode 8.3.3.

When I access the photo library on the simulator the UIImagePicker is presented with no problem and I can pick photos. As soon as I try to access the photo library on an actual device (iPhone 7+) the app crashes because the UIImagePicker won't get presented (I don't even get to the point to pick a photo). The odd thing is on an actual device the imagePicker presents the camera and I can take photos with no problem.

Even though I didn't add it inside this question, inside my actual code I have the api permissions running. Inside my actual code I used them and commented them out and the problem still occurs:

import AVFoundation

//there is way more code then this I just put these here to show that I'm using them
PHPhotoLibrary.authorizationStatus()
PHPhotoLibrary.requestAuthorization()
AVCaptureDevice.authorizationStatus(forMediaType: ...)
AVCaptureDevice.requestAccess(forMediaType: ...)

UPDATE: I still haven't resolved the issue but I have found out some more information. I kept playing around with the app and I tried the app again after a crash and it let me access the library. What I came to realize is the app will let me access the library on the phone as long as Xcode isn't running. As soon as I plug the phone back into Xcode and try to access the library again I get a crash. I don't know what to make of that.

As long as Xcode ISN'T hooked up to the device I can successfully obtain photos from the libary. With the simulator I have no problems obtaining photos. With the device NOT hooked up to Xcode I can obtain photos. However once the device and Xcode are connected I get a crash. I've tried initializing the UIImagePicker 3 different ways (as stated below) to see if either of them would change the outcome but it's always the same. My app as over 100 classes and 50 vcs, maybe the problem is happening somewhere else. However if it was happening somewhere else then it should crash when Xcode ISN'T hooked up to the device either.

Inside the classes that use the UIImagepicker I commented out all the unnecessary code and focused only on the library and camera buttons. The crash always happens once the device and Xcode are intertwined. The good thing is once their not connected I can access the library so the users won't have a problem because they'll never have Xcode running with my app.

It should be noted that when the device and Xcode are hooked up I can use the camera and successfully take pics. The problem seems to be regulated to the library.

I've seen this question asked several times but the answer is always

"the permissions inside your info.plist have to be set"

In my situation the permissions are set inside the info.plist:

Here is a pic of the Switch that is set to "on" inside the simulator's Settings page. I couldn't take a photo of the actual device's Setting's page but on there both the Camera and Photos Switches are set to "on"

My code:

MyController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{ 

fileprivate var imagePicker = UIImagePickerController()

override func viewDidLoad() {
        super.viewDidLoad()

        imagePicker.delegate = self
}

@IBAction fileprivate func libraryButton(_ sender: UIButton){

        self.imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
        self.imagePicker.allowsEditing = false
        presentViewController(self.imagePicker, animated: true, completion: nil)
 }

@IBAction fileprivate func cameraButton(_ sender: UIButton){

        self.imagePicker.sourceType = UIImagePickerControllerSourceType.camera
        self.imagePicker.allowsEditing = false
        present(self.imagePicker, animated: true, completion: nil)
 }

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

        if let myImage = info[UIImagePickerControllerOriginalImage] as? UIImage{
            imageView.image = myImage
        }
        else if let myImage = info[UIImagePickerControllerEditedImage] as? UIImage{
            imageView.image = myImage
        }
        else{"UIImagePicker Problem")
        }

        imagePicker.dismiss(animated: true, completion: nil)
    }

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    imagePicker.dismiss(animated: true, completion: nil)
}
}
}

I also tried:

fileprivate var imagePicker:UIImagePickerController?

@IBAction fileprivate func libraryButton(_ sender: UIButton){

        self.imagePicker = UIImagePickerController()
        self.imagePicker?.delegate = self
        self.imagePicker?.sourceType = UIImagePickerControllerSourceType.photoLibrary
        self.imagePicker?.allowsEditing = false
        present(self.imagePicker!, animated: true, completion: nil)
 }

@IBAction fileprivate func cameraButton(_ sender: UIButton){

        self.imagePicker = UIImagePickerController()
        self.imagePicker?.delegate = self
        self.imagePicker?.sourceType = UIImagePickerControllerSourceType.camera
        self.imagePicker?.allowsEditing = false
        present(self.imagePicker!, animated: true, completion: nil)
 }

I also tried:

fileprivate let imagePicker:UIImagePickerController?

override func viewDidLoad() {
        super.viewDidLoad()

        imagePicker = UIImagePickerController()
        imagePicker!.delegate = self
}


@IBAction fileprivate func libraryButton(_ sender: UIButton){

        imagePicker!.sourceType = UIImagePickerControllerSourceType.photoLibrary
        imagePicker!.allowsEditing = false
        present(imagePicker!, animated: true, completion: nil)
 }

@IBAction fileprivate func cameraButton(_ sender: UIButton){

        imagePicker!.sourceType = UIImagePickerControllerSourceType.camera
        imagePicker!.allowsEditing = false
        present(imagePicker!, animated: true, completion: nil)
 }

This is the same crash info I keep getting once the device and Xcode are hooked up:

libc++abi.dylib`__cxa_throw:
->  0x18fd96e70 <+0>:   stp    x22, x21, [sp, #-0x30]!
    0x18fd96e74 <+4>:   stp    x20, x19, [sp, #0x10]
    0x18fd96e78 <+8>:   stp    x29, x30, [sp, #0x20]
    0x18fd96e7c <+12>:  add    x29, sp, #0x20            ; =0x20 
    0x18fd96e80 <+16>:  mov    x19, x2
    0x18fd96e84 <+20>:  mov    x20, x1
    0x18fd96e88 <+24>:  mov    x21, x0
    0x18fd96e8c <+28>:  bl     0x18fd96a88               ; __cxa_get_globals
    0x18fd96e90 <+32>:  mov    x22, x0
    0x18fd96e94 <+36>:  bl     0x18fd9756c               ; std::get_unexpected()
    0x18fd96e98 <+40>:  stur   x0, [x21, #-0x60]
    0x18fd96e9c <+44>:  bl     0x18fd975ac               ; std::get_terminate()
    0x18fd96ea0 <+48>:  stur   x0, [x21, #-0x58]
    0x18fd96ea4 <+52>:  stp    x20, x19, [x21, #-0x70]
    0x18fd96ea8 <+56>:  mov    x8, #0x434c000000000000
    0x18fd96eac <+60>:  movk   x8, #0x4e47, lsl #32
    0x18fd96eb0 <+64>:  movk   x8, #0x432b, lsl #16
    0x18fd96eb4 <+68>:  movk   x8, #0x2b00
    0x18fd96eb8 <+72>:  mov    x19, x21
    0x18fd96ebc <+76>:  str    x8, [x19, #-0x20]!
    0x18fd96ec0 <+80>:  orr    w8, wzr, #0x1
    0x18fd96ec4 <+84>:  stur   x8, [x19, #-0x58]
    0x18fd96ec8 <+88>:  ldr    w8, [x22, #0x8]
    0x18fd96ecc <+92>:  add    w8, w8, #0x1              ; =0x1 
    0x18fd96ed0 <+96>:  str    w8, [x22, #0x8]
    0x18fd96ed4 <+100>: adrp   x8, 0
    0x18fd96ed8 <+104>: add    x8, x8, #0xef8            ; =0xef8 
    0x18fd96edc <+108>: str    x8, [x19, #0x8]
    0x18fd96ee0 <+112>: mov    x0, x19
    0x18fd96ee4 <+116>: bl     0x190433be4               ; _Unwind_RaiseException
    0x18fd96ee8 <+120>: mov    x0, x19
    0x18fd96eec <+124>: bl     0x18fd96f20               ; __cxa_begin_catch
    0x18fd96ef0 <+128>: ldur   x0, [x21, #-0x58]
    0x18fd96ef4 <+132>: bl     0x18fd975c4               ; std::__terminate(void (*)())

I don't have an Unwind Segue anywhere in my project so I'm unsure of why it says that. But regardless if it works on the simulator it should work on the phone or if it doesn't work on the phone then it shouldn't work on the simulator either. Below here is a snippet of the crash report and stack trace.

Bug Report:

I deleted the app from the device, shut down Xcode, relaunched it, accepted ok to give it access to the library, and same problem.

Any idea of what the problem is?


回答1:


Ash Furrow helped me out with this as it was a very non obvious problem and possibly an api bug. I posted pics for people unfamiliar with the process to resolve it.

It turns out inside the Breakpoint Navigator I had All Exceptions activated. For some reason when my app was hooked up to Xcode and the UIImagePicker was presenting the photo library, the All Exceptions breakpoint was triggered and there was a slight delay that caused the app to crash. The delay was milliseconds but it was long enough that the app thought that there was a problem. Ash said he never saw anything like that before and said there was possibly a corrupted jpg photo in my photo library but then again it was a wild guess. The simple solution was to deactivate or delete the All Exceptions breakpoint and the problem was resolved. He did say it was possibly an api problem because it was still causing a very odd crash.

It should be noted that he said that All Exceptions break point is good to keep activated because it will find exceptions earlier then later. I forgot his explanation in detail but basically it's best to keep it on and if you run into this problem just deactivate it.

Steps to resolve the UIImagePicker library presentation crash by deactivating the All Exceptions breakpoint:

  1. On the left side of the screen in the navigation pane, the 7th icon from the left that looks like an arrow is the Breakpoint Navigator

  1. The All Exceptions breakpoint is activated/highlighted to blue

  2. To deactivate the ALL Exceptions either click the highlighted blue arrow or right click on the word All Exceptions itself and from the list either choose Disable or Delete

  1. Assuming you either choose Disable or you click the blue arrow, it will be deactivated

  1. Obviously if you choose delete it will be erased form the Breakpoint navigator but if you want to add it again (or if you never had it to begin with) then you still have to be inside the Breakpoint Navigator (step 1) and in the lower left corner of the pane you press the plus button and choose Exception Breakpoint to add it.




回答2:


Try using below code works perfectly for me

  @IBAction func openLibraryButtonAction(_ sender: Any) {


        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary) {
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary;
            imagePicker.allowsEditing = true
            self.present(imagePicker, animated: true, completion: nil)
        }

    }


 @IBAction func takePhotoButtonAction(_ sender: Any)
{

    if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)
    {
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = UIImagePickerControllerSourceType.camera;
        imagePicker.allowsEditing = false
        self.present(imagePicker, animated: true, completion: nil)
    }
    else
    {
        noCamera() //Calling alert of No Camera
    }
}


func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
    {
        chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
dismiss(animated:true, completion: nil)
}



回答3:


I'm going to justify some suggestions and then paste the resulting snippet.

  • Make sure you inherit from UIViewController in order to use methods like viewDidLoad()
  • imagePicker is set at init, so remove any question marks or if let chaining.
  • For consistency, just remove any 'self.' that are not necessary
  • Move any redundant setup to viewDidLoad()

    class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    fileprivate let imagePicker = UIImagePickerController()
    
    override func viewDidLoad() {
    super.viewDidLoad()
    
      imagePicker.delegate = self
      imagePicker.allowsEditing = false
    }
    
    @IBAction fileprivate func libraryButton(_ sender: UIButton) {
    
      imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
      present(imagePicker, animated: true, completion: nil)
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    
      if let myImage = info[UIImagePickerControllerOriginalImage] as? UIImage{
        //original image
      }
      else if let myImage = info[UIImagePickerControllerEditedImage] as? UIImage{
        //edited image
      }
      else{
        print("image picker problem")
      }
    
      imagePicker.dismiss(animated: true, completion: nil)
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    
      imagePicker.dismiss(animated: true, completion: nil)
    }
    
      }
    

With these changes you should be good.




回答4:


You have to explicitly request an access to image library which uses the UIImagePicker.

For instance PHPhotoLibrary.requestAuthorization




回答5:


The problem in your code is UIImagePickerControllerSourceType.PhotoLibrary, the photo library is change to .photoLibrary p should be in small letter



来源:https://stackoverflow.com/questions/45789485/swift-ios-uiimagepickers-photo-library-is-presented-on-simulator-but-crashes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!