Access UIelements without making IBOutlets - ios

I want to access UIElements (e.g Labels and TextFields, etc) of viewController without making IBOutlet connections.
e.g. I have a UITextField in viewController and I want to access it like viewControllerName.textFieldName.text = "something I will set here"
or as the same concept of Android findViewById("id of element")
I have used "Tags" but it does not meet my requirement.

You will create UITextField programmatically, and access the UITextFieldName.text = "Some" programmatically.
Create a label programmatically Check This link

Yes, you can access UIElements(e.g Labels and TextFeilds etc) of viewController without making IBOutlet connections. First give UIElement a Tag.
Then try this. hope this would help:
If you want to access it in the same viewController
let label = self.view.viewWithTag(4) as? UILabel
label?.text = "Hello there"
and if you want to access it from other viewController
in firstViewControler
import UIKit
internal weak var FirstViewController: ViewController?
//in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
FirstViewController = self
}
it will make it accessible in all other viewControllers
then in secondViewController
let newlabel = homeViewController?.view.viewWithTag(4) as? UILabel
newlabel?.text = "new change"

Related

Swift load UIViewController from xib IBOutlets nil [duplicate]

This question already has answers here:
IBOutlet is nil, but it is connected in storyboard, Swift
(31 answers)
Closed 4 years ago.
I'm pulling out what little hair I have left!
I have a UIViewController with a matching .xib file. In the .xib, I have an IBOutlet that I made in interface builder called "titleText"
In a section of my code, I have the following lines:
let fooVC = FooViewController(nibName: "FooViewController", bundle: Bundle.main)
fooVC.titleText = "TEST"
The viewController "seems" to load fine, I get an object of the correct type, but the IBOutlets are not initialized.
Is there an additional step that I need to do to initialize any IBOutlets that I may have?
This has got to be something really simple, right?!
Outlets are nil until the view loads. So just make another variable and store title string like below
class FooViewController: UIViewController {
#IBOutlet titleText:UILable!
var titleString:String?
override func viewDidLoad() {
super.viewDidLoad()
titleText.text = titleString
}
}
Use:
let fooVC = FooViewController()
fooVC.titleString = "TEST"

How does iOS connect a UI object to the view controller object

I'm new to iOS development and not sure how iOS connects a UI object to the underlying view controller object. In Android the UI element has an id set in the designer and used in the view but I don't see the same in Xcode only the following (in the ViewController.swift which doesn't seem to connect to a specific UI element):
#IBOutlet weak var statusLabel: UILabel!
where as in Android I'd do the following in OnCreate()
statusLabel = (TextView)findViewById(R.id.statusLabel);
To change the variable name of the outlet once it's connected, Xcode 9.2 and higher has a refactor feature, which allows you to rename variables easily.
Command + Click on the variable name and then click Rename....
Each instance of the UIViewController class has an underlying UIView property called view. When you are using interface builder, you can ctrl+drag the view you have added to create an IBOutlet which references the view whose properties you have modified in interface builder.
This creates the UI element and will add it as a subview of UIViewController's view and allow you to access it directly in any of the UIViewController's methods, or (assuming its not private) any instance of that UIViewController.
let myViewControllerInstance : ViewController = UIStoryboard.init(name: "main", bundle: nil)!.instantiateViewController(withIdentifier: "ViewControllerStoryboardID")
myViewControllerInstance.myStatusLabel.text = "I can change the label's properties from any instance of the View Controller"
If you need to programmatically modify any properties of your UIView instance before the ViewController appears it is recommended to do so in ViewDidLoad.
class ViewController : UIViewController {
#IBOutlet weak var statusLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
statusLabel.text = "My Status Label" //Accessing your UI element directly
}
}
The alternative to using the storyboards approach would be to instantiate the view programmatically, set it's frame (or add constraints if using auto-layout), and add it as a subview.
class ViewController : UIViewController {
var myStatusLabel : UIView
override func viewDidLoad() {
super.viewDidLoad()
statusLabel = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
self.view.addSubview(myStatusLabel)
statusLabel.text = "This label was created progrommatically."
}
}
In iOS you usually use Storyboards (or sometimes XIB files) to set up your user interface. In a storyboard/XIB you control-drag from your interface into your view controller's code to create or connect outlet links.
The storyboard/XIB is an XML file internally that describes the UI and the links to outlets. At the time the storyboard/XIB is loaded, the system connects the outlet and action links.

Swift/iOS: IBOutlet nil after loading view controller

