I'm trying to load an instance of UIImagePickerController from a custom subview. For some reason it doesn't work and keeps giving me:
<UIImagePickerController: 0x7fde7282bc00> on <UIViewController: 0x7fde6f507f00> whose view is not in the window hierarchy!
Here's a skeleton of what my code looks like:
View Controller
let subview = SubView()
// Subview params...
subview.parent = self
self.view.addSubview(subview)
Subview
class SubView: UIView, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
let imagePicker = UIImagePickerController()
var parent = UIViewController()
override func draw(_ rect: CGRect) {
imagePicker.delegate = self
let add = UIButton()
// add params...
add.addTarget(self, action: #selector(addImg(_:)), for: .touchUpInside)
self.addSubview(add)
}
func addImg(_ sender: UIButton) {
imagePicker.allowsEditing = false
imagePicker.sourceType = .photoLibrary
parent.present(imagePicker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
// Do stuff with image
}
}
}
Any ideas on how I can get this working?
You can get current rootController using UIApplication. This is my working code. It will find the rootController and check if it is type of UINavigationController or UIViewController
if let rootController = UIApplication.shared.keyWindow?.rootViewController {
if rootController is UINavigationController {
if let navigationController = rootController as? UINavigationController {
if let topViewController = navigationController.topViewController {
topViewController.present(alert, animated: true, completion: nil)
}
}
}
else {
// is a view controller
rootController.present(alert, animated: true, completion: nil)
}
}
Related
I try to present VCs but buttons in popover menu, but I have hierarchy warnings like this:
Warning: Attempt to present "UIViewController: 0x14def7500" on "MyProject.MainViewController: 0x14f976400" whose view is not in the window hierarchy!
I have MainViewController and PopupMenu VCs classes:
Swift 4.0
class MainViewController: UIViewController, UIPopoverPresentationControllerDelegate {
//... here is my VC code
// showing Popup Menu VC
#IBAction func showPopupMenu(sender: UIButton) {
menuVC = PopupMenu()
menuVC?.modalPresentationStyle = .popover
menuVC?.preferredContentSize = CGSize(width: 150, height: 250)
if let pvc = menuVC?.popoverPresentationController {
pvc.permittedArrowDirections = .up
pvc.delegate = self
pvc.sourceView = sender
pvc.sourceRect = sender.bounds
}
self.present(menuVC!, animated: true, completion: nil)
}
// showing VC from popupMenu VC
#IBAction func showVCFromPopup(from target: PopupMenu, vc: UIViewController) {
target.dismiss(animated: false, completion: nil) // dismiss popup
if target.isBeingDismissed { // check is popup dismissed
vc.modalPresentationStyle = .overCurrentContext
self.present(vc, animated: true, completion: nil)
}
}
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .none
}
}// end of class
class PopupMenu: UIViewController {
var button = UIButton()
// here is init's
override func viewDidLoad() {
//... some other code
button.addTarget(self, action: #selector(vcOpen(sender:)), for: .touchUpInside)
}
#IBAction func vcOpen(sender: UIButton) {
if sender == button {
let vc = UIViewController()
if parent != nil { print("PARENT")} // Never will work, no ideas why, so MainVC isn't a parent of PopupMenu
if let mainVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MainViewController") as? MainViewController {
print("# ACTION: Opening VC")
mainVC.showVCFromPopup(target: self, as: vc!) // opening VC
}
}
}
}
But I have warning.
Maybe anyone will find mistakes in my code or have any ideas how to do this.
Thanks for all answers!
I edited you code to pass a reference of the mainVC to the PopupMenu:
class MainViewController: UIViewController, UIPopoverPresentationControllerDelegate {
// showing Popup Menu VC
#IBAction func showPopupMenu(sender: UIButton) {
menuVC = PopupMenu()
menuVC?.modalPresentationStyle = .popover
menuVC?.preferredContentSize = CGSize(width: 150, height: 250)
menuVC?.MainVC = self <--- here
if let pvc = menuVC?.popoverPresentationController {
pvc.permittedArrowDirections = .up
pvc.delegate = self
pvc.sourceView = sender
pvc.sourceRect = sender.bounds
}
self.present(menuVC!, animated: true, completion: nil)
}
}
class PopupMenu: UIViewController {
var mainVC: UIViewController <-- here
#IBAction func vcOpen(sender: UIButton) {
if sender == button {
mainVC.showVCFromPopup(target: self, as: vc!) <-- here
}
}
}
I'm trying to present the ImagePickerController modally. My button firing the present action is inside a subview of the main view.
When pressing the button, the ImagePicker view is showing and dismissing right away.
I tried the same with another button which resides in the main view, and it's working fine.
My button action code:
#IBAction func pressUploadProfilePhoto(_ sender: Any) {
picker.allowsEditing = false
picker.sourceType = .photoLibrary
present(picker, animated: true, completion: nil)
}
Class deceleration:
class ProfileVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
let imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
}
}
Delegate methods:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
profilePicImg.contentMode = .scaleAspectFill
profilePicImg.image = pickedImage
}
self.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
My Views hierarchy:
What am i missing?
Please Try the below code, may be your problem get resolved ->
1) Firstly add these Delegates in your Class.
class XYZ: UIActionSheetDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate
2) Create a variable ->
let imagePicker = UIImagePickerController()
3) Set imagePicker delegate in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
}
4) Write Delegate Methods for UIImagePicker
// MARK: - ImageView Controller Delegate Methods
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
imageviewProfile.contentMode = .scaleToFill
imageviewProfile.image = pickedImage
}
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
5) Now your Action Method ->
#IBAction func pressUploadProfilePhoto(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
imagePicker.allowsEditing = false
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
imagePicker.modalPresentationStyle = .fullScreen
present(imagePicker, animated: true, completion: nil)
}
}
Have such part of my storyboard:
So I want present from UserProfileController: UIViewController "Мой профиль", which is modal, (on the top on image) UIImageViewController.
My code:
extension UserProfileController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBAction func imagePressed(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
self.present(imagePickerController, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else {
return
}
picker.dismiss(animated: true, completion: nil)
userProfileImageView.image = image
}
}
Well, imagePickerController presented, but after I choose image I have dismissed both controllers (imagePickerController and parent - UserProfileControler).
What am I doing wrong? Thanks
P.S. May be problem is I'm showing "SideMenuNavigationController" as modal? (so advised in SideMenu framework documentation)
Try to create you UIImagePickerController reference in your class (as a variable)
// to choose an image from the Camera Roll
fileprivate lazy var imagePicker: UIImagePickerController = {
let picker: UIImagePickerController = UIImagePickerController()
picker.allowsEditing = false
picker.sourceType = .savedPhotosAlbum
picker.delegate = self
return picker
}()
I am tired of trying to PopOver the view controller and searched every where, tried myself also.This issue has again arrived and i am confused what to do next
func showPopover(base: UIView)
{
let storyboard : UIStoryboard = UIStoryboard(name: "Messaging", bundle: nil)
if let viewController = storyboard.instantiateViewControllerWithIdentifier("PreferencesViewController") as?PreferencesViewController
{
let navController = UINavigationController(rootViewController: viewController)
navController.modalPresentationStyle = .Popover
if let pctrl = navController.popoverPresentationController
{
pctrl.delegate = self
pctrl.sourceView = base
pctrl.sourceRect = base.bounds
self.presentViewController(navController, animated: true, completion: nil)
}
}
}
I am calling this method in any one of the actions clicked from UIBarButtons
func optionChoosed(hello:Bool)
{
if (hello)
{
self.showPopover(hello)
}
}
it says Cannot convert the value of type BOOL to expected argument UIiew.. can we fix this or am i going wrong direction.
class SHNewStylesViewController: UIViewController, UIPopoverPresentationControllerDelegate {
var popover: UIPopoverPresentationController? = nil
//MARK: - View life cycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: - IBActions
#IBAction func showPopover(sender: AnyObject) {
let genderViewController = storyboard!.instantiateViewControllerWithIdentifier("ViewControllerTwoIdentifier") as! ViewControllerTwo
genderViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
genderViewController.preferredContentSize = CGSize(width: 200.0, height: 400.0) // To change the popover size
popover = genderViewController.popoverPresentationController!
popover!.barButtonItem = sender as? UIBarButtonItem
popover!.delegate = self
presentViewController(genderViewController, animated: true, completion:nil)
}
//MARK: - Popover Presentation Controller Delegate methods
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
}
In my case showPopover is a IBAction of my bar button item. You can you that code inside the showPopover method wherever you want.
Thanks:)
I have 2 UIViewControllers:
ViewController 'A' named 'RERUN_SETUP' with an UIImageView and ViewController 'B' named 'SelectPhotos' with an imagePickerController.
There is an empty transparent UIButton over the UIImageView in ViewController 'A', which pops up ViewController 'B' and allows the user to select adding a picture from Camera or from Photos. ViewController 'A' is declared in ViewController 'B', but when I try to change the UIImageView on ViewController 'A' from ViewController 'B', the app crashes with an error
fatal error: unexpectedly found nil while unwrapping an Optional value.
Below is my code, any help will be greatly appreciated :)
ViewController 'A'
class RERUN_SETUP: UITableViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate {
//USER PICTURE
#IBOutlet weak var RERUNpictureIn: UIImageView?
//TRANSPARENT BUTTON OVER THE IMAGE VIEW
#IBAction func imageButton(sender: AnyObject) {
let popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("SelectPhotos")
popoverContent!.modalPresentationStyle = .Popover
popoverContent?.modalTransitionStyle = UIModalTransitionStyle.FlipHorizontal
var popover = popoverContent!.popoverPresentationController
if let popover = popoverContent!.popoverPresentationController {
let viewForSource = sender
popover.sourceView = self.view
popoverContent!.preferredContentSize = CGSizeMake(100,80)
popover.delegate = self
popover.permittedArrowDirections = .Any
}
self.presentViewController(popoverContent!, animated: true, completion: nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
ViewController 'B'
import UIKit
class SelectPhotos: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var savedImage = NSUserDefaults.standardUserDefaults().objectForKey("image")
var imageToSave = UIImage()
var otherController:RERUN_SETUP = RERUN_SETUP()
#IBAction func camera(sender: UIButton) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.Camera
pickerController.allowsEditing = true
self.presentViewController(pickerController, animated: true, completion: nil)
}
#IBAction func photos(sender: AnyObject) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
pickerController.allowsEditing = true
self.presentViewController(pickerController, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.dismissViewControllerAnimated(true, completion: nil)
self.imageToSave = image
otherController.RERUNpictureIn!.image = image
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
In View Controller B in your image picker delegate method save your image to nsuserdefault and in your viewconroller A get that image from nsuserdefault. and set the image.
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
let imageData = UIImagePNGRepresentation(image)
NSUserDefaults.standardUserDefaults().setObject(imageData!, forKey: "image")
NSUserDefaults.standardUserDefaults().synchronize()
}
and in your View Controller where you want to set the image
let imageData = NSUserDefaults.standardUserDefaults().objectForKey("image") as! NSData
imgView.image = UIImage(data: imageData)
The reason you are getting nil for RERUNpictureIn ImageView, is that it has not initalized yet for that empty object you have declare named otherController inside your SelectPhotos controller, Also that object will not helpful because the object you have create it not belongs to the object that is currently running with your application.
To send image to previous one you can use delegate/protocol for that.
First declare one protocol like this and implement with your RERUN_SETUP Controller
protocol ImageDelegate {
func getImage(image: UIImage)
}
Now implement it inside your
class RERUN_SETUP: UITableViewController, ImageDelegate, UIPopoverPresentationControllerDelegate {
//Your Code
//Implement method of ImageDelegate
func getImage(image: UIImage) {
self.RERUNpictureIn.image = image
}
}
Now add one object of ImageDelegate inside your SelectPhotos controller
import UIKit
class SelectPhotos: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var savedImage = NSUserDefaults.standardUserDefaults().objectForKey("image")
var imageToSave = UIImage()
var delegate: ImageDelegate?
#IBAction func camera(sender: UIButton) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.Camera
pickerController.allowsEditing = true
self.presentViewController(pickerController, animated: true, completion: nil)
}
#IBAction func photos(sender: AnyObject) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
pickerController.allowsEditing = true
self.presentViewController(pickerController, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.imageToSave = image
self.delegate.getImage(self.imageToSave)
self.dismissViewControllerAnimated(true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Note: Now inside RERUN_SETUP controller where you are creating object of SelectPhotos for presenting the view, just add one line before presenting the object.
objectOfSelectPhotosThatYouHvaeCreated.delegate = self
Typically, when I get this error, it has something to do with me having an extra "?" or "!" somewhere. Or that I'm missing one somewhere. Try messing around with those and see if it fixes your bug.