wi have 2 questions about using a popover in my application. First is about the popoverControllerDidDismissPopover function, it is never called in my application. I checked here about the same topics and found out that normally the problem is that the delegate is not set. But in my case i had:
class MainTableViewController: ...,UIPopoverControllerDelegate {
And to call the modal:
var popover: UIPopoverController!
On my cell tap event
popover = UIPopoverController(contentViewController: popoverContent)
popover.delegate = self
popover.presentPopoverFromRect(currentCell.LabelCellTitle.frame, inView: currentCell.LabelCellTitle.superview, permittedArrowDirections: UIPopoverArrowDirection.Left, animated: true)
The popover appears, but if i tap outside of it the method:
popoverControllerDidDismissPopover
will not be called. Any ideas?
The second question is about an error ill get when i tap on my cell again to load up the popover.
Warning: Attempt to present <...24ModalTableViewController: 0x7fda8a55e440> on <...23MainTableViewController: 0x7fda8a62eb80> which is already presenting (null)
Ok, i guess that mean that the ModalTableViewController is still there. Do i need it to set to nil with the popoverControllerDidDismissPopover function? Or how do i solve this warning?
Thanks in advance.
Edit:
After cleaning my projekt problem 1 is now solved (little mysterious) - maybe a bug in XCode Beta. Problem 2 still present
Edit2:
If i now set the Content and the Popover to nil after dismiss, i got the following error:
func popoverControllerDidDismissPopover(popoverController: UIPopoverController!) {
self.popover = nil
self.popoverContent = nil
}
Application tried to represent an active popover presentation
Why is the popover still active?
Related
I have a View and a popover that appears on top of it, which alters data. I am trying to update the view/run a function on the main view (that is under the popover) once the popover is dismissed. I have tried numerous things including viewwillappear, but it isn't being registered as technically the view doesn't disappear since the popover is just above (And you can see part of the view from behind). If anyone can suggest how to call a function on the parent view when dismissing the popover (without crashing the app, as most of my attempts have), I would be very grateful! Thanks.
Update: I am attempting to do this with a modally presented vc now, and have attempted to use protocol callbacks but to no avail. Below is the code.
protocol MainVCDelegate: class {
func pushIt()
}
in the modally pushed view:
weak var delegate: MainVCDelegate?
#IBAction func changePartnerButton(_ sender: Any) {
delegate?.pushIt()
dismiss(animated: false)
}
in the main VC I implement the protocol and create the function to be run, but nothing happens.
In iOS 13 and iOS 14, you set yourself as the popover's presentation controller's delegate and implement presentationControllerDidDismiss. In iOS 12 and before, you set yourself as the popover's popover presentation controller's delegate and implement popoverPresentationControllerDidDismissPopover.
Following Apple's documentation for adding and editing information Apple guide here I have a Viewcontroller with a tableview. The tableview contains a header with a "Add new" Button. If a table row is selected the detailViewController is pushed onto the stack. The detailViewController is also embedded in a UINavigationController, as in Apple's docs. If "Add new" is pressed, another segue is performed which presents the UINavigationController modally, which in turns shows the detailViewController. This works fine and the animation clearly shows a modally presented ViewController.
The detailViewController contains a Cancel Button in the NavigationBar. If it is pressed the following code is run:
#IBAction func cancel(_ sender: UIBarButtonItem) {
// Depending on style of presentation (modal or push presentation), this view controller needs to be dismissed in two different ways.
var isPresentingInAddActionMode = false
if let presentingVC = self.presentingViewController{
isPresentingInAddActionMode = presentingVC is UINavigationController
}
streekgidsModel.undoManager.endUndoGrouping()
print("undo grouping ended and undone")
streekgidsModel.undoManager.undo()
if isPresentingInAddActionMode {
dismiss(animated: true, completion: nil)
}
else if let owningNavigationController = navigationController{
owningNavigationController.popViewController(animated: true)
}
else {
fatalError("The MealViewController is not inside a navigation controller.")
}
}
The first if-statement checks if the property presentingViewController is present, and if so if it is of type UINavigationController. If so, the viewController is presented modally and should be dismissed. If not it is pushed onto the stack and the owningNavigationController should pop the detailViewController.
Running this code does not work as described by Apple. The check on the presentingViewController shows it is present, but the type check gives back "invalid". This is treated as false. The test on the owningNavigationController succeeds (I think it should fail) and the popViewController is executed. As there was no push, the view controller is not popped or dismissed and is still visible. A second press on Cancel executes the func cancel again, which results in an error as there is no longer a group started in the undo manager.
Baffling thing is that I have the same code in another viewcontroller, with similar UIViewTable and navigation and it works fine.
So to frame the question: why does this not work the way Apple describes it, why does my other view controller work as it is supposed to? Any input is appreciated.
BTW, the fatal error text is straight from the docs so the naming is not relevant and it is never executed.
I would start with checking who is presenter.
According to Apple docs on this:
When you present a view controller modally (either explicitly or implicitly) using the present(_:animated:completion:) method, the view controller that was presented has this property set to the view controller that presented it. If the view controller was not presented modally, but one of its ancestors was, this property contains the view controller that presented the ancestor. If neither the current view controller or any of its ancestors were presented modally, the value in this property is nil.
If the docs are correct then your presenter should be your "Viewcontroller with a tableview" which, I guess, is not UINavigationController. If that is the case then you should understand why your code fails.
It depends on your context of course, but I would just simplify a check this way:
var isPresentingInAddActionMode = self.presentingViewController != nil
... // your other code
if isPresentingInAddActionMode {
dismiss(animated: true, completion: nil)
}
else if let owningNavigationController = navigationController{
owningNavigationController.popViewController(animated: true)
}
If I understood your question and intent correctly then it doesn't matter for you who (which class) presented your detailVC and you care only about how your detailVC was presented - either pushed in navigation view controller or presented modally. I think just by checking presentingViewController property you can get that information.
I am presenting a view controller modally in iOS app. The issue is that there is no crash and the app freezes as soon as presentViewController:animated is called. The stats show the CPU usage to be 100% and the usage doesn't go down even after manually closing the app.
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
CustomModalViewController *vvc = [sb instantiateViewControllerWithIdentifier:#"CustomModalViewController"];
if(!vvc){
NSLog(#"ERROR!!! vvc is null");
}
NSLog(#"instantiate modal view controller");
vvc.providesPresentationContextTransitionStyle = YES;
vvc.definesPresentationContext = YES;
vvc.data = data;
NSLog(#"before presenting modal view controller");
[vvc setModalPresentationStyle:UIModalPresentationOverCurrentContext];
[self presentViewController:vvc animated:YES completion:nil];
I tried printing some debug statements in the viewDidLoad of my custom class, but those are also not getting called.
I don't understand why the view controller is not being displayed. Any help will be appreciated. I want to know in what case does your app go into infinite loop on pushing a view controller or is it because of some other cause??
UPDATE:
This error occured after I updated to XCode 7. Not sure, but I guess this might be an issue with new SDK- the UIKit or LLVM compiler. I copied my project to another mac with Xcode 6.4 and the error disappears!!! I haven't changed any build settings either that would cause the issue.
Any pointers on how to proceed?
Ok, this is bizarre, but I hope it helps: I have the EXACT same issue, the CPU jumps to 100% and view never shows. Works perfectly well in Xcode 6.4. In Xcode 7.1, on the view that I am calling, I have got a UITextView with some placeholder text "Notes:". What I found is that if I clear out the placeholder text, the view LOADS and all of the procedures execute as normal. If the placeholder text length is greater than 9 characters, the view also loads and procedures execute as normal. If the placeholder text length >0 and < 10, it's a no go. No view and CPU at 100%. This is odd, I realize, but hopefully it helps you out. Like you, I've got no errors or console output to show, it just spins.
EDIT FYI, blanking out the placeholder text in the storyboard, and just setting it in code fixes this as well irrespective of length
Same issue here.
I have a UITextView with the default string " Text " and fails with 100% CPU load. I was putting the placeholder only in code but until I remove the " Text " from the storyboard didn't work.
My code was developed in Xcode 6 and I noticed this error after send a new app revision builded with xcode 7.
I had the same exact problem as described in the OP and the answers:
Present a view controller (in my case a PageViewController)
The presented view controller has an button that when pressed presents another view controller to add a note
Move the app to the background while the "note" view controller is being presented. Then bring it back to the foreground.
The app is now frozen. When connected to the debugger, it seems to be frozen indefinitely, but when running in prod it crashes. The CPU was pegged at 100% and the memory usage was climbing.
I ultimately tracked this down to my "Note" view being set as the First Responder, When my view appears, via override func viewWillAppear(_ animated: Bool), I set the note UITextView to become the first responder, noteTextView.becomeFirstResponder().
If I removed that line and never tapped the note field, my app would successfully resume from the background.
To fix this problem, I ended up adding observers for when the app moves to the background and moves into the foreground. In these observers, I make the note text view become and resign firstResponder, respectively.
override func viewDidLoad() {
super.viewDidLoad()
//set up your view controller here.
NotificationCenter.default.addObserver(self, selector: #selector(self.appMovedToForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.appMovedToBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
}
#objc func appMovedToForeground() {
self.noteTextView.becomeFirstResponder()
}
#objc func appMovedToBackground() {
self.noteTextView.resignFirstResponder()
}
I'm not sure if I should be doing something differently to prevent this problem, or if it's best practice to resign first responder when the app goes into the background, but this seems to work for me.
I was presenting settings screen, so
I converted this:
private lazy var settingsVC: SettingsVC = {
let controller = SettingsVC.fromStoryboard()
settingsVC.delegate = self
return controller
}()
To this:
private lazy var settingsVC = SettingsVC.fromStoryboard()
And set the delegate later in view did load on controller which was presenting the settings:
override func viewDidLoad() {
super.viewDidLoad()
settingsVC.delegate = self
}
And now it works
My iPad app has several data gathering popovers, and I want to be able to disable the dismissal of the popover by touching outside of it, I then will use a button to quit the popover at the users discretion.
The app looks great, the popovers work fine, and I have a button inside them that quits nicely. Only I can't find a way of disabling dismissal in Swift, lots of posts on obj-c but nothing in Swift.
Does this mean that the functionality is no longer available?
I would greatly appreciate any help to my frustration.
Simply set the view controller's modalInPopover to true and the popover's passthroughViews to nil. But you must do the latter using delayed performance or it won't work. A small delay is all that's needed. Example:
let vc = UIViewController()
vc.modalPresentationStyle = .Popover
self.presentViewController(vc, animated: true, completion: nil)
if let pop = vc.popoverPresentationController {
vc.modalInPopover = true
delay(0.1) {
pop.passthroughViews = nil
}
}
For the delay function, see dispatch_after - GCD in swift?.
SWRevealViewController dismiss keyboard on swipe
Problem is the same but this answers does not help me.
There are some solutions in the given link.For example I don't have any #if macros to delete and I get an error when I write revealController.delegate = self; in AppDelegate.m
And the delegate method below never get called.
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position
{
//Never get called
}
I searched the Internet and did everything mentioned in the given link.
I am using SWRevealViewController V 1.1.3 https://github.com/John-Lluch/SWRevealViewController/releases
The problem is: I have a UITextField inside a ViewController which behaves as a Front View.When I click on UITextField, keyboard shows up, then I swipe to see my ViewController which behaves as Rear View but keyboard is still there and I can't hide it.
How can I make it possible?
I tried using willMove to position.........However it displays the keyboard when the Rear View controller pops up soon after the keyboard gets hidden..........
For me this worked perfectly....
func revealControllerPanGestureShouldBegin(revealController: SWRevealViewController!) -> Bool {
self.view.endEditing(true)
return true
}