I am having a hard time understanding the optionals and forced unwrapping in Swift language. I have read the book and chapters several times but I cannot understand it.
Is there a difference between the following two:
totalAmountTextField?.text.toInt()
totalAmountTextField!.text.toInt()
Also, when declaring the IBOutlets why do I always make it an optional field like this:
#IBOutlet var nameTextField :UITextField?
If I don't use the "?" at the end then it gives errors.
totalAmountTextField?.text.toInt() is equivalent to
func foo() -> Int? { // give you optional Int
if let field = totalAmountTextField {
return field.text.toInt()
} else {
return nil // return nil if totalAmountTextField is nil
}
}
foo()
it should be used if totalAmountTextField can be nil
totalAmountTextField!.text.toInt() is equivalent to
func foo() -> Int { // give you Int
if let field = totalAmountTextField {
return field.text.toInt()
} else {
crash() // crash if totalAmountTextField is nil
}
}
foo()
it should be used only if you know totalAmountTextField must not be nil
// It represents that totalAmountTextField may be nil and then stop the chain.
totalAmountTextField?.text.toInt()
// It assume that totalAmountTextField must have value, if not then caused a crash.
totalAmountTextField!.text.toInt()
You can take a look at the Swift Documentation about Optional Chaining. https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html
Related
I am new to Swift, but am curious about the behaviour of optional unwrapping.
Is there any explanation why guarding against != nil is not unwrapping the optional?
As a simple example:
func hasC(_ s: String?) -> Bool {
guard s != nil else {
return false
}
return s!.contains("c")
}
I need to put the exclamation sign and explicitly unwrap the value, even though it seems to be clear that at the last line s is not an optional string anymore.
I would love to hear the reasoning behind such a behaviour and how to unwrap the value properly in such a case?
creating extra variable seems ugly:
guard let s = s else { ... }
and guarding against not boolean condition is not working:
guard s else { ... }
Repl: https://repl.it/#valerii/optional-unwrap
The type of s is still Optional, so whether you did a nil check or not is irrelevant. The nil check is done in runtime, while the type system is doing a compile-time check. The only way to ensure s can never be nil is via optional binding if let or guard let.
The simple answer is that an equating operator, e.g. ==, != or any comparing operators have nothing to do with unwrapping an optional value from the point of view of the compiler.
A guard statement has 2 general use cases. One is to guard against a boolean value, which is produced by an equating or comparing operator, like in the following example:
guard ["foo", "bar"].contains("foo") == true else { return }
guard 10 > 5 else { return }
While another role of the guard statement is to unwrap optionals, which is written in a guard let or guard var syntax. For example:
guard let unwrappedValue = anOptionalValue else { return }
That specific syntax, lets the compiler know that you're trying to unwrap the value, and you get an unwrapped value as a result if the unwrapping is successful.
Sure, while creating another variable/constant may seem "ugly", that is the way to go in Swift.
You are not declaring a new variable using guard, function parameter is optional so thats why its allowing you to unwrap even after guard statement
func hasC(_ s: String?) -> Bool {
if let containsValueInString = s , containsValueInString.contains("c"){
return true
}
return false
}
or Simpler you can use Optional chaining with nil coalescing operator
func hasC(_ s: String?) -> Bool {
return s?.contains("c") ?? false
}
guard doesn't unwrap anything just by itself. It's like a special kind of if. guard let unwraps, but it's just a syntactic sugar.
you are using the wrong format
func hasC(_ s: String?) -> Bool {
guard let input = s else {return false}
return input.contains("c")
}
and you can do like that:
func hasC(_ s: String?) -> Bool {
if let input = s {
return input.contains("c")
}
return false
}
or you can make your output nullable like this:
func hasC(_ s: String?) -> Bool? {
return s?.contains("c")
}
or
func hasC(_ s: String?) -> Bool {
return s?.contains("c") ?? false
}
it is not ugly anymore. with lower lines.
best regards
I have been coding in Swift for a while, and I think I had to put a ! on all my let field variables that were not defined immediately.
Now I notice today that this piece of code does not compile and I am really surprised? why is this?
class MyClass : Mapper {
var a: Bool!
required init?(_ map: Map) {
}
// Mappable
func mapping(map: Map) {
a <- map["a"]
}
}
let myClass = MyClass()
if myClass.a { // Compiler not happy
// Optional type 'Bool!' cannot be used as a boolean; test for '!= nil' instead
}
if true && myClass.a { // Compiler happy
}
if myClass.a && myClass.a { // Compiler happy
}
Apple Swift version 2.2
Edit
Some people point out why am I using a let for a variable that will never change. I mentioned it is for field variables but I shorten the example. When using ObjectMapper (http://github.com/Hearst-DD/ObjectMapper), all the fields are not defined immediately in the init. This is why they are all either optional? or required!
You can declare let a: Bool without a ! and without declaring true or false right then. The compiler will complain if it can't guarantee the value gets set before you use it though.
This works.
let a: Bool
a = true
if a { // Compiler happy
}
This works as well, because a is guaranteed to be set.
let a: Bool
if thingOne < thingTwo {
a = true
} else {
a = false
}
if a { // Compiler happy
}
However, this would not work because a is not guaranteed to be set before you try to use it.
let a: Bool
if thingOne < thingTwo {
a = true
}
if a { // Compiler NOT happy
// "Constant 'a' used before being initialized"
}
Now, if you can't guarantee that your variable will be set by the time you do the check, then you should really be using an optional var in the first place.
var a: Bool?
if a == true { // Compiler happy
}
A bit of history...
In Swift 1.0, it was possible to check if an optional variable optVar contained a value by just checking:
if optVar {
println("optVar has a value")
} else {
println("optVar is nil")
}
In The Swift Programming Language, the update for Swift 1.1 (dated 2014-10-16) stated:
Optionals no longer implicitly evaluate to true when they have a value and false when they do not, to avoid confusion when working with optional Bool values. Instead, make an explicit check against nil with the == or != operators to find out if an optional contains a value.
So, the nonsensical error message that you are getting was put there because the Swift compiler is interpreting your:
if a {
}
to mean:
if a != nil {
}
and it is encouraging you to test against nil to determine if the Optional a has a value.
Perhaps the Swift authors will change it in the future, but for now you will have to explicitly unwrap a:
if a! {
}
or check against true:
if a == true {
}
or (to be completely safe):
if a ?? false {
print("this will not crash if a is nil")
}
I am trying to create a generic function that can take an optional argument.
Here's what I have so far:
func somethingGeneric<T>(input: T?) {
if (input != nil) {
print(input!);
}
}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // Errors!
It works with a String as shown, but not with nil.
Using it with nil gives the following two errors:
error: cannot invoke 'somethingGeneric' with an argument list of type '(_?)'
note: expected an argument list of type '(T?)'
What am I doing wrong and how should I correctly declare/use this function? Also, I want to keep the usage of the function as simple as possible (I don't want do something like nil as String?).
I guess the compiler can't figure out what T is just from nil.
The following works just fine though for example:
somethingGeneric(Optional<String>.None)
I believe you've overcomplicated the problem by requiring the ability to pass untyped nil (which doesn't really exist; even nil has a type). While the approach in your answer seems to work, it allows for the creation of ?? types due to Optional promotion. You often get lucky and that works, but I've seen it blow up in really frustrating ways and the wrong function is called. The problem is that String can be implicitly promoted to String? and String? can be implicitly promoted to String??. When ?? shows up implicitly, confusion almost always follows.
As MartinR points out, your approach is not very intuitive about which version gets called. UnsafePointer is also NilLiteralConvertible. So it's tricky to reason about which function will be called. "Tricky to reason about" makes it a likely source of confusing bugs.
The only time your problem exists is when you pass a literal nil. As #Valentin notes, if you pass a variable that happens to be nil, there is no issue; you don't need a special case. Why force the caller to pass an untyped nil? Just have the caller pass nothing.
I'm assuming that somethingGeneric does something actually interesting in the case that it is passed nil. If that's not the case; if the code you're showing is indicative of the real function (i.e. everything is wrapping in an if (input != nil) check), then this is a non-issue. Just don't call somethingGeneric(nil); it's a provable no-op. Just delete the line of code. But I'll assume there's some "other work."
func somethingGeneric<T>(input: T?) {
somethingGeneric() // Call the base form
if (input != nil) {
print(input!);
}
}
func somethingGeneric() {
// Things you do either way
}
somethingGeneric(input: "Hello, World!") // Hello, World!
somethingGeneric() // Nothing
Good question and answer. I have an Swift 4 update to contribute:
var str: String? = "Hello, playground"
var list: Array<String>? = ["Hello", "Coder256"]
func somethingGeneric<T>(_ input: T?) {
if (input != nil) {
print(input!);
}
}
func somethingGeneric(_ input: ExpressibleByNilLiteral?) {}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // *nothing printed*
somethingGeneric(nil as String?) // *nothing printed*
somethingGeneric(str) // Hello, playground
str = nil
somethingGeneric(str) // *nothing printed*
somethingGeneric(list) // ["Hello", "Coder256"]
list = nil
somethingGeneric(list) // *nothing printed*
I figured it out:
func somethingGeneric<T>(input: T?) {
if (input != nil) {
print(input!);
}
}
func somethingGeneric(input: NilLiteralConvertible?) {}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // *nothing printed*
somethingGeneric(nil as String?) // *nothing printed*
I think that you will never call somethingGeneric(nil) but mostly somethingGeneric(value) or somethingGeneric(function()) for which the compiler has enough info not to be stucked trying to guess the type:
func somethingGeneric<T>(input: T?) {
if let input = input {
print(input);
}
}
func neverString() -> String? {
return nil
}
let a: String? = nil
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(a) // Nothing and no error
somethingGeneric(neverString()) // Nothing and no error
Also, I would use the if let syntax instead of if(value != nil).
Here is the solution I came up with that compiles on Swift 5, as many of the solutions here did not compile for me. It might be considered hacky as I use a stored variable to help things along. I was unable to come up with a Swift 5 version of the nil parameters that resolve to type T.
class MyClass {
func somethingGeneric<T>(input: T?) {
if let input = input {
print(input)
}
}
func somethingGeneric() {
somethingGeneric(Object.Nil)
}
}
final class Object {
static var Nil: Object? //this should never be set
}
Actually there is a way to do this, inspired by Alamofire's internal code.
You do not have to install Alamofire to use this solution.
Usage
Your problematic method definition
func someMethod<SomeGenericOptionalCodableType: Codable>(with someParam: SomeGenericOptionalCodableType? = nil) {
// your awesome code goes here
}
What works ✅
// invoke `someMethod` correctly
let someGoodParam1 = Alamofire.Empty.value
someMethod(with: someGoodParam1)
I think it is possible to use Alamofire.Empty.value as a default value in someMethod definition as a parameter.
What does not work ❌
// invoke `someMethod` incorrectly
let someBadParam1: Codable? = nil
let someBadParam2 = nil
someMethod(with: someBadParam1)
someMethod(with: someBadParam2)
Solution definition (source)
/// Type representing an empty value. Use `Empty.value` to get the static instance.
public struct Empty: Codable {
/// Static `Empty` instance used for all `Empty` responses.
public static let value = Empty()
}
I have this question except for Swift. How do I use a Type variable in a generic?
I tried this:
func intType() -> Int.Type {
return Int.self
}
func test() {
var t = self.intType()
var arr = Array<t>() // Error: "'t' is not a type". Uh... yeah, it is.
}
This didn't work either:
var arr = Array<t.Type>() // Error: "'t' is not a type"
var arr = Array<t.self>() // Swift doesn't seem to even understand this syntax at all.
Is there a way to do this? I get the feeling that Swift just doesn't support it and is giving me somewhat ambiguous error messages.
Edit: Here's a more complex example where the problem can't be circumvented using a generic function header. Of course it doesn't make sense, but I have a sensible use for this kind of functionality somewhere in my code and would rather post a clean example instead of my actual code:
func someTypes() -> [Any.Type] {
var ret = [Any.Type]()
for (var i = 0; i<rand()%10; i++) {
if (rand()%2 == 0){ ret.append(Int.self) }
else {ret.append(String.self) }
}
return ret
}
func test() {
var ts = self.someTypes()
for t in ts {
var arr = Array<t>()
}
}
Swift's static typing means the type of a variable must be known at compile time.
In the context of a generic function func foo<T>() { ... }, T looks like a variable, but its type is actually known at compile time based on where the function is called from. The behavior of Array<T>() depends on T, but this information is known at compile time.
When using protocols, Swift employs dynamic dispatch, so you can write Array<MyProtocol>(), and the array simply stores references to things which implement MyProtocol — so when you get something out of the array, you have access to all functions/variables/typealiases required by MyProtocol.
But if t is actually a variable of kind Any.Type, Array<t>() is meaningless since its type is actually not known at compile time. (Since Array is a generic struct, the compiler needs know which type to use as the generic parameter, but this is not possible.)
I would recommend watching some videos from WWDC this year:
Protocol-Oriented Programming in Swift
Building Better Apps with Value Types in Swift
I found this slide particularly helpful for understanding protocols and dynamic dispatch:
There is a way and it's called generics. You could do something like that.
class func foo() {
test(Int.self)
}
class func test<T>(t: T.Type) {
var arr = Array<T>()
}
You will need to hint the compiler at the type you want to specialize the function with, one way or another. Another way is with return param (discarded in that case):
class func foo() {
let _:Int = test()
}
class func test<T>() -> T {
var arr = Array<T>()
}
And using generics on a class (or struct) you don't need the extra param:
class Whatever<T> {
var array = [T]() // another way to init the array.
}
let we = Whatever<Int>()
jtbandes' answer - that you can't use your current approach because Swift is statically typed - is correct.
However, if you're willing to create a whitelist of allowable types in your array, for example in an enum, you can dynamically initialize different types at runtime.
First, create an enum of allowable types:
enum Types {
case Int
case String
}
Create an Example class. Implement your someTypes() function to use these enum values. (You could easily transform a JSON array of strings into an array of this enum.)
class Example {
func someTypes() -> [Types] {
var ret = [Types]()
for _ in 1...rand()%10 {
if (rand()%2 == 0){ ret.append(.Int) }
else {ret.append(.String) }
}
return ret
}
Now implement your test function, using switch to scope arr for each allowable type:
func test() {
let types = self.someTypes()
for type in types {
switch type {
case .Int:
var arr = [Int]()
arr += [4]
case .String:
var arr = [String]()
arr += ["hi"]
}
}
}
}
As you may know, you could alternatively declare arr as [Any] to mix types (the "heterogenous" case in jtbandes' answer):
var arr = [Any]()
for type in types {
switch type {
case .Int:
arr += [4]
case .String:
arr += ["hi"]
}
}
print(arr)
I would break it down with the things you already learned from the first answer. I took the liberty to refactor some code. Here it is:
func someTypes<T>(t: T.Type) -> [Any.Type] {
var ret = [Any.Type]()
for _ in 0..<rand()%10 {
if (rand()%2 == 0){ ret.append(T.self) }
else {
ret.append(String.self)
}
}
return ret
}
func makeArray<T>(t: T) -> [T] {
return [T]()
}
func test() {
let ts = someTypes(Int.self)
for t in ts {
print(t)
}
}
This is somewhat working but I believe the way of doing this is very unorthodox. Could you use reflection (mirroring) instead?
Its possible so long as you can provide "a hint" to the compiler about the type of... T. So in the example below one must use : String?.
func cast<T>(_ value: Any) -> T? {
return value as? T
}
let inputValue: Any = "this is a test"
let casted: String? = cast(inputValue)
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
Why Swift doesn't just allow us to let casted = cast<String>(inputValue) I'll never know.
One annoying scenerio is when your func has no return value. Then its not always straightford to provide the necessary "hint". Lets look at this example...
func asyncCast<T>(_ value: Any, completion: (T?) -> Void) {
completion(value as? T)
}
The following client code DOES NOT COMPILE. It gives a "Generic parameter 'T' could not be inferred" error.
let inputValue: Any = "this is a test"
asyncCast(inputValue) { casted in
print(casted)
print(type(of: casted))
}
But you can solve this by providing a "hint" to compiler as follows:
asyncCast(inputValue) { (casted: String?) in
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
}
I have simple method (hope the syntax is right)
func foo() -> WmGroupItemSample?{
var sample:WmGroupItemSample?
if(a > 0){ // some condition
sample = mGroupItemSampleList[0]
}
else{
// do nothing
}
return sample
}
As I understand foo method might return nil if statement a>0 doesn't occur. Therefore return type is: WmGroupItemSample?.
My doubts are in place where I call this method:
var sample:WmGroupItemSample? = foo()
if let temp = sample{
return sample.getStartDate()
}
else{
return -1
}
Is this proper way to validate if not nil? I use Beta 6
What difference if I'll call without ? or with ! like:
var sample:WmGroupItemSample = foo()
or:
var sample:WmGroupItemSample! = foo()
Why I can't validate sample like:
if sample == nil {
/* do one*/
}
else {
}
To compare value with a nil it has to be allowed to be a nil by ? mark. This means that the value can (possibly) be a nil. So by default:
var a : String
can not be a nil. To allow a string be a nil you have to do:
var a : String?
calling variable with ! is unwrapping an optional value
"Trying to use ! to access a non-existent optional value triggers a
runtime error. Always make sure that an optional contains a non-nil
value before using ! to force-unwrap its value." Excerpt From: Apple
Inc. "The Swift Programming Language."
iBooks. https://itun.es/pl/jEUH0.l
For more information I would suggest:
basics
more advanced
reading. Also that SO question with answer might be helpful.
You may have to implement either the Equatable or Comparable protocols.
implementing the Equatable protocol using a global function
func ==<T>(lhs:T, rhs: T?)-> Bool{
return lhs == nil
}
// in your class you can now extend the Equatable protocol in the class definition. ie
class ClassName: Equatable{
// properties and functions
}