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.
Related
I'm creating a ViewController that will contain as a portion of it a scrollView. In that scrollView I would like to include the view of another ViewController. When I set up this ViewController inside of the ScrollView, all of that ViewController's data is pulled from the web and even it's "ViewDidLoad" method is called. However, nothing appears except for the tableViewLines and a spinner I've created to show the page is loading. Here is what it looks like (the ScrollView in question is under Commitments and Awards):
What should be loaded inside the scrollView is a tableView that looks like this:
It may be that the tableview's delegate/datasource are not set correctly. Could you check whether tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: are called or not?
It is not a good idea to show view of one view controller in another view controller view. Apple does not recommend it. what ever you want to do, do it in the same view controller.
In one of my view controllers, I've got the following structure:
+-View
+-Scroll View 1
+-UIView
+-Scroll View 2
...and I'm adding three subviews into Scroll View 2, one of which contains a series of UITextViews and UILabels as a form-like structure.
The problem I'm seeing is that when I try to access the properties that refer to those controls from the view controller level, they are coming up nil. However, if I set a breakpoint in awakeFromNib inside the UIView that contains the UITextFields and UILabels, the properties are valid... it's almost like the reference disappears.
I can clearly see that they exist, and if I do the following in the debug console after setting a breakpoint, I definitely get the view graph output to the console:
po [self.profileEditView recursiveDescription]
Does this sound familiar to anyone, and if so, how can I remedy it?
One thing I'm thinking of doing is just not trying to access those properties directly, since the goal is to get the view controller to be the delegate of those UITextView controls so it can respond to becoming the first responder by adjusting Scroll View 1's position when each text view gets focus. It's just more of a hassle, but if that's what I have to do I'll go that route.
I've just never seen this happen before so I thought it was pretty strange. There's definitely a lot going on in this view controller.
Additional Details:
The View Controller is defined in a Storyboard.
The UIView subviews added at runtime have XIBs that I load programatically.
I discovered what the problem is... I was inadvertently instantiating another subview as a subview inside initWithFrame (don't ask me why I was doing that... I think I was under the impression that I needed to do that to instantiate the XIB at that point), so the properties on the nested subview were valid but the properties of the top-level view (the one contained in Scroll View 2) were all nil.
I had a five-minute conversation with a developer in NZ and he asked about what I was doing there and it became readily apparent that what I needed to do was instantiate the view and its NIB in the view controller with:
ProfileEditView *view = [[[NSBundle mainBundle] loadNibNamed:#"ProfileEditView" owner:nil options:nil] objectAtIndex:0];
...instead of instantiating it with initWithFrame.
Thanks for the help, however!
I'v never used UITableViewControllers or UICollectionViewControllers, because you can have the same functionality by using UIViewController with its root UIView, then adding UITableView in xib or storyboard and assigning its delegate and datasource. And I also was able to put activity indicator inside the center of root UIView.
Now the things get a little bit complicated when using UICollectionViewController where its root view is UICollectionView. I need to update some code of other guys and they put activity indicator inside UICollectionView (in storyboard). The problem is this activity indicator gets hidden when cells are reused because activity indicator view is the most bottom one. I was unable to change visibility priority storyboard and also this code in view didLoad is not working:
[self.itemsCollectionView bringSubviewToFront:self.activityIndicator];
Because labels, images and etc. views of collection view cell are placed later, during collectionView:cellForItemAtIndexPath:. I could try to call bringSubviewToFront: in collectionView:cellForItemAtIndexPath: but that would be a wrong decision. Any ideas how to achieve this when using UITableViewControllers or UICollectionViewControllers?
IMHO the only reason to use UITableViewControllers or UICollectionViewControllers is because static cells are not shown storyboards when designing layout.
UPDATE It appears iOS wraps UICollectionView inside UICollectionViewControllerWrapperView. Tried to add activity to this wrapper view in viewWillAppear:
[self.itemsCollectionView.superview addSubview:self.activityIndicator];
But with no luck - activity indicator is still is below the cells.
I'v ended in refactoring existing UICollectionViewController in storyboards: I'v opened storyboard xml file with TextEdit, searched for the screen and changed its type from collectionViewController to viewController because was unable to find another way how to change the type of controller, though I hope there will appear some more elegant way for that in the nearest future. Then, I'v wrapped collectionView inside root view and placed activityIndicator inside this view. It's proven classical approach that works like a charm.
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.
I'm getting the Unable to simultaneously satisfy constraints error.
I don't get the error when the viewcontroller establishes itself using viewDidLoad but it does get the error when using loadView...
Why is this happening?
I thought the only difference between loadView and viewDidLoad is that viewDidLoad occurs after loadView. At least, that seems to be the going explanation...
I don't know whether my answer would completely address your issue,but it might act as a starting point to resolve your issue.
There are quite a few points(you might be aware of) which needs to be noted before you use loadView:
loadView is a method that gets called when view is loading,viewDidLoad is method that will be executed after the
view is loaded.
loadView is recommended when you are willing to create the view programatically instead of setting in xib file,other wise there is
no point in using or calling loadView(It all depends on your
application requirement though).
Don't call super loadView if you initialise your view from story
board or xib file.
If you initialise your view from story board, do not call
[super loadView] and you must assign your rootView to self.view
property, if you call [super loadView] inside the method, you better never override this method and put your code in viewDidLoad method..
If you are using xib file to set up the view,do the modifications of objects set up in viewDidLoad and don't call loadView,if you are creating the view programatically,initialise the view in the loadView and do the additional set up in viewDidLoad.
The constraint error generally pops up in story board or xib file,when "Use AutoLayout" is selected,if you unselect it,the error disappears,since you are creating the view programatically in loadView,it is your responsibility to see to it that the auto layout option is disabled i.e. you need to make use of setTranslatesAutoresizingMaskIntoConstraints property by setting it to "NO".
You can also refer to some of related questions here and there which could well get you out of this issue.
Thanks and happy coding :)