2

This is my first question, hope it won't be too stupid.

Here is my app:
VC1
VC2 - ChatTableViewController
VC3 - PopupPhotoSourceVC

VC1 - a button to present VC2 modally
VC2 - a "Bar" button to present VC3 modally (VC3 presentation set to "Over Current Context")
VC2 - set a unwind segue

@IBAction func unwindToChatTableViewController(segue: UIStoryboardSegue) {

    attachPhotoButtonFinish()
}

VC3 - two buttons on the middle, both set to above unwind segue by drag and select using StoryBoard.

Inside VC3, use prepare for segue to let VC2 knows what user choose

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let destChatViewController = segue.destination as! ChatTableViewController


    if segue.identifier == "library" // library Button
    {
        print("set cameraType to library from popupviewcontroller")
        let time = getCurrentTime()
        print("==== timer start ====== \(time.3):\(time.4):\(time.5)")

        destChatViewController.cameraType = "library"
    }
    else if segue.identifier == "newphoto" // newphoto Button
    {
        print("set cameraType to newphoto from popupviewcontroller")
        let time = getCurrentTime()
        print("==== timer start ====== \(time.3):\(time.4):\(time.5)")

        destChatViewController.cameraType = "newphoto"
    }

    // for unwind segue, no need to call dismiss
    print("not calling dismiss pop up")
    let time = getCurrentTime()
    print("==== timer start ====== \(time.3):\(time.4):\(time.5)")

    //dismiss(animated: true, completion: nil)
}

Inside VC2, attachPhotoButtonFinish will try to invoke image picker controller based on user's choice

func attachPhotoButtonFinish() {

    print("attachphotobutton start")
    let time = getCurrentTime()
    print("==== timer start ====== \(time.3):\(time.4):\(time.5)")


    let image = UIImagePickerController()
    image.delegate = self

    if cameraType == "library"{
        image.sourceType = UIImagePickerControllerSourceType.photoLibrary

    }
    else if cameraType == "newphoto"{
        image.sourceType = UIImagePickerControllerSourceType.camera
        image.cameraCaptureMode = .photo
    }
    else{
        print("Something wrong!!!")
        return
    }
    image.allowsEditing = false
    image.modalPresentationStyle = .overCurrentContext

    print("calling imagepicker")
    let time1 = getCurrentTime()
    print("==== timer start ====== \(time1.3):\(time1.4):\(time1.5)")

    self.present(image, animated: true, completion: nil)
}

And I also try to print deinit time of VC3

deinit{
    print("===== \(self.classForCoder.description()) be deinit")
    let time = getCurrentTime()
    print("==== timer start ====== \(time.3):\(time.4):\(time.5)")

}

About running result, sometimes (1 out of 10) VC3 finish before VC2 present image picker. So I can see it display correctly.

==== timer start ====== 18:34:58
not calling dismiss pop up
==== timer start ====== 18:34:58
Unwind to ChatTableViewController cameraType = library
==== timer start ====== 18:34:58
attachphotobutton start
==== timer start ====== 18:34:58
calling imagepicker
==== timer start ====== 18:34:58
===== PhotoStreamSourceTest.PopupPhotoSourceVC be deinit
==== timer start ====== 18:34:59
2017-09-20 18:34:59.274464+0800 PhotoStreamSourceTest[14690:399530] [AXRun-PID] Client requesting unsuspension of PID:14706 Name:
2017-09-20 18:34:59.283271+0800 PhotoStreamSourceTest[14690:399463] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /Users/_/Library/Developer/CoreSimulator/Devices/54B3F249-2C6A-4C18-B2E1-C7271199A7CF/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2017-09-20 18:34:59.284012+0800 PhotoStreamSourceTest[14690:399463] [MC] Reading from private effective user settings.

But most of time, I receive following result and image picker doesn't display.

==== timer start ====== 18:35:48
not calling dismiss pop up
==== timer start ====== 18:35:48
Unwind to ChatTableViewController cameraType = library
==== timer start ====== 18:35:48
attachphotobutton start
==== timer start ====== 18:35:48
calling imagepicker
==== timer start ====== 18:35:48
2017-09-20 18:35:48.967515+0800 PhotoStreamSourceTest[14690:400836] [AXRun-PID] Client requesting unsuspension of PID:14706 Name:
2017-09-20 18:35:49.049357+0800 PhotoStreamSourceTest[14690:399463] Warning: Attempt to present on while a presentation is in progress!
===== PhotoStreamSourceTest.PopupPhotoSourceVC be deinit
==== timer start ====== 18:35:49

Thank you!

Hungo
  • 31
  • 3
  • have a look at this [Meaning of Warning “while a presentation is in progress!”](https://stackoverflow.com/a/17120065/4056108) – chirag90 Sep 20 '17 at 10:58
  • 1
    @chirag90 Thank you for your prompt reply. I just wonder if unwind segue doesn’t suit for this scenario. Make sure VC3 is closed before calling image picker is definitely the rule. – Hungo Sep 20 '17 at 11:27
  • Sorry Mate, i was just helping with the warning – chirag90 Sep 20 '17 at 12:09

1 Answers1

1

Thanks to @chirag90 's link Meaning of Warning “while a presentation is in progress!

The key point is to use the completion block of dismiss method to make sure that VC3 is truly closed before we let VC2 to launch image picker.

Following solution use delegate instead of unwind segue. If anyone has other approach please let me know! Thank you!

First of all, on VC3, delete the unwind segue on both buttons from Storyboard. Then add IBAction on both buttons called libraryButtonPressed() and takePhotoButtonPressed()

On VC3:PopupPhotoSourceVC, add a protocol

protocol PopupPhotoSourceVCDelegate {
func finishPassing(string: String)}

On VC3 also add a delegate variable of that type

var delegate: PopupPhotoSourceVCDelegate?

Now on VC2, adopt the protocol

class ChatTableViewController: UITableViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, PopupPhotoSourceVCDelegate{

And implement the finishPassing function to obey the protocol

func finishPassing(string: String) {
    cameraType = string
    attachPhotoButtonFinish()
}

Don't forget to set delegate to self

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let destination = segue.destination as? PopupPhotoSourceVC{
        destination.delegate = self
    }
}

Now, back to VC3, let's implement the key methods

@IBAction func libraryButtonPressed(_ sender: UIButton) {
    dismiss(animated: true) {
        self.delegate?.finishPassing(string: "library")
    }

}
@IBAction func takePhotoButtonPressed(_ sender: UIButton) {
    dismiss(animated: true) {
        self.delegate?.finishPassing(string: "newphoto")
    }
}

These two methods will dismiss the VC3:PopupPhotoSourceVC and after dismiss is actually complete it then call finishPassing in VC2:ChatTableViewController to start launch image picker.

Hope this help, thanks.

Hungo
  • 31
  • 3