Unable to access UIView subclass IBOutlets From TabBarController - swift

I have a UIView Class with xib. I try to add it in another ViewControllers as a popover view. I have outlet connections. But when I run the application it crashed and stated
This class is not key value coding-compliant for the key btnAbtUs
I think the problem is should select delegate. I may using wrong way to add this xib. How can I correct it?
Here is my code.
my UIView subclass
class MoreView: UIView {
#IBOutlet var containerView: UIView!
#IBOutlet weak var btnAboutUs: UIButton!
override public func awakeFromNib() {
super.awakeFromNib()
}
override init(frame: CGRect) {
super.init(frame: frame)
loadViewFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadViewFromNib()
}
func loadViewFromNib() {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "MoreView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.insertSubview(view, at: 0)
commitInit()
}
private func commitInit(){
containerView.translatesAutoresizingMaskIntoConstraints = true
self.btnAboutUs.addTarget(self, action: #selector(self.clickAboutUs(_:)), for: .touchUpInside)
}
class func instanceFromNib() -> UIView {
return UINib(nibName: "MoreView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}
#objc func clickAboutUs(_ sender: Any) {
print("tap")
}
}
in UITabBarController
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
let moreView = MoreView.instanceFromNib
if let navigationController = viewController as? UINavigationController,
navigationController.viewControllers.contains(where: { $0 is MoreViewController }) {
moreView().frame.origin.y = 100
self.view.addSubview(moreView())
return false
} else {
moreView().removeFromSuperview()
return true
}
}

Finally I found the issue. This is the right way to add a UIView as a SubView controller of a UIViewController.
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if let navigationController = viewController as? UINavigationController,
navigationController.viewControllers.contains(where: { $0 is MoreViewController }) {
let mySubView : MoreView
mySubView = MoreView(frame: CGRect(x: 0, y: 0, width: 375, height: 667) )
self.view.addSubview(mySubView)
return false
} else {
return true
}
}

You might have copied the XIB and forgot to remove/add a connection with the IBOutlet. Please check.
It indicates that an already connected Interface Builder object is removed/renamed in its owner's source (File's Owner).

You may forgot to remove a connection with the IBOutlet. Please check on on show connection inspector.First click on file inspector of xib then click on show connection inspector. Shown in image.
Remove the broken outlets.

Related

Call to IBOutlet in custom UIView from another class

I am looking for a way to refer to the IBOutlet variable in a custom class UIView, from another class. I found layoutSubviews, but each change only works on the first call, and not on each subsequent call. Thanks for help!
ViewController class:
var SB = StatusBar()
SB.update(1)
SB.update(2)
SB.update(3)
StatusBar class:
class StatusBar: UIView {
#IBOutlet var view: UIView!
#IBOutlet weak var label: UILabel!
var ActualStatus: Int!
required init?(coder: NSCoder) {
super.init(coder: coder)
xibSetup()
}
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
func update(status) {
ActualStatus = status
self.layoutSubviews()
}
override func layoutSubviews() {
super.layoutSubviews()
label.text = ActualStatus
}
func xibSetup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of:self))
let nib = UINib(nibName: "StatusBar", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
}
Result: label.text is 1, change only works on the first call

Crash on DidSet from external XIB

I have an external XIB that is #IBDesignable.
Inside the view that shows this XIB, I have this outlet.
#IBOutlet weak var digitizingButton: DigitizingButton! {
didSet {
digitizingButton.buttonIsBeingTouched = {[weak self] in
// bla bla
}
}
}
crash on
digitizingButton.buttonIsBeingTouched = {[weak self] in
EXC_BAD_ACCESS (code 2)
DigitizingButton loads like this:
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
self.loadViewFromNib()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.loadViewFromNib()
}
/** Loads instance from nib with the same name. */
func loadViewFromNib() {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: .init(String(describing: type(of: self))), bundle: bundle)
let myView = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
self.view = myView
self.addSubview(myView)
}
Any ideas what is going on? Thanks in advance.
Try to change the approach of your initialization.
Add an IBOutlet from the first view of your xib file to the swift file:
#IBOutlet var containerView: UIView!
Then edit your loadViewFromBib method as follow:
func loadViewFromNib() {
Bundle.main.loadNibNamed("DigitizingButton", owner: self, options: nil)
addSubview(containerView)
containerView.frame = self.bounds
containerView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
// Other initialization here
}

