Delete the only one page in UIPageViewController - ios

Whenever I want to refresh my UIPageViewController I call the following snippet, including when I want to delete a viewController from my UIPageViewController.
[self setViewControllers:#[currentViewController] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
Everything is working just fine... except when I want to delete the one and only viewController from my UIPageViewController because I cannot pass an empty array as the first parameter. In fact I get an exception if I do so.
How can I force a refresh and not set the current viewController for my UIPageViewController?
Right now I am passing a dummy ViewController but I don't find that very pretty. If I do so I get a page indicator even though I am returning zero in my (NSInteger) presentationCountForPageViewController:(UIPageViewController*)pageViewController overload.

The question makes no sense. There is no such thing as a page view controller without a view controller. If your goal is to hide the page view controller's view, hide it (or even rip the whole thing right out of the interface).

Related

UIWebView redraws on view did appear, how can I prevent this?

I am working on a app using UIWebView now getting a issue listed below please help me to sort it out.
In my UIWebView, I show some HTML content from String in it.
However, when I go to another ViewController and return back, it goes white for a second then draws my HTML content again.
Is there any way to prevent this? My html content does not change, so can I set it as fixed content or something to draw it faster ?
This is how I set html in webview:
webView.loadHTMLString(htmlData, baseURL: nil)
Your HTMl code is not changing, so that put your webView load code inside viewDidLoad instead of viewDidAppear, because viewDidAppear always call when your view is appear, where as viewDidLoad called single time when your view is load.
you can execute the code which is directing webview once in a life cycle of app or customize accordingly.
// if you are navigating your application using navigation controller enables you to come back to the rootview without executing whole code of that class associated with view.
// this doesn't apply the whole life cycle of view controller
[self.navigationController pushViewController:vc animated:YES];
// if you navigating through below code this apply the whole life cycle concept of view controller.
[self presentViewController:vc animated:NO completion:nil];
you must have a look about the life cycle of view controller here is a useful apple doc
viewController Life cycle short note
ViewDidLoad - Called when you create the class and load from xib. Great for initial setup and one-time-only work.
ViewWillAppear - Called right before your view appears, good for hiding/showing fields or any operations that you want to happen every time before the view is visible. Because you might be going back and forth between views, this will be called every time your view is about to appear on the screen.
ViewDidAppear - Called after the view appears - great place to start an animations or the loading of external data from an API.
ViewWillDisappear/DidDisappear - Same idea as ViewWillAppear/ViewDidAppear.
ViewDidUnload/ViewDidDispose - In Objective C, this is where you do your clean-up and release of stuff, but this is handled automatically so not much you really need to do here.

Keep UI data when navigating between views

In my test project I have a ViewController and a TableViewController controller embedded in a Navigation Controller. The ViewController is the main view, and the user can navigate to the TableViewController and then return back to the ViewController.
I am using a 'push' segue when going from ViewContoller>TableViewController, and the TableViewController is dismissed using [self dismissViewControllerAnimated:YES completion:nil]; when the user wishes to go back to ViewController.
In ViewController, I have a button that changes the text on a label:
-(IBAction)onButtonPress:(id)sender {
_myLabel.text = #"New Label Text";
}
When navigating to TableView, and then back to ViewController, the change in the _myLabel.text has been lost and the original text is restored. What is the best way to ensure UI data is retained when navigating between views? I might only have one label in this project, but at some point I will have many UI elements, for example, WebViews that need to keep a page loaded when the user navigates away and then comes back.
What would you suggest is the best method to implementing this?
Thanks for your time.
First of all, View is your data representation, any data is your Model. So you may store Model with its entities and values. Your controllers manage data to represent it on View or to change Model according to user actions in View.
So add some Model-object for storing _myLabel.text. And use this object for both controllers in your app.
Try to remove setting the text from the ViewWillAppear or ViewDidAppear method, put it in ViewDidLoad.

Dismissing/Delegate second view in a modal stack in storyboard

I have a TableView which describes a book with sections which represents the chapters and rows representing the verses.
A the top of this TableView I have a button in a navigation bar to allow "navigation".
The goal of this navigation button is to allow the user to easily jump to a given chapter/verse without scrolling manually (which can be very long).
When the button is pressed a tableview controller is called displaying all the available chapters of the book and when a chapter is selected another table view is called displaying a list of the available verses in the current chapter. Finally when the line is chosen the tablew view displaying the book should scroll to the given index/row.
So the idea : from the tableview representing the book I call the chapters view as modal and the verses as a push over the chapters view.
My problem is that I don't get the point of managing the delegate and dismissing from the 2nd modal view.
With 1 modal view I do things like that.
In the displayed VC (View Controller) I added the protocol and the delegate
#protocol ChapitresTableViewControllerDelegate <NSObject>
- (void)didDismissPresentedViewController;
#end
#interface ChapitresTableViewController : UITableViewController
#property (nonatomic, weak) id <ChapitresTableViewControllerDelegate> delegate;
#end
I have in the didSelectRow
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate didDismissPresentedViewController];
}
in the displaying VC I add the following line
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
ChapitresTableViewController *chapitresTableViewController = segue.destinationViewController;
chapitresTableViewController.delegate = self;
}
and of course
-(void)didDismissPresentedViewController
{
[self dismissViewControllerAnimated:YES completion:nil];
}
this would just work fine if I wanted to close after the first modal VC, but what I want is to have the second one being dismissed after I click in the second. Ok I can write the protocol and stuff in the second modal VC but how do I manage to have the delegate being send to the second VC.
Hope my question is clear enough it is not so easy to explain it.
Anyone understand me and can help me ?
NOTE : I know for now I don't pass any parameters back to the delegate, which I will do later to do the scroll. For now I just want to be able to close the second view, then I will add the required stuff to pass the parameters back to the delegate
I'm sure you can do this, but rather than modal view controllers with a navigation bar, wouldn't it be easier to use a navigation controller? Then you can use popToViewController to go back as many levels as you want to a particular view controller. You can either pass the UIViewController* of the various controllers you might want to pop to, or do so programmatically: e.g. How to pop back to specify viewController from navigationController(viewControllers/stack)?
In this scenario previous views controllers are retained. The ones you pop off are released (just like the modal ones you dismiss are released), but the ones that you pushed from are retained (just like the ones you presented from in a modal world are retained).
If the book is large, though, you'll have to be sensitive to memory usage. Thus, you will probably want to handle didReceiveMemoryWarning to release the model data for the previous views in either your modal sequence or push sequence, in which case, on viewDidAppear, you'll want to see if your app had to release the memory in response to didReceiveMemoryWarning and reload it in that case. But that's the desired behavior, either way, gracefully release the pages if needed (and reload them when the particular view reappears), but keep it in memory if you can.
Finally, you might also want to contemplate using UIPageViewController. Given what you've described, I'd like consider UIPageViewController first, UINavigationController and push segues second, and the use of modal segues third.

