How to make a xib subview interact with superview in Swift? - ios

I've been trying this for days...
I want to have a nib subview with some buttons and other stuff. The main view would have other subviews that change in response to pressing the buttons of the nib view.
What I can do:
I already loaded the xib subview into the superview using this approach.
The problem:
I can't make the buttons on the xib interact with other subviews (e.g. to change the text of a Label)
What I haven't nailed yet is how to structure the files and their relations.

You could use addTarget:action:forControlEvents: after you load the nib to add the action methods for your buttons; the target should be self (the controller where you've added this view). The view should have IBOutlets for any buttons or other controls you need to interact with. You shouldn't have any actions for the buttons in the subview class if you use this approach.
Another approach, would be to have the action methods for the buttons in the subview class, and have those methods call methods of a delegate protocol that you create in the subview class. When you add the subview to your view, you would set the controller as the delegate of the subview, and implement any protocol methods that you defined.

Related

How to access individual elements from .xib file loaded into the view controller?

I have a .xib file for a view controller and a corresponding Swift file. On click of a button another xib is loaded to show a popup view.
I load the popup view's xib file like this:
let myPopupView : UIView = (Bundle.main.loadNibNamed("myPopupView",
owner: nil,
options:nil)?.first as? UIView)!
Now the popup view has a set of labels for which I want to set selectors. How to do this?
You can't set selectors on views. What you can do is either use buttons or add UIGestureRecognizers (probably tap gesture recognizers) on your views.
You can either make your view a custom subclass of UIView that has IBOutlets to its subviews, or make the file's owner of your XIB file be the view controller that it's being loaded into, and then wire up outlets from the subviews directly into the view controller. The second approach won't work for a situation like a table view cell where you're adding multiple instances of this view to your view controller. In that case you'd need use the first approach of making your top-level view a custom subclass of UIView

Add a subview to a custom class UIViewController that loads from nib, in Storyboard

To clarify on this ridiculous title:
I'm using my own subclass of JSQMessagesViewController (https://github.com/jessesquires/JSQMessagesViewController) - let's call it ACMessagesViewController. I'm loading my ACMessagesViewController through storyboard, by setting the storyboard UIViewController's custom class to ACMessagesViewController. I am trying to add a subview to ACMessagesViewController's view through the storyboard.
JSQMessagesViewController loads from a nib. When I add a subview to ACMessagesViewController's view through storyboard, the view disappears. The subview seems to be adding to a view other than my ACMessagesViewController's self.view, and by the time the viewdidload scope runs through, the subview is gone.
My questions are:
1. What is the proper way to add a subview (through storyboard) to a custom class UIViewController, when the UIViewController loads from a nib?
2. What is happening in this view loading process? Why is my subview (added through storyboard) adding onto a view that is not the same self.view in my ACMessagesViewController?
Thanks in advance!
I think it's one of those "if you need to work around it, you're probably doing it wrong" scenarios you so often hit in iOS development. :-) Really, if you want the functionality the JSQMessagesViewController provides, you shouldn't need to add additional views. But if you must add views, the "right" way to do it is to add them as subviews of whatever self.view is after you call super in viewDidLoad. If you don't want to construct views programmatically, you can put them in a separate nib (instead of the storyboard) and manually load them.
(Note: this is assuming viewDidLoad is getting called. If it isn't, you might need to hook into some other method.)
I used #Anna's suggestion to add the view in viewDidLoad but you don't need to use a second Xib or design the view in code.
What you need is:
A. Design your view in the your JSQMessagesViewController scene in the storyboard/xib file.
B. Create an outlet of the view you need to present.
C. In viewDidLoad add your view with view.addSubview(myView) (or [self.view addSubview:self.myView] for all the objc ones out there)
D. That's it!

How to add UIViewController as target for a programmatically added subview like in IB

When adding UIViews in Xcode's interface builder you can use Ctrl+drag to create a target-action to the UIViewController that holds that view. You can also do that to any subviews you add using IB.
If a subview is created and added programmatically in awakeFromNib is there a way to add the target-action from it to the view controller right there or do you have to first create the subview in awakeFromNib and later create the target-action using the view controller as a delegate?
If its created from scratch, you have to bind events manually.
If however it's loaded from another NIB, there're at least 2 options:
You can get a uiviewcontroller from view, see this answer: https://stackoverflow.com/a/3732812/126995 Then you can pass the VC to the loadNibNamed:owner:options: method.
In the IB, you can change the type of the root view from UIView into your custom UIView-derived class, and bind actions and outlets from the subviews to the NIB's root view.

On iOS, if we use Interface Builder for the UIViewController's view, how do we implement a drawRect for it?

If we use Interface Builder to edit the content in the view, then how do we add a drawRect to that UIView object? (Probably we want a new class FooView that subclasses UIView -- but how will the .xib content be placed on this view?)
Adding "content" to the view controller's view in the xib just involves adding subviews - these are not affected by drawRect:.
That said, to set a custom class as the main view property of a view controller, just select the view in the xib, go to the identity inspector, and change the class from UIView to your custom class.
At beginning i want to point that i have done something like this(subclassing) with UIButton
and since UIButton is inherited from UIView this must be possible with UIView too.
(after subclassing UIView) create an instance of your subclass on your view controller and add this instance to ViewController as subview. At this point you can call your specific drawRect: method, which you have declared on your subclass

IBOutlets for custom UIView

I have a simple application, in which there is a view controller which is inited with nib file. In this nib file I have a simple View who's parent class is a customUIView subclass of UIView. In this view there are some buttons which I want to access on my custom UIView subclass methods when the setNeedDisplay method is called. Is it good practice to create IBOutlets for these buttons in both customUIView and customUIViewcontroller classes, or should I access these buttons by iterating on self.subviews?
You should create the IBOutlets indeed... since this is the best way to acces these buttons properties.

Resources