Accessing PageViewController's methods from child view controller - ios

The issue is this. I have a PageViewController as my root view controller. Initialising the first page using SetViewControllers in the ViewDidLoad block of the PageViewController class works, as does the flipping back and forth of pages using the page's gesture recognizers. This root view controller is available application-wide via the AppDelegate.
I wanted to add the ability to return to the first page from anywhere in the book, so created a public method in my PageViewController class that simply called the SetViewControllers method. While this appears to work, I've noticed certain quirks. Music that is looping in the background (again, an AVAudio object declared in the AppDelegate) is restarted and the ViewDidLoad block doesn't fire until the page is turned again using the gesture recognizers.
I tried the same thing using GetNextViewController but that simply throws a null reference exception for the PageViewController reference. I'm assuming there is some relationship between the controls I'm not grasping, perhaps something to do with the PageViewController's DataSource. I have tried delegating this to a class that overrides the default methods, as well as using Mono's this.pageViewController.GetNextViewController = delegate(method signature) syntax to no avail.
Does anyone have any insights as to what my problem here is?
Edit: Code for AppDelegate.cs can be viewed here: https://gist.github.com/1747537 and for PageViewController.cs here: https://gist.github.com/1747559.

I can see several issues in your code:
your PageViewController is already the root controller in your app, there is no need to call AddSubview() anywhere.
You are inherinting from UIViewController and then encapsulate a UIPageViewController.You should either inherit from UIPageViewController or have no inheritance at all (if it is true as Dimitri says the UIPageViewController is not meant for subclassing).
The ReturnToFrontPage() could be a method of your AppDelegate instead of your subclassed UIPageViewController.
With your combination of inheritance and encapsulation you are building a hierachy of view controllers. This will make problems with events being triggered if not implemented properly.
In short: don't inherit anything in your case. Use a plain UIPageViewController and make the ReturnTpFrontPage() a method of your AppDelegate, then it should all be a walk in the park.

Related

iOS Swift how to monitor UIViewController lifecyle

I am new to iOS development. So pardon me if this is a very basic thing.
From what I have learnt till now:
UIViewController class resembles somewhat equivalent to an Activity class in Android.
and viewDidLoad/viewWillAppear method to onCreate/onStart method
and viewDidAppear method to onResume method
Please correct me if I am wrong here.
Now, in Android we can monitor which of these methods(including other lifecycle methods) are triggered/called by implementing an Interface (ActivityLifecycleCallbacks) (somewhat resembling a protocol in iOS) which exists in the Application class in any Activity (particularly in a class which extends Application class).
It means that now these methods will be triggered/called whenever there is any navigation from one screen to another in the android app.
How do I do this in iOS using Swift? How do I know which screen(UIViewcontroller) the user is currently in and where he is navigating?
In short I want to write a standalone class which logs which screen(UIViewController) the user is currently in and which one of the lifecycle methods(viewDidLoad, viewWillAppear etc) is being executed?
Someone please help me out.
Edit:- I don't want them to subclass my standalone class instead of UIViewController class.
There are no global events that are fired when the UIViewController lifecycle methods are called. To create those you would need to subclass UIViewController as has been suggested.
You can look at UIApplication.sharedApplication().keyWindow?.rootViewController to get the current root view controller (which is often, but not always the currently active view controller).
You wouldn't typically design an app that depended on some central object tracking the state of view controllers.
The flow of UIViewController methods is pretty well described in the class reference and you can also work it out from the function names -
viewDidLoad called after the view controller instance is loaded (once per instantiation)
viewWillAppear called before this view appears
viewDidAppear called after this view appears
viewWillDisappear called before this view disappears
viewDidDisappear called after this view disappears
Create a view controller subclass and add that implementation in there. Then make sure all the view controllers you create subclass that new class rather than UIViewController itself

How to implement interactive transitions in a custom container view controller

