I have a view that exits in its own class, with its own xib.
This view is initialized and added as a subview to my viewController view.
When the view is initialized, the method layoutSubviews is called where i customize some stuff in the view.
BUT which method is called when the view is removed from the superview (if any)?
For example, for a ViewController, viewWill/DidDisappear is called. Is there a similar method to a UIView (opposite to the layoutSubviews)?
Thanks in advance
---EDIT---
I just found a method that is called both on adding and removing a subView:
- (void)willMoveToSuperview:(UIView *)newSuperview
AND if newSuperview == 0, you can customize the removing of the subview.
Am i right or is it a tacky way to handle the situation?
BUT which method is called when the view is removed from the superview (if any)?
-removeFromSuperview is called, so you can override that if you need to do some housekeeping when the view is removed. Just remember to call super's version, too.
-layoutSubviews isn't necessarily only called when the view is added to a superview -- it's called whenever layout is needed. For example, it might be called when the orientation changes, or when the superview lays itself out again, or when the view's frame changes. There's really not an inverse of -layoutSubviews because none is needed. (What would it be called? -messupSubviews? ;-))
Related
My view hierachy looks like this: (I use Autolayout)
ContentView
CustomView (implements drawRect)
Button
TableView
In the drawRect of the CustomView I draw a UIBezierPath from the top to the bottom through all CustomView.SuperView.subViews where the line stops if a Frame is in the way and begins to draw further till the next frame and so on.
On Startup when the DrawRect is called the Views are not finished with layouting I guess, because the frames I get from the views are not correct.
The Problem is solved if I call
customView.setNeedsLayout()
customView.layoutIfNeeded()
in the ViewDidAppear method. But this impacts performance cause it gets called twice.
What's the right way to do this?
Your approach is a violation of the principle tell, don't ask. You should be telling your view where to draw; it shouldn't be asking.
Inside CustomView:
Get rid of any calls to self.superview.
Add a property that represents the information you need to draw (like #property NSArray *framesToSkip)
In drawRect: look in your property for the information you need.
In your view controller:
In viewWillLayoutSubviews:, update your custom view's framesToSkip property with the appropriate views.
If needed, call setNeedsDisplay on your custom view.
A few general rules that, if broken, indicate you might be violating tell, don't ask:
Never access a view's superview.
Never access a view controller's parentViewController or presentingViewController.
Never import a view controller class unless it's your child / presented view controller.
When creating a custom UIViewController container (a UIViewController that contains other UIViewControllers and their views) who is responsible for calling viewWillLayoutSubviews and viewDidLayoutSubviews? My container class has two sub-controllers of which neither is having these methods called when it moves to the parent view controller.
UIViewController's beginAppearanceTransition(_:animated:) is documented as being the right way to trigger viewWillAppear(), viewWillDisappear(), viewDidAppear(), and viewDidDisappear() but I see no equivalent for viewWillLayoutSubviews() / viewDidLayoutSubviews().
As best I can figure the parent view controller (which in this case is being presented via presentViewController(_:animated:completion:)) is responsible for calling its sub-controllers viewWillLayoutSubviews() / viewDidLayoutSubviews() in its own implementation of those same methods. The framework seems to call these methods under certain circumstances (like when you set the rootViewController property of UIWindow) but not others (like when you call addChildViewController() in UIViewController).
Is this the correct, idiomatic way to go about things?
who is responsible for calling viewWillLayoutSubviews and viewDidLayoutSubviews?
The runtime. You should never call these methods yourself.
Basically, when the view's bounds changes for any reason. According to Apple's docs:
When a rotation occurs for a visible view controller, the willRotate(to:duration:), willAnimateRotation(to:duration:), and didRotate(from:) methods are called during the rotation. The viewWillLayoutSubviews() method is also called after the view is resized and positioned by its parent. If a view controller is not visible when an orientation change occurs, then the rotation methods are never called. However, the viewWillLayoutSubviews() method is called when the view becomes visible. Your implementation of this method can call the statusBarOrientation method to determine the device orientation.
I have a UINavigationController with a UIViewController pushed onto it. In my viewControllers view, I have two subview UIScrollViews. I recreate these scrollviews every time in the viewWillAppear method in my viewController and add them as subviews to my viewcontroller's view. I am using ARC, should I be destroying the two scroll views in viewDidDisappear method? What is better practice for memory usage.
EDIT: I did some investigation, and without removing the scroll views and setting them to nil in the viewDidDisappear method, they are not released. The viewcontroller's view gets an increasing number of subviews as viewWillAppear is called. As I mentioned in the comments, I never deallocate my main viewcontroller. It always stays on the navigation controller's stack. Why must I manually release the scroll views?
It may not be necessary to do anything at all. If your UIViewController is removed from the screen and is then being deallocated, it will automatically deallocate its view hierarchy (including subviews you have added). An easy way to check for this is to override the dealloc methods of the classes you're interested in (using an ObjC Category method added to the class), and log a message to indicate they've been removed.
I need some kind of hook or template method to override which gets called when a view is added as subview to another view, but couldn't find it in the documentation. It must be something that gets called automatically by UIKit. The reason is that my view must start some animations as soon as there is a superview, but stop animating as soon as there is no superview anymore.
I can't override -setSuperview: as Xcode is not indicating that such class exists - and I can't call super.
You want to override - (void)didMoveToSuperview.
didMoveToSuperview
Tells the view that its superview changed.
The default implementation of this method does nothing. Subclasses can override it to perform
additional actions whenever the superview changes.
If you implement willMoveToSuperview on a UIView subclass, is it guaranteed to be called (with nil) when removeFromSuperview is called on your view?
The docs say that the newSuperview parameter may be nil and that it's called "whenever the superview changes" but I'm not sure if I can interpret this to mean it will be called when the view is removed from its superview even when not being moved to a different superview.
Whenever a view receives removeFromSuperview, and the view's superview was not already nil, the view will always do [self willMoveToSuperview:nil].