Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clean way to force view to load subviews early

Recently I wrote some code where I tried to refer to an outlet on a UIViewController I'd just instantiated with [storyboard instantiateViewControllerWithIdentifier] and modify the subview that the outlet pointed to before presenting the ViewController. It didn't work because the ViewController's view hadn't loaded its subviews yet, including the one that my outlet referred to, so the property just gave me a null pointer.

After (with some struggle) tracking down the cause of my issue in the debugger, I Googled around and learned, through answers like this one, that I can cause the view to load its subviews without being displayed by calling the myViewController.view getter. After that, I can access my outlet without any problems.

It's a clear hack, though, and Xcode - quite rightly - doesn't like it, and angrily protests with this warning:

Property access result unused - getters should not be used for side effects

Is there a non-hacky alternative way to do this that doesn't involved abusing the .view getter? Alternatively, are there canonical/idiomatic patterns for this scenario involving something like dynamically adding a handler to be called as soon as the subviews are loaded?

Or is the standard solution just to replace myViewController.view with [myViewController view] to shut up Xcode's warning, and then live with the hack?

like image 536
Mark Amery Avatar asked Jun 24 '13 15:06

Mark Amery


People also ask

How do I force layoutSubviews?

If you want to force a layout update, call the setNeedsLayout() method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded() method.

What does layoutSubviews do?

layoutSubviews() This UIView method handles repositioning and resizing a view and all its subviews. It gives the current view and every subview a location and size. This method is expensive because it acts on all subviews of a view and calls their corresponding layoutSubviews methods.

How do I load a view in Swift?

loadView() When using Storyboards, this is the method that will load your nib and attach it to the view , but when instantiating view controllers manually, all this method does is create an empty UIView . You can override it to change this behaviour and add any kind of view to the view controller's view property.


2 Answers

On iOS 9 or newer, one can use:

viewController.loadViewIfNeeded()

Docs: https://developer.apple.com/reference/uikit/uiviewcontroller/1621446-loadviewifneeded

like image 104
Rudolf Adamkovič Avatar answered Oct 26 '22 03:10

Rudolf Adamkovič


I agree that forcing a view to load should be avoided but I ran into a case where it seemed the only reasonable solution to a problem (popping a UINavigationController containing a UISearchController that had yet to be invoked causes a nasty console says warning).

What I did was use new iOS9 API loadViewIfNeeded and for pre-iOS9 used viewController.view.alpha = 1.0. Of course a good comment above this code will prevent you (or someone else) removing this code later thinking it is unneeded.

The fact that Apple is now providing this API signals it can be needed from time to time.

like image 41
Swany Avatar answered Oct 26 '22 04:10

Swany