Input from UITextField connected from storyboard to Swift view controller file - ios

Using Swift, how do I get the input from a UITextField?
In my Main.storyboard, I have chosen a "Text Field" from the premade components and dragged it onto my storyboard.
Now how can I access its value in my ViewController.swift?
What I'm currently doing:
I ctrl+drag the text field into my ViewController.swift file. Then in the popup-box I choose "outlet" and name it "myInput".
Then in another function, I access its value by using self.myInput.text.
Is this the only way to access its input? Is my approach following Swift conventions?

Yes, your approach of creating an IBOutlet from the storyboard and referencing it using self.myInput.text is a standard way of accessing this field in Swift.
As for whether to use self.myInput vs. myInput, I prefer to always write self because it is very obvious that the variable is a property and will probably be changed in many different places (opposed to a local var). Also, once you have self there, you don't have to worry about introducing local vars with the same name or making changes if you copy and paste a block of code into a closure that requires self.

Related

Can we access the objects in Storyboard by ObjectID

I have a bunch of static objects (UILabel, buttons, views) in multiple Scenes. They are not connected to any IBOutlet. But I'd like to access them at appdelegate (or first VC), and change their properties before it is loaded.
Anyway to do this?
EDIT: Adding my intention:
I actually wanted to make a custom "multi-language" app. I want to be able to change language from within the app. I can get a list of all the objects by applying built in localization of storyboard (Main.strings is autogenerated). Then I disable localization again. Then from this autogenerated file, I want to be able to connect it to a json data based on language that I select.
Of course you can. For example, you can use tags of UIView. Just set tags in Storyboard. It's easy but not so good. Another way to do this is using Accessibilities. Enable and set for it in Storyboard.
And then you can access it by accessibilityIdentifier property.
I will post my choice of "solution". So what I did was make use of accessibilityIdentifier to set the "key" for the multilanguage phrase translation purpose.
And I make use of the UIView+Recursion class (you can find this simple class somewhere in SO), and basically iterate all the objects in a particular Scene and if the text matches, set the key in accessibilityIdentifier property (either in viewDidload or viewWillAppear or viewDidlayoutSubviews).
This way you can have language changes "on-the-fly" within the app, without restarting.

Wrapping my mind around Objects in iOS