Loading UIView from Bundle only fills screen partially

Hello there.
Using Swift 4, I am attempting to load a Custom UIView with XIB onto a UIViewController.
However, it only seems to fill the screen partially, and I'm not sure why.
I did the following:
The view controller is defined in a UIStoryboard
UIViewController that adds the UIView in the viewDidLoad
The UIView swift file and the XIB are connected via the File Owner property
The XIB file is added into the copy bundle resources
The hot pink background color is set using the Xcode visual editor, its not done in code.
I simulate using the iphone xr, but I get the same issue if I simulate on iPhone 6s
The view controller code is empty, but I've included the relevant part:
// QuestionViewController
class QuestionViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let subview = QuestionView()
self.view.addSubview(subview)
}
}
The UIView is also pretty basic:
class QuestionView: UIView, XibView {
override init(frame: CGRect) {
super.init(frame: frame)
setupXib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupXib()
}
func setupXib() {
guard let v = loadFromXib() else {
return
}
addSubview(v)
}
}
I use a protocol that I found on stackoverflow to load the xib file from bundle. Originally I had a lot of issues even loading the bundle, but fortuently I was able to rectify this issue. Anyway, my XIB protocol file is here:
// XIB protocol file
protocol XibView {
func setupXib()
func constrainView(_ view: UIView)
func loadFromXib() -> UIView?
}
extension XibView where Self: UIView {
func setupXib() {
if let xibView = loadFromXib() {
addSubview(xibView)
constrainView(xibView)
}
}
func constrainView(_ view: UIView) {
view.translatesAutoresizingMaskIntoConstraints = false
addConstraints(
NSLayoutConstraint.constraints(
withVisualFormat: "V:|[view]|",
options: [.alignAllCenterX, .alignAllCenterY],
metrics: nil,
views: ["view": view]
)
)
addConstraints(
NSLayoutConstraint.constraints(
withVisualFormat: "H:|[view]|",
options: [.alignAllCenterX, .alignAllCenterY],
metrics: nil,
views: ["view": view]
)
)
}
func loadFromXib() -> UIView? {
let xibView = UINib(nibName: String(describing: Self.self), bundle: Bundle(for: type(of: self))).instantiate(withOwner: self, options: nil).first as? UIView
return xibView
}
}
--
Question:
Why does the UIView not fill the entire screen or only fill the screen partially and how can I resolve this?
With thanks
Edit:
The storyboard looks for the UIViewController only has a single view with no content.
I think you should take a UIview(0,0,0,0 four constraints) in Your Viewcontroller and then assign it a custom class which is a subclass of UIView and then load the Xib file and it will surely occupy the whole screen
Try this man::----
class QuestionViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let subview = QuestionView()
subview.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.width)
self.view.addSubview(subview)
}
}

Hide Custom View UIButton From UIViewController Class

