When to modify constranints so it will override storyboard setup? - ios

The problem of mine is, that I setup the constraints in the storyboard. But then I want to adapt it before the view appears on screen.
So for example if I lay down 5 views in a line and I want to hide one of then on smaller phones, where do I put the code for this. I tried viewWillApper, but the storyboard setup loads after that method and override my setup.
I found viewDidLayoutSubviews but now Im wondering if this is the best approach. Because I think this gets called many times later but I want some method that is called only after constraints are modifyed by storybord setup. So just before the main view appears on screen.
Hope you'll guide me in the right direction.

The constraint will finish setting when viewDidLoad gets called. viewDidLayoutSubviews will be called by the system in proper time or when you change you orientation.

Related

UIViewController lifecycle function loadview() frame question

I have been mainly working with storyboard until I recently moving to only creating controller with code.
I followed our coding standard to create some subview in the loadView() function, inside which, the first line is super.loadView().
From what I observed, after I called super.loadView(), the frame of self.view is already set correctly with the viewController itself, which is exactly the frame of the viewController.
My more experience colleagues are saying this was 100% not working in the old days that it should give u CGRectZero instead and probably I should not rely on it.
I want to hear more suggestion from other people.
Here is my sample project setup:
1. create a simple proj
2. add a button in the first VC
3. create second VC by code, override loadView() function in second VC, call super.loadView() there and print self.view.bounds next line
4. self.present or use navigation controller from VC1 in the button action to present or push to VC2
5. it always give me correct frame of the second VC.
Please let me know.
----------- Edit -------------
To clarify my question, I know the lifecycle functions like viewDidLayoutSubviews or layoutSubViews to return the correct view. I am NOT asking these.
My question is why loadView() IS returning me the CORRECT frame now.
Unfortunatelly I cannot give any insights as to what is happening under the hood - what I can do though, is tell you that according to the documentation you shouldn’t be calling super.loadView() :
You can override this method in order to create your views manually. If you choose to do so, assign the root view of your view hierarchy to the view property. The views you create should be unique instances and should not be shared with any other view controller object. Your custom implementation of this method should not call super.
(Emphasis mine)
1) I have been mainly working with storyboard until I recently moving to only creating controller with code.
I followed our coding standard to create some subview in the loadView() function, inside which, the first line is super.loadView().
Since you are using xibs, use viewDidLoad over loadView because of If you use Interface Builder to create your views and initialize the view controller, you must not override this method. as stated in loadView in Apple Docs.
2) My more experience colleagues are saying this was 100% not working in the old days that it should give u CGRectZero instead and probably I should not rely on it.
I want to hear more suggestion from other people.
The proper frame for the viewController.view will be when viewWillLayoutSubviews is called. As for its subviews, viewDidLayoutSubviews is what you will need
view frame inside loadView and viewDidLoad are Nib frame size. Your colleagues are correct that it will not return a proper size. This is noticeable upon running an iPad app with viewcontroller presented modally, or run your app on different screen size as contrast to what the device is in xib
ALSO, this question is directly related to yours:
Why am I having to manually set my view's frame in viewDidLoad?

Some IBOutlets are nil in view created using IB

I have created a view using IB in xib, loaded the view, and when I try to customize the containers (image, label, button e.t.c.) some containers are customized and some not. Like if I am setting the image on a image view it is getting set on the other hand customizing the button/label fails. I am doing all these customization in awakeFromNib method, this method is kept in view created using xib.
I tried to debug to see what's going on behind the scenes. Whenever an instance of view from xib is created awakeFromNib is called and rest of the picture is well presented by the screenshot below
As the screen shot shows, my code is halt by the breakpoint in awakeFromNib method and the debugger shows view is created in memory, it's subviews images are also created but label and button are nil, also used lldb to see if the things shown in debugger are correct.
Now I am not able to understand this behavior of creating a view using XIB having some containers created/ some not in awakeFromNib method, also the docs says use IBOutlets inside awakeFromNib to do any customization as the time awakeFromNib is called the view is completely created. But I guess it's not so.
Any help in decoding/ reverse engineering the above behavior of the debugging or what goes while creating a view with nib is much appreciated.
Many thanks in advance.

When I set a property in code does it matter if the storyboard option is enabled or disabled?