I'm having trouble understanding the idea of objects. From what I've read, they're instances of a class. When learning swift, they're quite easy to understand. Simply create a class and create an instance of it, and from there, you can modify it's properties and call its methods:
class ExampleClass {
let ExampleProperty = "rabbit"
}
let exampleInstance = ExampleClass()
But I don't see how that translates when using iOS, since I haven't seen any objects being created explicitly yet:
var example = Wss()
So my questions are:
Are things like buttons, labels, and sliders objects?
-If so, where's the "code" behind them? Why do buttons, labels, etc. display even before they're connected through outlets and actions to the View Controller? Is there a hidden "var thisButton = ThisViewController()" embedded into each of those sliders and buttons?
If my assumptions are wrong, can someone explain to me how objects work?
"Is there a hidden "var thisButton = ThisViewController()" embedded into each of those sliders and buttons?"
No, and this is exactly where interface builder excels. Much of Xcode's modern Interface Builder comes from NeXTSTEP. When you drag out a new UI component like NSButton and place it on your story board, Xcode is instantiating a new object of the NSButton class for you. When you save your file, Xcode serializes all the objects of your story board into a .nib file. At the time when this was invented, it was quite revolutionary, all made possible because of the dynamism of Objective C. It made GUI programming much simpler and dynamic. Every object in your story board is aware of its class. For example, when you instantiate a new NSButton, you can open the inspector and see for yourself that its class is NSButton. When you add custom views to your application, they keep track of their class in the same way. Whenever a nib file is loaded, these views are instantiated from their classes. You might have noticed that you never override the initializer of your views. Instead, you override methods like awakeFromNib. This is because there's a lot of behind the scenes work being done for you, from the time the object is first instantiated, to the time. During this time IBOutlets and IBActions are bound for you.
Competitors tried to make similar interface building applications, but they ultimately resorted to doing code generation behind the scenes. In these systems, when you saved your interface file, the program would generate a source file that contains code that instructs how to instantiate these objects anew whenever the interface is loaded. However, it proved significantly more complex a task then just serializing the objects, so these systems were error prone, and significantly harder to debug (because you'd be trying to debug machine generated source files).
Answering your questions:
Yes. Your objects are just being created from a NIB, or Storyboard. So the NIB, or Storyboard, will create those visual (UI) elements for you, which you can then be accessed via the IBOutlets
Your assumptions, are not completely wrong as in, there is in fact something allocating those objects for you. The NIB, or Storyboard, just describe a way for those objects to be created. Also some other customisations, like frames, colors, etc.
More about how this ties up can be found here.
Building on Alexander's answer:
UIView objects have a method init(frame:) that lets you create a new UIView object with a specified frame.
Other UIView subclasses might have init methods that take additional parameters.
UIView objects also support an init method init(coder:) that knows how to create an object from a stream of stored data. This is known as "deserializing" the object, or converting it from a byte-stream back into a running object.
When you build an object in a Storyboard or XIB file in Interface Builder, the system serializes the object into a byte stream and saves it into your Storyboard/XIB.
Then when you invoke the storyboard scene/XIB, the system reads the data stream and uses it to recreate (deserialize) the objects that are described in the storyboard/XIB.
The effect is essentially the same as if you wrote a bunch of code that created and configured all your views, but instead of writing all that code you are able to build your interface in Interface Builder, which is faster and easier to create, and MUCH faster and easier to update and maintain than a bunch of custom code.
But I don't see how that translates when using iOS, since I haven't seen any objects being created explicitly yet
There's no difference between the objects in iOS and what you understand objects to be. Objects are instances of a class. What you need to understand is that your own code is not the only place where objects can be created, and your own code will often interact with objects created outside your code. Here's a simple example:
let defaults = NSUserDefaults.standardUserDefaults()
Here defaults gets a reference to a user defaults object that the system provides. You never need to instantiate NSUserDefaults yourself.
Are things like buttons, labels, and sliders objects?
Yes, those are instances of UIButton, UILabel, and UISlider, respectively.
If so, where's the "code" behind them?
It's in the UIKit framework. You don't get to see the source code for those classes, but you can still use them by linking the framework into your app.
Why do buttons, labels, etc. display even before they're connected through outlets and actions to the View Controller?
You're talking about storyboards here. When you set up a view in Xcode's storyboard editor, the data that's stored in the storyboard file is essentially an archive containing serialized objects. When a view controller is instantiated from a storyboard, the objects in the storyboard are recreated from that data and then connected to the view controller's outlets. You can start this process yourself by instantiating a new view controller like this:
let storyboard = UIStoryboard(name: "MyStoryboard", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "MyViewController")
You don't usually need to do that, though, because the segues in your storyboard provide for transitioning between scenes, including creating the view controller that's the destination of a given segue.

Avoid hard coding storyboard IDs in 2 places

When I want to set an ID for a View Controller I go into the storyboard file, select the ViewController, then on the Identity inspector I type in the Storyboard ID as something like "theVCID":
When I want to use that View Controller in code I do something like:
UIViewController *myVC = [myStoryboard instantiateViewControllerWithIdentifier:#"theVCID"];
Is there a way I can just hardcode this ID string in one location instead of hard coding it inside storyboard and when I use it in code?
If I could get a variable in the storyboard XML, I could just get the hardcoded string variable inside the XML source, but I don't know how/where to set up a variable so that the storyboard XML can access it.
Unfortunately you are forced to duplicate the declaration.
I wouldn't recommend parsing the XML as you will be basing that on the assumption of an implementation detail. Technically, storyboards could change their data type to anything in the future and this would break your implementation.
The safest way to do this is to keep your storyboard identifiers in a single class (say StoryBoardCoordinationController) and simply reference the storyboard objects through this single interface. Hopefully you should never be in the situation where these values are changing often, and if they are you should definitely seek to do something about it:)

iOS Interface Builder: How to make templates

I've recently started developing an iOS app, which I've never done before, so it's been going a bit slow, but I'm learning, so that's understandable.
I want to make a custom interface, so I've been making subclasses of the default view classes (like UIButton) so that I can define custom drawing. I've been told this is the best way to define custom interface elements that can be reusable. It definitely seems to be working that way. However, I haven't been able to make elements completely reusable by just using a subclass.
For example, in order to prevent a button's text from changing color when it is clicked, I have to manually go into the interface builder and set the button type to "Custom." After that, code that I enter into the subclass's constructor to change attributes seems to work. But I have to do this for every button I add, and in code the "buttonType" attribute is read only. Is there a way for me to define (just once) certain attributes for every instance of my button subclass that I add to the interface?
My goal is to be able to have a button subclass or template that defines all attribute values that I want my buttons to have, and every instance that I add automatically reflects those properties without me having to change anything. More so, I want to be able to modify that subclass/template and have those changes reflected in every existing instance. I have to imagine that this is possible in iOS. There is simply no way to build sophisticated interfaces without this capability.
Define a custom Button class (inherited from UIButton) in your project and in the init set the properties which you wanted to be set across.
In the interface builder go to the the class inspector and enter the button to be of the previously declared button.
buttonType needs to be set for all the button as this is defined at initialization time and exposed as read only property. If you want absolute reusability for your case, create a view, with an embedded button in code. when you create a button, create using the static method buttonWithType.
Wherever you need, drag and drop a UIView and set the view type to be the custom view.

How to generate UIviews in Xcode?

I'm very new to Xcode and programming in general. I have made my first app, submitted it and to be terribly honest it crashed and burned.
Onwards I go. I am now interested in just creating a basic reminders app so that I can teach myself a little bit more. What I mainly don't get is how you can take a main user input questionnaire framework (e.g. Name: X, Time: X, Date: X), save it and generate another UIView with this information?
Thank you in advance.
-S
If you want to create this with the latest technology you can create a project with a storyboard.
Add labels for Name, Time, Date and position them in the view of your choice in your storyboard.
Add a UITextField for each label. Use the cntrl + drag technique from your storyboard to your class.
To do this open the Assistant editor.
Make sure the correct class file is open on the right panel. (you can get this by choosing the automatic options)
cntrl + drag from each textField either to your associated class's .h or the private properties in the .m
Once you have these IBOutlets connected, add the textField Delegate protocol to the .h file.
Implement the delegate methods, there are many tutorials on using UITextFields.
Create a Questionnaire Class with the 3 properties. Initialise a questionnaire object and assign the associated textfield.text strings to the object's properties.
Then you can pass that Questionnaire object to whatever viewController you like and access the properties to use the string data.
Be sure to use copy for strings, this stops modifications to a string from effecting newly assigned strings. (as not copying will be a pointer to a pointer(which can change or even end up pointing to another valid object due to memory reuse by the OS, causing unrecognisedSelector crashes), rather than a pointer to the copied data location)
#property (nonatomic, copy) NSSString *someString;

Resources