UIViews buttons inside a scrollview not triggering IBAction - ios

I have a horizontal scrollview with pagination enabled so each page will show a distinct xib view. Some xib views have buttons in them that linked to IBAction. I declare the IBAction in each xib's class. Everything seems and looks good the buttons show clicking effects and all, but the IBAction isn't fired?
Here is a code sample:
let clockView: ClockViewController = ClockViewController(nibName: "ClockViewController", bundle: nil)
let carView: CarViewController = CarViewController(nibName: "CarViewController", bundle: nil)
scrollview.addSubview(clockView.view)
carView.view.frame.origin.x = self.view.frame.width
scrollview.addSubview(carView.view)
clockView and carView both have buttons in them and the buttons are linked to IBActions declared in ClockViewController.swift and CarViewController.swift respectively.
Here how one of the views look like. I'm not adding UIViewController in the xib, I'm only using a UIView. I'm guessing this could be part of the problem but I can't use UIViewController as subview because it gave an error.
Any help is appreciated,

The problem is that you are declaring carView as a local variable, so it will be released once the function exits as there is nothing to hold a strong reference. The view elements themselves are referenced by the scrollview, so they aren't released but there will no longer be a view controller instance to process the events.
If you change carView and clockView to be properties then a strong reference will be held.

The issue seems that you are using ViewControllers inside ViewControllers. If you'd like to do this via storyboard, you'll have to use a containerView and place the ViewController within this containerView using the embed segue that it comes with.
If you'd like to do this programmatically, you'll have to add child viewcontrollers to the parent viewcontroller that emcompasses these child View Controllers that you have which are carView and clockView.
P.S. it's a bit confusing that you are calling your view controller carView, perhaps CarViewController is less confusing :)

Related

What is the difference between a UIView outlet, and a ChildViewController?

Lets say I have a container view in a parent UIView.
What is the difference between referencing it as an Outlet in my parent UIView, or accessing it this way :
categoryContainerViewController = self.childViewControllers[0] as! CategoriesControllerView
View and view controllers are two different things
A VIEW is an object that is drawn to the screen. It may also contain other views (subviews) that are inside it and move with it. Views can get touch events and change their visual state in response. Views are dumb, and do not know about the structure of your application, and are simply told to display themselves in some state.
A VIEW CONTROLLER is not drawable to the screen directly, it manages a group of view objects. View controllers usually have a single view with many subviews. The view controller manages the state of these views. A view controller is smart, and has knowledge of your application's inner workings. It tells the dumb view objects what to do and how to show themselves.
now you can get idea about View and a view controller.
A view and a view controller are two totally different things.
categoryContainerViewController = self.childViewControllers[0] as! CategoriesControllerView
In spite of the name, that is a view controller.
The outlet is to the view.
In layman terms : -
IBOutlet connects any view element from your interface builder to attached swift class file. So you can get reference to any subview of UIView(eg, UILabel, UIButton) from interface builder to your UIViewController or UIView Swift class
In your ex.
by using
categoryContainerViewController = self.childViewControllers[0] as! CategoriesControllerView
You are getting reference to your ChildViewController and not any view

How to add UITableView to UIView which is already a subview?

I have specific situation for which I haven't found solution.
I'm doing over storyboard. So I have ViewController on which I'm using segment control for switching subviews. Every subview is ViewController but one of them is using table view. So basically it's like this:
HomeViewController
FavoritesViewController
Table View (with custom cell)
GalleryViewController
How to properly set up this? Should I rename/refunction FavoritesViewController to FavoritesTableViewController or?
If there is any other question, please ask it.
UPDATE 1:
FavoritesViewController is having just UIView in UI because I don't need whole UIViewController
Create an IBAction from the segmented control. Inside the handling method, use "ViewController containment" to switch between two view controllers.

UIViewController inside XIB?

Currently I'm struggling with creating a subclass of UIViewController or UINavigationController with XIB file as a view.
When I create everything from the Xcode's menu (New File -> Class -> With Nib... etc.) I get a XIB but only with a plain UIView but I want UIViewController instead.
I read somewhere that XIBs are only for a views and you have to handle controller in code, is it true? Because as you can read here it's possible to insert Navigation Controller component into XIB. But I have one problem with the code from this tutorial - I get empty view with empty UINavigationBar. When I do the same with regular View Controller I get info abut this controller being used more than once...
I'm not trying to force Interface Builder to do something unusual but I want to know if this is possible (it would be easier and nicer to modify view controller component insted of a content view)? And if it is, how to achieve this?
I have just checked to confirm whether it is possible and to my surprise it is! You can have UIViewControllers inside Xibs
The test was done in XCode 10.1, Swift 4.2.
I have never used it before, but i thought since it gives you the option from the item library to pick view controllers, it has to be possible. I have added one to my xib, and just like in the storyboards, i have linked it with class, set IBOutlets and IBActions and it all worked perfectly fine.
The key thing is to instantiate it like this:
// Method inside the `UIViewController` you want to present our view controller from xib
// The xib file is `XibViewController.xib` and it has only one item inside - `UIViewController` with custom class set to `XibViewController`
guard let xibViewController = UINib(nibName: "XibViewController", bundle: nil).instantiate(withOwner: self, options: nil).first as? XibViewController else { return }
present(xibViewController, animated: true)
here you can find my test project: https://github.com/stoqn4opm/XibViewController
An XIB file is used for building content that is viewable on a screen. A UIViewController is not viewable. It instead owns a view (which is viewable) created from an XIB or from code.
I think from what you are trying to do is use a storyboard which lets you visually layout your UIViewControllers to define there segue from each other (in your case in a Navigation Controller) which means show the next UIViewControllers view and put it in the UIViewController hierarchy.

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!

Choose subview with UISegmentedControl

I have an iOS application with a subview, as well as a UISegmentedControl. I want to use my UISC to change subview1 to subview2. I decided to drag out a few more ViewControllers onto my storyboard, and put subview1 into the first, and subview2 in the second. After connecting the ViewControllers and making outlets for the subviews, I went back to my main ViewController (at this point there are three) and did
#import "SecondViewController"
SecondViewController *myView;
self.mySubview = myView.myOtherSubview;
but the subview on-screen didn't change. Is my template method of doing this totally wrong? If so, how would you suggest I proceed?
Look at [UIView transitionFromView:toView...]
The basic idea is you'll have to child view controllers (check the docs in UIViewController under the child view controllers section) and transition from the view of one to the view of the other.
https://developer.apple.com/library/ios/documentation/uikit/reference/uiview_class/uiview/uiview.html#//apple_ref/occ/clm/UIView/transitionFromView:toView:duration:options:completion:
This question, IOS Storyboard: Load Multiple Subviews for given position, is the same as mine, phrased better. The answer given there worked.

Resources