I am using a keychain wrapper written in Swift.
When value is nil, this wrapper I'm using automatically saves data as "nil" instead of saving as an actual nil value.
For ex, ["last_name" : "nil"].
In one of my label in my iOS app, I'm returning last_name value.
It bothers me that a text in label is saying "nil" when there supposed to be nothing.
I remember in Swift that there is a syntax like A ?? B which puts B instead if A is not valid. But I cannot remember it right now.
In my app, I want to something like below:
if the value I'm looking for is nil, then input "" instead of "nil"
If keychain["last_name"] == nil ?? ""
I know this is a horrible explanation but this is all I could come up with.
?? is the nil coalescing operator. It is used for unwrapping optionals — a ?? b is shorthand for a != nil ? a! : b.
You probably want to use the ternary operator instead. You could even combine them like this:
let lastName = keychain["last_name"] == "nil" ? "" : (keychain["last_name"] ?? "")
That said, it might be easier to just filter out these responses immediately after getting the keychain instead of checking every time:
var keychain = ["first_name" : "aaron", "last_name" : "nil"]
keychain.forEach { if $0.1 == "nil" { keychain.removeValueForKey($0.0) } }
print(keychain) //["first_name": "aaron"]
The $0 is a shorthand argument name. Here's the long form version of the same code:
keychain.forEach { (key, value) -> () in
if value == "nil" {
keychain.removeValueForKey(key)
}
}
Related
I am implementing UserDefault string value ! = nil or !="" but my validation not working. How do I solve this?
if((UserDefaults.standard.string(forKey: "name")) != nil || UserDefaults.standard.string(forKey: "name") != "") {
self.items.insert(UserDefaults.standard.string(forKey: "name") ?? "", at: 5) // Always reaching here....
}
Check if there is value for the key by optional unwrapping. Then check if it is not empty. Then insert it to the array.
if let value = UserDefaults.standard.string(forKey: "name"), !value.isEmpty {
items.insert(value, at: 5)
}
The reason the if is executed every time in your case is because you are using an OR (||) instead of AND (&&). So, the second condition is true even when there is no value for the key in the UserDefaults.
P.S: Make sure the array has at least 6 items before you call insert at 5.
Most of my searching here on SO is proving futile. My guard statement works as far as checking each value and correcting it if one is nil. However if two of the values are nil, then I crash unexpectedly finding nil while unwrapping an optional. How does one go about checking that multiple values are not nil using swifts guard statement?
func protectInput() {
guard Double(myAmount.text!) != nil else {
myAmount.text = "0.00"
return
}
guard Double(myRate.text!) != nil else {
myRate.text = "0.00"
return
}
guard Double(myFee.text!) != nil else {
myFee.text = "0.00"
return
}
}
Maybe I am completely on the wrong track, any help with an example would be appreciated. I have read all I can take in. I do not need to compare two values or have some complex comparison.
Guard statements aren't the right thing to use here. If any of them fail, then you will return from the function and your later statements won't get executed. So if myAmount doesn't have a valid value in it, you'll never correct myRate and myFee.
if Double(myAmount.text ?? "") == nil {
myAmount.text = "0.00"
}
This pattern would suit you better:
the text value isn't force unwrapped any more, which will prevent one potential crash - ?? is the nil coalescing operator which will use either the text value or, in this case, an empty string
there is no return so the function will check all of the values.
I'm building a very simple login verification app inside of xCode 7 using Swift. I'm extremely new to Swift and building apps in general, so I'm having some difficulty with a part of my code.
I'm checking whether or not a user has left any fields empty, and if they have, they will receive an error alert message.
However, when I go to build my project, I get the error:
Value of optional type 'String?' not unwrapped;
This is my code:
let userEmail = userEmailTextField.text
let userPassword = userPasswordTextField.text
let userRepeatPassword = repeatPasswordTextField.text
if(userEmail.isEmpty || userPassword.isEmpty || userRepeatPassword.isEmpty){
displayAlertMessage("All fields are required.") // custom made function
return;
}
Any help is appreciated.
Also, If someone could explain why my code is not functioning correctly, that would be awesome! Because, I can't seem to understand other forums explanations or fixes.
The problem here is that the property text of UITextField is an optionl string so you have to change like this:
let userEmail = userEmailTextField.text!
let userPassword = userPasswordTextField.text!
let userRepeatPassword = repeatPasswordTextField.text!
or use it like this
guard let userEmail = userEmail, let userPassword = userPassword, let userRepeatPassword = userRepeatPassword where !userEmail.isEmpty && !userPassword.isEmpty && !userRepeatPassword.isEmpty else {
displayAlertMessage("All fields are required.") // custom made function
return;
}
As already noted, UITextFields property text is of type String? (aka Optional<String>), so you cannot directly apply methods or get properties of String.
Forced unwrapping (!) would be very risky, as that property may actually be nil.
In such cases, you have some options to treat the Optional value:
Use optional bindings, its representative is if let, but guard let or sometimes while let may be useful.
Use optional chaining, represented with ?.. Maybe you are using this somewhere else.
Giving default value using nil-coalescing operator ??.
With the latter two, I get this line:
if((userEmail?.isEmpty ?? true) || (userPassword?.isEmpty ?? true) || (userRepeatPassword?.isEmpty ?? true)) {
As you see, userEmails type is String?, so I have chosen optional chaining:
userEmail?.isEmpty
Which may return three kinds of values:
Optional.Some(true)
Optional.Some(false)
Optional.None (this is called nil)
(I omitted specifying <Bool>, for readability.)
It's still Optional, so I added ?? true to supply a default value for nil case.
userEmail?.isEmpty ?? true
lhs:Optional.Some(true) -> true (left hand side of ?? is not nil, use lhs value unwrapped)
lhs:Optional.Some(false) -> false (left hand side of ?? is not nil, use lhs value unwrapped)
lhs:Optional.None -> true (left hand side of ?? is nil, so right hand side value is used)
You know, when the text is nil, you should think it as empty, so supplying default value true for nil case is appropriate.
You need to write similar code for all three variables, and you get the line I have shown above.
In Class A I have this variable:
var collectionElement : PFObject?
I then need to call a method which users it. But before I want to check if it is nil or not. So I do something like:
if collectionElement != nil{
if let elementName = collectionElement["elementName"] as? NSString{
elementTitle.text = elementName as String
}
...
query.whereKey("fileCollectionElement", equalTo:collectionElement!)
}
In class B I assign the value like this:
cell.collectionElement = collectionElements[indexPath.row]
where collectionElements[indexPath.row] is a PFObject.
This code gives me errors, and by playing around with the ! and ?, I can make the app run but it crashes, specifically because of the line coll... != nil
I am really confused with the ? and ! things. What is the right thing to use and when? Why sometimes I cannot check if something is nil (in Objective-C I could do it all the time)?
? and ! for variables:
? is used when the the variable could be an object or can be nil.
! is used when the variable could be an object or can be nil BUT it should never be nil. This prevents the coder from having to unwrap it everytime.
? and ! for casting:
"x as? y" checks if the "x" CAN be casted as "y" AND it if so it WILL be casted as "y".
"x as! y" forces the cast from x to y
So in your code you should check as? String, because it seems like you are trying to cast it later on anyway to String. So try this:
if collectionElement != nil{
if let elementName = collectionElement["elementName"] as? String{
elementTitle.text = elementName
}
...
query.whereKey("fileCollectionElement", equalTo:collectionElement!)
}
As for the error when you index countElements, this could return a nil value so you should make sure the two sides agree on the type they working with. if countElements contains an optional (PFObject?) then make sure cell.collection element is an optional (PFObject?) also.
Having the same exact types is crucial in Swift.
New to ios and swift. Want some best practice tips.
I want to append content to a label in a new line. My try:
#IBOutlet weak var history: UILabel!
#IBAction func appendContent() {
if history.text != nil && !history.text!.isEmpty {
history.text = history.text! + "\r\n" + "some content"
}
else{
history.text = digit
}
}
It seems to work, however,
Is there a better way to check the text is not nil and not empty?
Is there a "keyword" thing for "\r\n"?
You can use optional binding: if let to check if something is nil.
Example 1:
if let text = history.text where !text.isEmpty {
history.text! += "\ncontent"
} else {
history.text = digit
}
Or you can use map to check for optionals:
Example 2:
history.text = history.text.map { !$0.isEmpty ? $0 + "\ncontent" : digit } ?? digit
!$0.isEmpty is in most cases not even needed so the code can look a bit better:
history.text = history.text.map { $0 + "\ncontent" } ?? digit
EDIT: What does map do:
The map method solves the problem of transforming the elements of an array using a function.
Let’s say we have an array of Ints representing some sums of money and we want to create a new array of strings that contains the money value followed by the “€” character i.e. [10,20,45,32] -> ["10€","20€","45€","32€"].
The ugly way of doing this is by creating a new empty array, iterating our original array transforming each element and adding it to the new array
var stringsArray = [String]()
for money in moneyArray {
stringsArray += "\(money)€"
}
Using map is just:
let stringsArray = moneyArray.map { "\($0)€" }
It can also be used for optionals:
The existing map allows you to apply a function to the value inside an optional, if that optional is non-nil. For example, suppose you have an optional integer i and you want to double it. You could write i.map { $0 * 2 }. If i has a value, you get back an optional of that value doubled. On the other hand, if i is nil, no doubling takes place.
(source)
What does ?? do:
The nil coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type. The expression b must match the type that is stored inside a.
The nil coalescing operator is shorthand for the code below:
a != nil ? a! : b
What about using something like this:
if let text = history.text where !text.isEmpty {
history.text = "\(text)\nsome content"
}