On iOS, why would a dismiss view controller immediately followed by a present view controller not work?

The code that works used to be
[self presentViewController:aNewViewController animated:YES completion:nil];
and self is the same class as aNewViewController, so it is a page that keeps on presenting a new page (with different data), by flipping horizontally.
But since presentViewController in this way can cause memory usage to be more and more (sort of like a web browser just having more and more history for Back and Forward), so I changed the code to:
[self.presentingViewController dismissViewControllerAnimated:NO
completion:^{
[self.presentingViewController
presentViewController:aNewViewController
animated:YES completion:nil];
}];
But for some reason, it just "goes back" to the previous view controller's view, without going to the new one (aNewViewController). Initially, I put the above code in 2 parallel lines, one after another, and then I put the second line in the completion block of the first call. And these two methods both won't work as expected. Is there something tricky that makes it not go to the new view controller?
Also, it used to have the good effect of flipping to the new content, but right now, if it works, it probably will flip back to the first page (the starting page), and then flip to the result page, and next time, flip to the starting page again. Because the starting page looks quite different from the result page, I would rather it just keep on flipping showing the result page (from one result page, flip to another result page). If I set the "dismiss" to have no animation, it won't have the flip animation, but it will still show the starting page first, and then flip to the result page. Is there a way to solve this?
Update: Won't it be true that self cease to exist after the dismiss? (the object is dealloc'ed). The above code is actually done in a class method (the class is the same class of aNewViewController, which is the result page's view controller). To solve the self issue, I tried to set a local variable first
UIViewController *presentingViewController = foo.presentingController;
[presentingViewController dismissViewControllerAnimated:NO
completion:^{
[presentingViewController
presentViewController:aNewViewController
animated:YES completion:nil];
}];
(foo is passed in, and have the value of self). then it actually works! But what if it is not a class method but is an instance method... will self not exist any more? (If it is in an instance method, will the completion block keep the object alive? But what about after the completion block, who is keeping the object alive?) I did it in a class method because then the starting page can just call this class method to present this page (with URL data fetching logic).
You need to add some delay between these two transitions. Try adding dealy of 0.40. Like [self performSelector:#selector(anySelector:) withObject:nil afterDelay:0.40];

ViewController won't update after load

I got two viewControllers using a navigation bar. The first viewController displays some data I change on the second viewController.
So if I load the second viewController, a back button appears in the NavBar and I can change my values (and they are stored, I used the debugger). My problem is, after hitting the backButton to come to my firstView Controller, it does not call it's viewDidLoad method. It's clear, that there are no updated values at all, when this function is not called.
At the first start, the viewDidLoad method is called and does what I want it to do. After going back and forth between the viewControllers the method is not called again.
Any solutions?
Thanks!
EDIT:
SOLVED
I did not want to delete my question, maybe someone needs this too:
This method is called every time the view appears, it is probably not defined by default:
-(void)viewDidAppear:(BOOL)animated
{
NSLog(#"View appeared.");
}
But the update code (like [[self view] setNeedsDisplay];) in viewWillAppear.
To make it clear: viewDidLoad is called when your view is loaded. This happens at the first time the view is going to be displayed. When you then navigate to the next view the first view can (depending on your code) still be loaded. Therefore when you navigate back to that view viewDidLoad won't be called because the view is still there.
But every time the view is going to be shown (for example when you navigate back to this view) the method viewWillAppear and viewDidAppear will be called.
Hope that helps.
ViewDidLoad method will get called when there is view controller allocation-initialization happens. In the case of moving back in navigation controller, it is not creating any new view controllers, it is reusing previous references from navigation stack.
Hence viewDidLoad will not get called. As your view controller is already in memory stack. So it will just make the view to reappear on windows and it will call viewWillAppear respectively.

Resources