I'm building an app (in XCode 8.2.1) where some objects are displayed on a 2D board, and when the user taps one of these objects some info should be displayed about it as a styled modal info box. My design is to have the info written in a separate view controller, which I would display when needed.
I've designed a basic stub for the second view controller and added a single label to it in the interface builder. Then I've ctrl-linked this label to my custom VC class:
class InfoViewController: UIViewController {
#IBOutlet weak var info: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func displayInfo() {
info.attributedText = NSAttributedString(string: "abc")
}
}
However, when I test my app and tap the object, the info field is nil even in the viewDidLoad() method of my custom VC class. The way I'm displaying my VC is as follows:
let infoViewController = InfoViewController()
infoViewController.modalPresentationStyle = .overCurrentContext
self.present(infoViewController, animated: true, completion: nil)
infoViewController.displayInfo()
(Note: In the end I will have only one single instance of InfoViewController but this is just for testing. I don't expect having a global instance would make any difference?)
As I said, be it inside the viewDidLoad() method or in the displayInfo() method, info is always nil, such that setting its attributedString attribute crashes the app. Thinking the present method might be called asynchronously, I've tried calling displayInfo() from inside viewDidLoad(), but that didn't make any difference.
Can anyone tell my what I've forgotten that would allow my IBOutlet from being properly initialized properly?
Thanks!
David
The problem is the reference to InfoViewController(), which instantiates the view controller independent of any storyboard scene. You want to use instantiateViewController:
let infoViewController = storyboard?.instantiateViewController(withIdentifier: "Info") as! InfoViewController
infoViewController.modalPresentationStyle = .overCurrentContext
present(infoViewController, animated: true) {
infoViewController.displayInfo()
}
A couple of notes:
This assumes that (a) you've given the scene in the storyboard a "storyboard id"; (b) you've set the base class for that scene to InfoViewController.
Note, I called displayInfo in the completion handler of present because you probably don't want that called until the scene has been presented and the outlets have been hooked up.
Alternatively, you can update non-outlet properties of the InfoViewController immediately after instantiating it and then have its viewDidLoad take those properties and update the outlets, e.g.:
class InfoViewController: UIViewController {
var info: String!
#IBOutlet weak var infoLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
infoLabel.attributedText = NSAttributedString(string: info)
}
}
Note, I changed the #IBOutlet name to be infoLabel and added the String property called info. That tends to be the convention, that outlets bear some suffix indicating the type of control, and model objects, like the String property, are without the suffix. (You'll just want to make sure you remove that old outlet in the connections inspector in IB so that you don't have problems with these property name changes.)
Anyway, you can then do:
let infoViewController = storyboard?.instantiateViewController(withIdentifier: "Info") as! InfoViewController
infoViewController.info = "abc"
infoViewController.modalPresentationStyle = .overCurrentContext
present(infoViewController, animated: true, completion: nil)
The key point is don't try to update outlets of the scene immediately after instantiating it, but make sure that this is deferred until after viewDidLoad was called.
I Replaced
let vc = CCDetailViewController()
With
let vc = self.storyboard?.instantiateViewController(withIdentifier: "CCDetailViewController")
Finally
self.present(vc!, animated: true, completion: nil)
Now It Works...
In my case, I had created new view controller for the same class. Which had ended up with two view controllers in storyboard, but referring to the same class. After deleting old view controller, everything worked fine.
Hope it helps to someone.

Adding Custom input view to UITextField in Swift

I am trying to use a calculator as a custom input view to an UITextField in swift.
I have a calculator separately defined in my app as CalculatorViewController.
I need to access the CalculatorViewController in the UITextField I have in my InputViewController.
I defined the following property in the InputViewController to access the calculator view
var textFieldInputView : UIView!{
let calculatorInputController = self.storyboard?.instantiateViewControllerWithIdentifier("calculatorVC") as! calculatorViewController
let calculatorInputView = calculatorInputController.view
return calculatorInputView
}
then added following code in the textField to access the textFieldInputView
textField.inputView = textFieldInputView
Now when I click the textField, the calculator popup,as per the below, which is not in the position where keyboard appears. Also none of the buttons working.
Much appreciated if some one could advise me how to get this fixed.
Resolved this as per the below.
Created a interface builder "keyboard.xib" with all the UIButton and UILabel for display.
Linked the keyboard.xib to calculatorViewController
Subclass the view controller (say DetailViewController) where the UITextFields are present as the subclass of calculatorViewController.
Created a UIView as per the below code
var customkeyboardView : UIView {
let nib = UINib(nibName: "CalculatorView", bundle: nil)
let objects = nib.instantiateWithOwner(self, options: nil)
let cView = objects[0] as! UIView
return cView
}
Assign the customkeyboardView as an inputView of the UITextField as indicated below
textField.inputView = customkeyboardView

Accessing to a IBOutlet of another class

I have a UIScrollView with a lot of different UIViewController.
In one of this ViewController I want to change the IBOutlet of another UIViewController. The error is : found nil while unwrapping an optional value.
But the textView is not "nil".
import UIKit
class WeirdViewController: UIViewController {
let third = ThirdViewController()
#IBAction func font1(sender: AnyObject) {
third.textView.text = "try"
}
}
According to your code you are creating new ThirdViewController
let third = ThirdViewController()
and in this case third.textView is nil.
What you need is to get reference to the existing object of ThirdViewController which is inside of UIScrollView and then change value of textView.text

Resources