Now only i am start working with swift language. I have initialize the button as follows
#IBOutlet weak var systemTextButton: UIButton!
after that i can set the title using .setTitle() property.
If i use ? instead of ! while initialize then showing the error on .setTitle() as
UIButton? does not have a member named 'setTitle'
So, Anyone please tell me the difference between UIButton! and UIButton? .
Both of them are optional types. But UIButton! is implicitly unwrapping optional type. You don't have to unwrap it manually. Take a not that your app will crash if you try to access value of UIButton! while its nil.
For more info read "Implicitly Unwrapped Optionals" section in Apple's "The Swift Programming Language" book.
The button is optional because it is not determined from the beginning if the button will be found in the interface builder document. So either
you are sure it will be there, in which case you unwrap it right in the declaration,
or it is really an optional - then you have to unwrap it each time you want to use it.
Maybe the existence of the button in interface builder is somehow dynamic, then you would keep it optional (UIButton?) to allow a nil value. In this case you have to either check for its existence before you use it, or unwrap it with myButton!. You do this at your own risk because if you try it on a nil value your program will crash.
Both variants are dealing with optionals (variables that may be nil).
#IBOutlet weak var systemTextButton: UIButton!
This is an implicitly unwrapped optional. The exclamation mark states that you (the programmer) are absolutely sure that this variable is not nil when using. You set the title via
systemTextButton.setTitle(...)
If systemTextButton is nil at that point the application crashes.
The questionmark states that this variable may be nil, so you have to use:
systemTextButton?.setTitle(...)
Now, setTitle() is only executed if systemTextButton is not nil.
Hope that helps.
For further reference on optionals see The Swift Programming Language
In this two examples the UIButton is declared as optional.
The difference is that when you declare it as UIButton! it's unwrapped for you automatically, you don't have to check is it nil, you should be sure that the button will not be nil.
The other declaration UIButton? doesn't unwrap this optional for you, you have to do it manually when you want to access it (or access it's properties).
You can do it in two way. If you are sure that the object is not nil you can use this:
button!.setTitle()
but if you are not sure about state of this optional, use this:
if let btn = button {
btn.setTitle()
}
else {
// button is nil
}
When you declare the variable of type UIButton?, you are saying to compiler that that variable could be nil (NULL in Objective-C world). So, it becomes an "optional", and all subsequent actions an that object are skipped if it's nil.
For example:
class MyClass {
var property: String?
}
let myInstance = MyClass()
if let testVar = myInstance.property {
println("Hello world")
} else {
println("Property unset")
}
You can find more info in the official swift documentation:
https://developer.apple.com/librarY/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html
These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional.
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation mark
Straight from Apple Developer Library
Related
I met a strange issue today. Please look at this code:
class A {
var button1: UIButton!
var button2: UIButton!
func foo() {
let array = [button1, button2]
}
}
Xcode says that array is [UIButton?] type. For some reason Swift4 casts UIButton! elements to UIButton?. Why?
EXPLANATION
ImplicitlyUnwrappedOptional is not a distinct type, rather a normal Optional with an attribute declaring its value may be implicitly forced (based on SE-0054):
However, the appearance of ! at the end of a property or variable declaration's type no longer indicates that the declaration has IUO type; rather, it indicates that (1) the declaration has optional type, and (2) the declaration has an attribute indicating that its value may be implicitly forced. (No human would ever write or observe this attribute, but we will refer to it as #_autounwrapped.) Such a declaration is referred to henceforth as an IUO declaration.
Thus when you use this:
let array = [button1, button2]
The compiler derives the array type to [UIButton?], because the type of the button1 and button2 is Optional<UIButton>, not ImplicitlyUnwrappedOptional<UIButton> (even if only one of the buttons was optional, it would derive the optional type).
Read more in SE-0054.
Side note:
This behavior is not really related to arrays, in the following example the type of button2 will be derived to UIButton? even though there is the ! and there is a value set in button:
var button: UIButton! = UIButton()
func foo() {
let button2 = button // button2 will be an optional: UIButton?
}
SOLUTION
If you want to get an array of unwrapped type, you have two options:
First, as Guy Kogus suggested in his answer, use explicit type instead of letting swift derive it:
let array: [UIButton] = [button1, button2]
However, if per chance one of the buttons contains nil, it will cause Unexpectedly found nil crash.
While by using implicitly unwrapped optional instead of optional (! instead of ?) you are claiming that there never will be nil in those buttons, I would still prefer the second safer option suggested by EmilioPelaez in his comment. That is to use flatMap (compactMap in Swift 4+) which will filter out nils, if there are any, and will return an array of unwrapped type:
let array = [button1, button2].flatMap { $0 }
Because UIButton! is not a type, or rather it is a UIButton? with some conventions. The ! means always implicitly unwrap the optional. The following
var x: UIButton!
// Later
x.label = "foo"
Is syntactic sugar for
var x: UIButton?
// Later
x!.label = "foo"
When you create an array of them. The compiler has the choice of implicitly unwrapping them and inferring [UIButton] or leaving them as optional and inferring [UIButton?]. It goes for the safer of the two options.
Swift is playing it safe by assuming them to be optionals, rather than unwrapping them by default, since they can technically be nil. If you try to explicitly mark them as implicitly-unwrapped like this
let array: [UIButton!] = [button1, button2]
you will receive the following error:
error: implicitly unwrapped optionals are only allowed at top level and as function results
In that case, if you want them to be unwrapped then just define it as
let array: [UIButton] = [button1, button2]
I'm finding Swift blog as really the best source for such changes so:
Before Swift 4:
A mental model many people have for implicitly unwrapped optionals is that they are a type, distinct from regular optionals. In Swift 3, that was exactly how they worked: declarations like var a: Int? would result in a having type Optional, and declarations like var b: String! would result in b having type ImplicitlyUnwrappedOptional.
Swift 4
The new mental model for IUOs is one where you consider ! to be a
synonym for ? with the addition that it adds a flag on the declaration
letting the compiler know that the declared value can be implicitly
unwrapped.
In other words, you can read String! as “this value has the type
Optional and also carries information saying that it can be
implicitly unwrapped if needed”.
This mental model matches the new implementation. Everywhere you have
T!, the compiler now treats it as having type T? , and adds a flag in
its internal representation of the declaration to let the type checker
know it can implicitly unwrap the value where necessary.
All the quotes taken from Swift blog
I have a question for you guys. I'm trying to avoid do implicit unwrap variables but I haven't figure out how to do it. Here is my example with implicit unwrap
class MyView : UIView {
#IBOutlet var button : UIButton!
var buttonOriginalWidth : CGFloat!
}
There is a way of avoid the implicit unwrap ?
I'll really appreciate your help.
Implicitly unwrapped optionals can be avoided by:
Declare a initial value:
var buttonOriginalWidth: CGFloat = 20.0
Declare its value within init:
var buttonOriginalWidth: CGFloat
init() {
self.buttonOriginalWidth = 20
super.init()
}
You can always declare it as an optional:
var buttonOriginalWidth: CGFloat?
But that of course means you have to unwrap it yourself next time you call it.
You can also use lazy to declare a property that is set after init.
That being said, you should not always avoid using implicitly unwrapped optionals. They are especially useful if you are using Storyboard. #IBOutletand #IBAction are declared mostly as implicitly unwrapped optionals.
#IBOutlet var button: UIButton!
Because if you have configured your Storyboard correctly, it will never be nil.
You can avoid that by adding ? called optional instead of ! which is force unwrapping the variable for example:
#IBOutlet var button : UIButton?
Is a valid point to add it for Outlets connected from storyboard and it actually doesn't prevent you from doing that, but its by default optionals for Outlets connected from storyboard. And also for a variable:
var buttonOriginalWidth : CGFloat?
And to use the a variable which is optional you'll need to check first that its not actually still nil using if let or guard let as the following:
if let widthIsValid = buttonOriginalWidth {
// use the widthIsValid here
}
And if you tried to use the variable without force unwrapping the app at least will not crash for example to do like Which will print it like Optional(478431):
print(buttonOriginalWidth)
I recommend you to read about Optional Chaining in Swift.
In case of the outlet, don't avoid it
#IBOutlet var button : UIButton!
is intended. It reveals a design error (outlet not connected) if the code crashes.
In case of a regular variable – especially scalar types and strings – declare it as non-optional
var buttonOriginalWidth : CGFloat = 0.0
Basically use implicit unwrapped optionals only for outlets and variables which cannot be initialized via init but are supposed to have a value when they are used the first time. It's up to you – the developer – to handle the cases carefully. In all other cases if a variable needs to be optional use a regular optional (?).
I met a strange issue today. Please look at this code:
class A {
var button1: UIButton!
var button2: UIButton!
func foo() {
let array = [button1, button2]
}
}
Xcode says that array is [UIButton?] type. For some reason Swift4 casts UIButton! elements to UIButton?. Why?
EXPLANATION
ImplicitlyUnwrappedOptional is not a distinct type, rather a normal Optional with an attribute declaring its value may be implicitly forced (based on SE-0054):
However, the appearance of ! at the end of a property or variable declaration's type no longer indicates that the declaration has IUO type; rather, it indicates that (1) the declaration has optional type, and (2) the declaration has an attribute indicating that its value may be implicitly forced. (No human would ever write or observe this attribute, but we will refer to it as #_autounwrapped.) Such a declaration is referred to henceforth as an IUO declaration.
Thus when you use this:
let array = [button1, button2]
The compiler derives the array type to [UIButton?], because the type of the button1 and button2 is Optional<UIButton>, not ImplicitlyUnwrappedOptional<UIButton> (even if only one of the buttons was optional, it would derive the optional type).
Read more in SE-0054.
Side note:
This behavior is not really related to arrays, in the following example the type of button2 will be derived to UIButton? even though there is the ! and there is a value set in button:
var button: UIButton! = UIButton()
func foo() {
let button2 = button // button2 will be an optional: UIButton?
}
SOLUTION
If you want to get an array of unwrapped type, you have two options:
First, as Guy Kogus suggested in his answer, use explicit type instead of letting swift derive it:
let array: [UIButton] = [button1, button2]
However, if per chance one of the buttons contains nil, it will cause Unexpectedly found nil crash.
While by using implicitly unwrapped optional instead of optional (! instead of ?) you are claiming that there never will be nil in those buttons, I would still prefer the second safer option suggested by EmilioPelaez in his comment. That is to use flatMap (compactMap in Swift 4+) which will filter out nils, if there are any, and will return an array of unwrapped type:
let array = [button1, button2].flatMap { $0 }
Because UIButton! is not a type, or rather it is a UIButton? with some conventions. The ! means always implicitly unwrap the optional. The following
var x: UIButton!
// Later
x.label = "foo"
Is syntactic sugar for
var x: UIButton?
// Later
x!.label = "foo"
When you create an array of them. The compiler has the choice of implicitly unwrapping them and inferring [UIButton] or leaving them as optional and inferring [UIButton?]. It goes for the safer of the two options.
Swift is playing it safe by assuming them to be optionals, rather than unwrapping them by default, since they can technically be nil. If you try to explicitly mark them as implicitly-unwrapped like this
let array: [UIButton!] = [button1, button2]
you will receive the following error:
error: implicitly unwrapped optionals are only allowed at top level and as function results
In that case, if you want them to be unwrapped then just define it as
let array: [UIButton] = [button1, button2]
I'm finding Swift blog as really the best source for such changes so:
Before Swift 4:
A mental model many people have for implicitly unwrapped optionals is that they are a type, distinct from regular optionals. In Swift 3, that was exactly how they worked: declarations like var a: Int? would result in a having type Optional, and declarations like var b: String! would result in b having type ImplicitlyUnwrappedOptional.
Swift 4
The new mental model for IUOs is one where you consider ! to be a
synonym for ? with the addition that it adds a flag on the declaration
letting the compiler know that the declared value can be implicitly
unwrapped.
In other words, you can read String! as “this value has the type
Optional and also carries information saying that it can be
implicitly unwrapped if needed”.
This mental model matches the new implementation. Everywhere you have
T!, the compiler now treats it as having type T? , and adds a flag in
its internal representation of the declaration to let the type checker
know it can implicitly unwrap the value where necessary.
All the quotes taken from Swift blog
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "segueone")
{
let cellIndexPath = self.tableView!.indexPathForCell(sender as UITableViewCell)
if let unwrappedCellindexPath = cellIndexPath
{
var nextVC = (segue.destinationViewController as TableTwo)
nextVC.items = items[unwrappedCellindexPath.row]
}
}
}
With this piece of code, I have a few questions regarding the optionals. I recently read-through the apple developer web document as well as a few personal explanations of optionals but still have question.
Anyways,
in the line
let cellIndexPath = self.tableView!.indexPathForCell(sender as UITableViewCell)
Is this statement only considered to be an optional because a user may not select one of the cells in my table? And with that, since I know that as long as a user wants to continue through the app, they must select a cell, I can place the exclamation point in to notify the compiler that this cell does in deed have a value(index path)?
Why does the exclamation point go after "self.tableview" and not after "sender as UITableView) in parentheses?
If my assuming is correct, I am able to use the if let syntax because I have an optional in the previous line of code?
let cellIndexPath = self.tableView!.indexPathForCell(sender as UITableViewCell)
Uses an exclamation point after tableView, because self.tableView! may not have been set (it may be nil).
It is an optional because it has the option to have a value, and it also has the option to be nil. Variables that are not optionals cannot be nil, they have to have a value.
The exclamation point goes after tableView because that is the optional which could be nil. If it went after .indexPathForCell(sender as UITableViewCell), that would imply that the value returned could be nil.
You can use the if let syntax because of this optional. This will return true if the value can be assigned to the variable. For example:
var myNilValue: String?
if(let nonNilValue = myNilValue){
//this will not be called
}
if let will return false, but:
var myNonNilValue: String? = "Hello, World!"
if(let nonNilValue = myNilValue){
//this will be called
}
Will return true.
Question marks ? are used after variable declarations to define that the variable may not have a value, and it may never have a value. They need to be unwrapped by using an exclamation point ! after the variable name. This can be used for results from a database, in case there is no result.
Exclamation points ! are used after variable declarations to define that the variable may not have a value, but it will have a value when you need to access it. They do not need to be unwrapped, but the compiler will throw an error if the variable is nil at the time of accessing it. This is typically used in #IBOutlets or #IBActions which are not defined until the program compiles
Both self.tableView and indexPathForCell() are optionals. By banging one, you only have one optional to dereference in the result. sender is also an optional and indexPathForCell() doesn't take an optional so it probably needs a bang too, but I haven't compiled it so I can't say for sure what the compiler will do.
self.tableView is reference to a property that might not have been set (e.g. is nil), so it is an optional. You can declare it for example an #IBOutlet with a ! at the end if you know it will ALWAYS be defined, such as from the Storyboard, and then you don't have to bang dereference it later.
A common thing to do is:
#IBOutlet var tableView : UITableView!
That's an implicitly unwrapped optional, and will generate an error if it's referenced when nil. But you don't need to use a ! to dereference.
Correct. The result of the line will produce an optional that you can test with if let
I was investigating the difference between ! and ? in var declaration.
My Question in brief
If you call unwrap! on a a var declared with ! - why isnt this a double unwrap?
I created two IBOutlets as this is when ! is used a lot
#IBOutlet weak var searchBar1: UISearchBar? //"Optional"
#IBOutlet weak var searchBar2: UISearchBar! //"Implicitly Unwrapped Optional"
I understand that if outlets are non nil then all these will work
self.searchBar1!.text = "dd" //builds ok but crashes on nil
self.searchBar2!.text = "dd" //builds ok but crashes on nil
self.searchBar1?.text = "dd1" //builds ok but does nothing on nil
self.searchBar2?.text = "dd1" //builds ok but does nothing on nil
//---
self.searchBar1.text = "dd2" //ERROR: 'UISearchBar?' does not have a member named 'text'
self.searchBar1!.text = "dd2" //OK: must unwrap Optional(UISearchBar) to UISearchBar
self.searchBar1!.text = "dd2" //OK: must unwrap Optional(UISearchBar) to UISearchBar
self.searchBar2.text = "dd2" //ok unwrap declared in var but will crash if nil
//----
Am I correct in thinking the last line works because the unwrap is in the var declaration
this works because Unwrap! is in var declaration
self.searchBar2.text = "dd2"
Why doesnt this crash - isnt this a double unwrap
self.searchBar2!.text = "dd"
self.searchBar is Optional(UISearchBar) >> Unwrap! self.searchBar2! >> UISearchBar
The two key sentences in the book are:
An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it is accessed.
and
You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used.
My understanding here is that an implicitly unwrapped optional is just like a normal optional, and can be accessed like one, including using the unwrapping! operator on it. Implicit unwrapping simply removes the need to unwrap, rather than making it an error if you don't.
It's a "normal optional... but can also be used like a nonoptional value"—to me that implies that both methods of accessing it are fine.
If variable var declared as Type!, then any reference to var is equivalent to var!. You can think that compiler adds ! every time you use this variable. There's no "double unwrap" here, it's single unwrap.