Consider UITableView's refreshing option.
If I have code in place to set up and display a refresher, should I keep it enabled or disabled in storyboard (With the little check-boxes)?
I figure it is not usually critical, but I would imagine that there are certain things that can cause bugs when overlooked, like if setting the refresher as 'off' in storyboard also changed some scrolling properties that were not covered in code (even though it doesn't-).
I am presuming that written code takes priority over storyboard options, and any storyboard settings are configured at compile time.
Is something that I need to be concerned with?
Every change you do in your UIViewControllers method -(void)viewDidLoad will be performed after the view has been loaded, so it will override the Storyboard/nib settings. And from this point on, all the code changes should be preserved (maybe some layout code can be problematic because of Auto-Layout etc.)
As the UIViewController documentation says:
viewDidLoad
Called after the controller’s view is loaded into memory.
- (void)viewDidLoad
This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView method. You usually override this method to perform additional initialization on views that were loaded from nib files.

iOS: setFrame no longer working from viewDidLoad or viewWillAppear

I prefer to disable autoresizesSubviews and to use setFrame to place all of my subviews.
As of iOS 6, things seem to have changed a lot.
When I call setFrame on a view in viewDidLoad, there is no effect. I tried it from viewWillAppear; same thing.
A setFrame call will work in willAnimateRotationToInterfaceOrientation, but that is not called initially like it was in iOS 5.
Can someone clarify please where I am expected to layout my views from?
I guess you want to layout your views from UIViewController. Have you tried performing your layout tasks in viewDidLayoutSubviews:
- (void)viewDidLayoutSubviews
According to Apple's documentation:
Your view controller can override this method to make changes after the view lays out its subviews.
Since your view itself does not do layout its subviews (you do not use autosize, autolayout or layoutSubViews:) you can do the layout tasks in this method.
Nevertheless, the elegant way would be to use a custom parent UIView and perform all the layout there, overriding UIView's layoutSubViews: (unless you add/removes views dinamically). Quote from Apple's documentation on "How View Controllers Participate in the View Layout Process":
Ideally, the views themselves perform all of the necessary work to reposition themselves, without requiring the view controller to participate in the process at all. However, if the view controller adds and removes views dynamically, a static layout in Interface Builder may not be possible. In this case, the view controller is a good place to control the process, because often the views themselves only have a limited picture of the other views in the scene.
You can use setFrame in viewDidLoad if you uncheck the Autolayout option in Interface Builder. If you need to use auto layout, You need to perform your layout tasks in viewDidLayoutSubviews:.
Regarding "Asking the views to lay themselves out doesn't make sense to me. Views don't have authority to say where they should go. That's the role of the controller, isn't it?". I think the answer is often negative. It's the parent view (not view controller) which usually plays the role of laying out it's own subviews. It does so by utilizing autoresizingMask or autolayout (iOS 6 only). Or You can make layout programmatically by overriding -layoutSubviews method of the parent view.
Sure, like Imre mentioned, controller can participate in the layout process as well by overriding - (void)viewDidLayoutSubviews. I often use this approach when I don't want to subclass the top level view of the view controller for keep things simple.
Finally, I found this post super useful. Even with some minor errors, the post provides a big picture of view layout process.

How to properly switch UIViews

I want to have multiple views in my application that I switch between.
What is the proper way to switch between UIViews that also supports UISplitViewController?
Is there a support way to switch or are Apple's controller classes designed to be root and root only?
I've tried having one root view and root controller and swap subviews in and out. One of the subviews is a UISplitViewController. It did not like the arrangement and does not display correctly. The detail view was not displayed, the master view displayed wrong orientation and wrong size.
I've then tried managing adding and removing one subview from the UIWindow in the app delegate. This works most of the time. However, the views added after the applicationDidFinishLaunching method do not appear setup correctly. They mostly look correct, however sometimes the orientation thinks its portrait when in reality its landscape. Also, when I try to display a popover, it shows up in an incorrect location. If I change the orientation, it redraws correctly. I've also have some random instances where the UISplitViewController view does not fully display, as if its frame is incorrectly sized.
Any suggestions heartily appreciated.
In applicationDidFinishLaunching, your objects haven't completed loaded from NIBs yet. Try using a viewDidLoad method instead.
What is the user-interface for switching between views? If one of these views represents a transient mode that the user enters and then exits, consider using a modal view. (See presentModalViewController:animated:.)
I would need more details about what you're doing to answer more particularly.

Resources