Actually i have a Custom view with two button, and i want to hide it at runtime through UIViewController , So i don't get any exact thing to hide that button from UIViewcontroller class
Here is my CustomView class,
import UIKit
class BottomButtonUIView: UIView {
#IBOutlet weak var btnNewOrder: UIButton!
#IBOutlet weak var btnChat: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
// MARK: init
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
if self.subviews.count == 0 {
setup()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup() {
if let view = Bundle.main.loadNibNamed("BottomButtonUIView", owner: self, options: nil)?.first as? BottomButtonUIView {
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(view)
}
}
#IBAction func btnOrderNowClick(_ sender: Any) {
let VC1 = StoryBoardModel.orderDeatalStoryBord.instantiateViewController(withIdentifier: "NewOrderViewController") as! NewOrderViewController
VC1.isPush = false
let navController = UINavigationController(rootViewController: VC1) // Creating a navigation controller with VC1 at the root of the navigation stack.
let currentController = getCurrentVC.getCurrentViewController()
currentController?.present(navController, animated:true, completion: nil)
}
#IBAction func btnChatNowClick(_ sender: Any) {
}
func getCurrentViewController() -> UIViewController? {
if let rootController = UIApplication.shared.keyWindow?.rootViewController {
var currentController: UIViewController! = rootController
while( currentController.presentedViewController != nil ) {
currentController = currentController.presentedViewController
}
return currentController
}
return nil
}
}
I set it to UIView in StoryBoard, and then I create outlet of that view,
#IBOutlet weak var viewBottmNewOrder: BottomButtonUIView!
Now i want to hide btnNewOrder from UIViewcontroller class but when i use
viewBottmNewOrder.btnNewOrder.isHidden = true it cause null exception, Please do need full answer.
Please don't do like that. The required init(coder aDecoder: NSCoder) will call a lot of times when the BottomButtonUIView created from xib. And your custom view will look like:
[BottomButtonUIView [ BottomButtonUIView [btnNewOrder, btnChat]]].
So when you access to btnNewOrder like that:
viewBottmNewOrder.btnNewOrder it will null.
I think you should add your custom view in viewDidLoad of your `UIViewController'.

Xib file renders when called by my page view controller but not as a tab

I'm rendering a Xib file which is a subview in a view controller, the view controller is called by setViewController in a pageviewcontroller . It works great. I then placed the same Xib sub view in a view controller called by my tab view controller and it doesn't render.
To try and get to the bottom of this weird occurrence I have removed all code such that there is no class attached to the UIviewcontroller parent of the subview Xib in both cases. It is now a pure IB implementation of the Xib and the Xib classes are identical.
So in my comparison between the two implementations the only difference is one is opened from a page view controller and the other from a tab. I even copied the working view controller just so I knew they were identical.
Has anyone had this experience (where the same Xib doesn't render in one workflow compared to another) or have an idea as to why the two implementations cause different results??
Update: I took it one step further. Now there is absolutely no code. The only thing that is in the Xib is an unattached label. It only renders when the parent view is called from a page view controller! Wtf
Signin View Xib. (Works when instantiated from UIPageViewController:
SigninView.swift
class SigninView: UIView, GIDSignInUIDelegate, GIDSignInDelegate {
var view: UIView!
var nibName: String = "SigninView"
var delegate: SigninViewDelegate?
#IBOutlet weak var googleButton: GIDSignInButton!
#IBOutlet weak var signoutButton: UIButton!
override init(frame: CGRect) {
// properties
super.init(frame: frame)
// Set anything that uses the view or visible bounds
setup()
}
override func awakeFromNib() {
print("AWAKING!")
}
#IBAction func tapSignOut(sender: AnyObject) {
GIDSignIn.sharedInstance().signOut()
UserManager().logout()
self.updateDisplay()
}
required init?(coder aDecoder: NSCoder) {
// properties
super.init(coder: aDecoder)
// Setup
setup()
}
func setup() {
view = loadViewFromNib()
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().delegate = self
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
addSubview(view)
self.updateDisplay()
}
func updateDisplay() {
self.googleButton.layer.hidden = false
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: nibName, bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
func signIn(signIn: GIDSignIn!, presentViewController viewController: UIViewController!) {
//present vc on delegate
let delegateVC = self.delegate as! UIViewController
delegateVC.presentViewController(viewController, animated: true, completion: nil)
}
func signIn(signIn: GIDSignIn!, dismissViewController viewController: UIViewController!) {
print("Dismiss view controller")
let delegateVC = self.delegate as! UIViewController
delegateVC.dismissViewControllerAnimated(true, completion: nil)
self.updateDisplay()
}
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
var success = false
if (user != nil) {
print("signed in? UID: \(user.userID), email: \(user.profile.email), name: \(user.profile.name), pic: \(user.profile.imageURLWithDimension(150))")
UserManager().createUser(user)
LocalDataStorage().saveContext()
success = true
} else {
print("User not signed in.")
}
self.updateDisplay()
if self.delegate != nil && self.delegate!.signInComplete != nil {
self.delegate!.signInComplete!(success)
}
}
func signIn(signIn: GIDSignIn!, didDisconnectWithUser user: GIDGoogleUser!, withError error: NSError!) {
print("disconnected")
}
}
Working UIViewController that contains working Signin Subview
Working call from UIPageViewController
let vc = UIStoryboard(name: "Intro", bundle: nil).instantiateViewControllerWithIdentifier("IntroPage2")
setViewControllers([getSlide(index)],direction: .Forward,animated: true,completion: nil)
UIViewController called from tab view that does not render signin subview
I am posting AN answer but really it's more of a work around. After hours of trying to finagle the views I get the code working consistently. To get it working created a new Xib and new VC file for the Signin module. I copied all the code from my original Signin class to the new one and it worked. No code was altered.
So if anyone comes across the gnarly painful situation give that a shot! This could very well be an XCode bug.