I implemented my own custom container view controller and I try to make it compatible with iOS 7 view controller transitions. I make my custom container view controller conform to UIViewControllerContextTransitioning and I send self when I call transitionDuration: and animateTransition:. It all works fine as long as I use only animated transitions.
Now I want to make it work with interactive transitions, so I call the interaction controller's startInteractiveTransition: instead of the animation controller's animateTransition:, using self again as a parameter. However, if I use a UIPercentDrivenInteractiveTransition as the interaction controller, it then calls a _animator method on my context (which is the container view controller itself). Of course, I haven't implemented this method which is private and undocumented, so it crashes...
Am I missing something in my implementation? Is UIPercentDrivenInteractiveTransition only compatible with Apple classes because it uses some implementation magic (as when it requires that everything should be in a UIView animation block)? The documentation and header files make it look like we can implement our own container view controllers and still use custom transitions, but is it really true or just wishful thinking because nobody would actually do that?
If I can't use UIPercentDrivenInteractiveTransition, then where exactly should the interaction/animation logic be? In the UIViewControllerTransitionCoordinatorContext object? In the UIViewControllerInteractiveTransitioning object (most likely, this object is the driver...)? Or in the UIViewControllerAnimatedTransitioning object (this is probably where the real animation should happen, but would that mean calling animateTransition: several times during the interaction? Or adding new methods for each step of the interactive transition?)
Edit: The documentation says:
A percent-driven interactive transition object drives the custom animation between the disappearance of one view controller and the appearance of another. It relies on a transition animator delegate—a custom object that adopts the UIViewControllerAnimatorTransitioning protocol—to set up and perform the animations.
There is no UIViewControllerAnimatorTransitioning protocol. Assuming it is a mistake, or a name change that happened during iOS 7 development and it is actually the UIViewControllerAnimatedTransitioning protocol, how do we link the interaction controller with the animation controller? I guess it's the responsibility of the view controller driving the transition but I don't see any API to make this link, so it would mean that UIPercentDrivenInteractiveTransition is indeed reserved for Apple classes?
I'm trying to do the same on my own and ended up writing my own UIPercentDrivenInteractiveTransition equivalent. Seems like the percent driven transition asks for the animation and actually starts it after the interactive transition is started. I've got some trouble with implementing the reverse animation when canceling though.

Objective-C: Inject code into delegate method

What I want
I want to add some logging code into my app without having to update all of my view controllers.
What I've tried
I attempted to add a category to UIViewController and override one of the delegate methods. However, this produced several warnings/errors.
Is there a way for me to inject code into all of my app's ViewControllers?
Look into method swizzling. It is a powerful tool and can save you a lot of time. Swizzle one of the methods you wish to have logs in, and then call the original method to have it do what it is originally supposed to.
You could subclass UIViewController and then add the logging methods in your super class. You would still need to touch all of your VC's though and change the class to your super class though.
You can't possibly have so many view controller classes in an iOS app that touching each one will be a huge problem. So create your own UIViewController subclass, maybe OurSuperViewController that'll act as a superclass for your view controllers, and add the logging there. Then modify each of your view controller classes so that they inherit from OurSuperViewController, and make sure that each one calls super in the relevant view controller methods.
Once you've done that, you can turn logging on or off at will by modifying just OurSuperViewController.

How to instantiate a particular view controller with storyboard in iOS at early stage of loading?

When using tabs with storyboard in iOS 5, some of them may take quite a long time to initialize when switching to it (for example, a tab containing GLKViewController).
This happens because an amount of work in viewDidLoad method in this controller could be very big.
Is there a way to initialize particular view controller (and call it's viewDidLoad method) defined in the storyboard at early stage - when an application starts? Having done this, the delay should be eliminated.
Are you sure it's the view controller's instantiation and not the viewDidLoad method? The view controllers are probably all created when the storyboard is unpacked, but a view controller tries to delay loading its actual view object as long as possible; viewDidLoad isn't called until the view property of your UIViewController subclass is accessed.
So a way around this could be to manually access the view property:
__unused CGRect frame = [[tabBarController.viewControllers objectAtIndex:index] view].frame;
If the slowdown is, in fact, in the instantiation and the view controller isn't being created until you switch to that tab, then you'll have do force the view controller to be instantiated by accessing it programmatically, like in the above example.
Calling the frame of the vewcontroller or the .view property will most likely work,
but i dont advice you to mess up with the viewcontroller initializations and view settings
For the following reasons
changes you make will not be standard, they will be tricks and hacks that will later on get out of hand
changes that you make will not be carried with you easily to other projects you create
If i faced a problem like this i would create the GLKViewController separately for example in the app delegate and held it there, untill the viewDidLoad gets called in the viewController, then i would move this initilized GLKViewController to the viewController

What happens if I write touches event for a View in its View Controller?

I have seen Code snippets where people have written touchesBegan and touchesEnded in the View Controller of a view.
I am relatively new to iOS development and am unable to understand how is that possible.
Aren't these methods of UIView class that we override in our custom views.
and If its possible then If I call view's touches Event which version gets the priority ?
The one in the View controller or one in the View itself.
As you can easily look up in the documentation, the touches...:withEvent: family of methods is declared in the UIResponder class. Since both UIView and UIViewController inherit from UIResponder, both classes have access to the methods and can override them.
As to the question which implementation gets priority if both are implemented, that is defined by the responder chain. Touch events travel up the responder chain until they find an object that wants to handle the event. Since a view is placed before its view controller in the responder chain, the implementation in the view class would be executed.
The view controller has copies of these methods as well. It's for convenience so you don't have to create a custom UIView subclass just to handle touch interaction.
If both the view and the view controller implement these methods then they both get called when the user touches the screen, however I believe that the ones on the view get called first.
Note that as of iOS 3.2/4.0, UIGestureRecognizers are generally a much easier way to do most types of touch interaction. There's rarely any need to use touchesBegan and touchesEnded any more.

Resources