How and where to call - setNeedsLayout method of an UIView instance when device rotation changes without necessarily having an UIViewController controlling the view? Basically this could boil down to understanding view life cycle generally without a controller...
I guess some of the things that an UIViewController acts on behalf of the views when the user interacts with them (such as interface orientation changes, etc.) might be be handled by registering to UIApplicationDidChangeStatusBarOrientationNotification in UIView instead.
Related
The following UIResponder methods report raw touches on screen:
- touchesBegan:withEvent:
- touchesMoved:withEvent:
- touchesEnded:withEvent:
Recently I was playing with a UIView subclass that I wanted to be touch responsive.
Initially I implemented the methods above in the UIViewController that was responsible for the view in question.
However, I realised that the touch methods were being called whenever the UIViewControllers view was being touched, not the subview I wanted.
I reimplemented the methods inside a UIView subclass and everything worked as expected.
However I feel like this is violating MVC. I have control logic inside my view.
Should I keep the methods implemented inside the UIViewController instead, and somehow hit test to interpret which view was touched, or am I correct in having the methods implemented inside the UIView subClass?
I feel like the later is the lazy way out.
Thanks for your time.
In MVC, the view is responsible for user interaction. Therefore, it makes more sense to have your UIResponder methods overridden in your UIView. To keep strictly with MVC, you should then use a delegate pattern (or some other pattern) to call control logic functions that are in your controller.
The above image is from (Apple's MVC documentation). The part that pertains to your question is in the upper left. The view should tell the controller it has been touched ect, and the controller should execute the logic.
The UIViewController only is able to implement these methods because it comes with a built in view. This is confusing because it means that the UIViewController itself violates MVC, but thats a more involved discussion.
Reading several tutorials and books on iOS development I often encounter terms : UIViewController life cycle and UIView life cycle. I'm interested: is there an actual difference between these two terms?
Looking Apple docs I found that methods such as viewDidAppear or loadView is a part of view controller's life cycle, but I think it is more correct to refer them as view life cycle and methods such as initWithNibName or dealloc as controller's life cycle. Or there is no such a separation and when someone speaks about view life cycle he actually means UIViewController life cycle?
Both are different concepts, therefore have different life cycles.
UIViewController
A ViewController is the Controller in a MVC architecture. Therefore, it is responsible to coordinate the info between the model (your data) and your views. UIViewControllers coordinate the UIViews and are part of navigation between screens (pushViewController, presentViewController). Therefore it needs to know when it will appear in the screen.
A UIViewController has a very specific life Cycle and it has methods that can be extended that are part of that life cycle. Examples of those methods are:
viewDidLoad, viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear
View
A View, on the other hand, shouldn't be worried when it has to appear on screen. Therefore, it has a complete different life cycle:
awakeFromNib, willMoveToSuperView, didMoveToSuperView
This methods usually are called in the sequence of the UIViewController's life cycle. Therefore, normally, the UIView responds to changes and people don't consider they have a Life cycle on their own.
The ViewController's life cycle only makes sense when a class extends UIViewController while a UIView's Life cycle only makes sense when extends UIView.
Most of the times, when people talk about Life cycle they will talk about the UIViewController life cycle, since the View usually responds to changes. Two examples of those changes are: the view changed its size, changes its parent.
All your confusion will go away once you fully realise the difference between the two classes and ingrain it into your mind (by practice)
UIViewController - a class that has no UI in itself (not completely true though...see root view), its purpose is to control views and do some related stuff..It is like a policeman or traffic controller policing others. (views).
Most of the time you create your own subclass of UIViewController and that class tends to be quite heavy on functionality like
handling logical rules when to show what view
connecting to model layer (data and facts about the problem your app is solving)
interacting with other controllers,
UIView - a class that represents a rectangle area that can be heavily visually modified, but the most important fact is, it is visible on the screen, and can have subviews, which are also UIViews. Views are organised into view hierarchies.
Most of the time you customize your view so that it is
visually pleasing
handles it's subviews via autolayout
represents the particular type of visual information you need often subclassed to a more specific view class like labels, texts, buttons, etc.
One bit that confuses newcomers is that every view controller has one root view, a property which holds a UIView instance. Often you can get lost as to whether this root view is discussed, or the view controller is discussed. In causal discussion between developers, the two words are sometimes used interchangeably.
Both controllers & views have the lifecycle but you must not confuse the two.
ViewController lifecycle is what happens to the controller itself, like it awakes from nib file, or receives a low memory warning, but mostly about how its root view comes to life, how it appears disappears and dies..
View Lifecycle is about how the view lays out its subviews, and how it renders its content.
I like visual analogies..
Simply imagine a policeman with a lot of colorful paper rectangles. The policeman is the controller, and he says what (views) is shown and when on the screen.
The controller and the View are abstractions that are part of (Model View Controller) MVC architectural pattern. I recommend you study that immediately, so that the problem with lifecycle confusion is further cleared in your mind.
Adding to these answers and focusing a bit more on your exact questions:
I'm interested: is there an actual difference between these two
terms?
Yes, there is a different between both, but in a context where you are dealing with a UIViewController's root UIView, they are in a way related.
Looking Apple docs I found that methods such as viewDidAppear or loadView is a part of view controller's life cycle, but I think it is more correct to refer them as view life cycle and methods such as initWithNibName or dealloc as controller's life cycle.
And this is why they are related:
viewWillAppear
viewDidAppear
viewWillDisappear
viewDidDisappear:
They are all under Responding to View Events in the documentation. So these are callbacks from the UIView to the UIViewController telling it about its state. And although:
loadView
viewDidLoad
Are not under the same section (in the documentation), it's the UIView requesting/telling the UIViewController about its current state. And you have other examples of these interactions, for example:
viewWillLayoutSubviews
viewDidLayoutSubviews
In a way (and in your question's context) the general answer is: yes, those are two different lifecycles with different particularities, but they are related in a way. An example where they are not directly related would be the UIViewController's didReceiveMemoryWarning. (I say directly, because indirectly, it might be the UIViewController's root UIView the culprit).
Most of the lifecycle is handled automatically by the
system and no need for calling some methods like parent and child view
controllers relationship
Here are the mentioned lifecycle methods for UIView:
didAddSubview(_:)
willRemoveSubview(_:)
willMove(toSuperView:)
didMoveToSuperview
willMove(toWindow:)
didMoveToWindow
I'm trying to "mirror" a view controller:
app instantiates view controller 1 (of class A)
app instantiates view controller 2 (also of class A) on another UIWindow (external display, via Airplay or physical connector)
any touch event that view controller 1 receives should be mimicked on view controller 2
I've got part of this working on things like MkMapViews and simple view controllers by just catching things like region changes or scrolling in vc1 and telling vc2 to set its region or scroll to that position, having UIControl IBActions on vc1 also call the same action in vc2, etc.
This works with simple cases, but the problem comes with complex view controllers that have things like UITableViews with custom UITableViewCells that expand / contract, etc. I find myself having to implement every single possible delegate / action and make a bunch of objects aware of things they shouldn't be aware of, which just seems wrong if I'm going to make this at all reusable.
I've tried walking the subview tree of vc1 and using objc_setAssociatedObject() to associate the UIResponders in the view controller instances with each other, but I still have to catch every delegate / action on vc1 to look up the UIResponder on vc2 to mimic the event. There has to be a simpler way to do this. I tried subclassing UIWindow and overriding sendEvent and sending the event to the external display's UIWindow as well, but each UIEvent seems to have info in it that ties it to the UIWindow it originated in, as the external display UIWindow did nothing with it when I sent it.
How would I do this in a way that would allow me to abstract away the mirroring into a nice subclass or something so I don't have to litter every view controller with special-case code? I've thought about swizzling UIView's touch events, but I'm not even sure if that will help since UITouches and UIEvents are tied to the UIWindow they originated from, and UIEvent doesn't seem to provide a way for me to create my own event.
NOTE: what I'm trying to do is not default Airplay mirroring, as I want the external display experience to take advantage of the full display resolution and dimensions. The idea is to allow an iPhone app to work on the device itself (i.e. taller than it is wide), while also providing an experience on an external display that is geared for that display (wider than it is tall, greater resolution, opportunities to present info in a more readable HDTV-friendly format).
Thoughts?
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.
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.