I have the following Dictionary:
["oct": nil,
"jan": Optional(3666.0),
"nov": nil,
"apr": nil,
"sep": nil,
"feb": nil,
"jul": nil,
"mar": nil,
"dec": nil,
"may": nil,
"jun": nil,
"aug": nil]
I want to enable a button only when any value of any key is not nil. Is there any functional "magics" to do it without a traditional loop?
Use contains(where:) on the dictionary values:
// Enable button if at least one value is not nil:
button.isEnabled = dict.values.contains(where: { $0 != nil })
Or
// Enable button if no value is nil:
button.isEnabled = !dict.values.contains(where: { $0 == nil })
You've already been provided with similar solutions, but here you go:
dict.filter({$0.value == nil}).count != 0
You can use filter to check if any value is nil in a dictionary.
button.isEnabled = dict.filter { $1 == nil }.isEmpty
I recommend to conform to the standard dictionary definition that a nil value indicates no key and declare the dictionary non-optional ([String:Double]).
In this case the button will be enabled if all 12 keys are present. This is more efficient than filter or contains
button.isEnabled = dict.count == 12
Related
I have a NSSize variable
var originalselectedimagesize:NSSize
if(originalselectedimagesize == nil)
{
}
I'm trying to check if NSSize is set ? But i keep getting the following warning.How can i check if the value of NSSize is changed?
h(aka 'CGSize') to 'nil' always returns false
Because from the declaration, NSSize is not an optional. So checking a non-optional value for nil always return false.
In case if you have the following, then you won't get the warning.
var originalselectedimagesize:NSSize?
if(originalselectedimagesize == nil)
{
}
You can declare originalselectedimagesize as NSSize? (Optional type of NSSize), and set it to nil. Then, you can check if it has value like this:
var originalselectedimagesize: NSSize? = nil
// what ever...
// check for value
if let size = originalselectedimagesize {
}
I am trying to get the value from a row, turn it into a string and then check to see if that string is in an array. So far I have this:
let row: IntRow? = form.rowBy(tag: "devicefield")
let stringvalue = String(describing: row?.value)
if (row?.value) != nil
{
if tableDevices.contains("\(stringvalue)")
{
self.dismiss(animated: false, completion: nil)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "filterData"), object: nil)
}
else
{
SCLAlertView().showError("Error", subTitle: "\(stringvalue) does not exist at your facility")
return
}
}
But for some reason it keeps printing out my variable stringvalue as an optional.
row?.value is an optional. That's pretty clear since you see the "?". So the print command you are using is simply printing out that it is an optional. The string isn't optional, the variable is. You can get a new variable like this:
if let printableRowNumberAsInt = row?.value {
// do your stuff like...
print("\(printableRowNumberAsInt)")
}
I'm new to Swift and is trying out the beginner's project of building a calculator. I understand that "display.text" returns an optional string and the string value inside of it has to be unwrapped with "!" before it can be used.
However, I have noticed "display.text" only needs to be unwrapped once and then it can be used multiple times without unwrapping it again. Is this true for Swift optional values? Where could I find some guidelines regarding to the matter?
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var display: UILabel!
var userIsInTheMiddleOfTypingANumber = false
#IBAction func appendDigit(sender: UIButton) {
let digit = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
display.text = display.text! + digit
} else {
display.text = digit
userIsInTheMiddleOfTypingANumber = true
}
}
Two standard options for unwrapping an optional where it can be used again:
1) if let
if let unwrappedValue = someOptional {
// unwrappedValue can be used only inside this block of code
}
2) guard
guard let unwrappedValue = someOptional else { return }
/// unwrappedValue can be used as long as it is in scope
Try this.
guard let displayText = display.text else {
// handle the case when optional has nil value
}
// In this scope you can use non-nil value of display.text as displayText.
print("displayText = \(displayText)")
This is how you can use optional values after unwrapping once. Another simpler way would be to just use instead of guard-let.
if let displayText = display.text else {
// safely unwrapped
}
Hope that helped!
Check this link for more help.
You should generally avoid to forcibly unwrap optionals (with operator !), as this will yield a runtime exception in case the optional contains nil. Below follows some techniques to handle unwrapping of optionals.
Optional binding
Note that the only way you can "unwrap it once and then use it multiple times" if if you unwrap and assign it to another non-optional variable to the same inherent type.
This is what is done when using optional binding:
/* Example setup */
let display: UILabel = UILabel()
let digit = "1"
/* optional binding using if-let:
_assign_ unwrapped value (if non-nil) to 'unwrapped' */
if let unwrappedText = display.text {
// 'unwrapped' resides in scope inside of the if-let block
display.text = unwrappedText + digit
}
else {
display.text = digit
}
/* optional binding using guard-let-else:
_assign_ unwrapped value (if non-nil) to 'unwrapped' */
func foo(disp: UILabel, _ dig: String) {
guard let unwrappedText = display.text else {
display.text = digit
return
}
// 'unwrapped' resides in scope outside of the guard-let-else block
display.text = unwrappedText + digit
}
foo(display, digit)
Nil coalescing operator
If you don't want to explicitly assign the unwrapped value using conditional binding, you can make use of the nil coalescing operator for safe unwrapping.
/* nil coalescing operator */
display.text = (display.text ?? "") + digit
Now, you could, however, use the nil coalescing operator in a semi-optional-binding fashion; assign the unwrapped value of an optional or some default value if the optional is nil:
let metaUnwrapped = display.text ?? ""
Immutable metaUnwrapped would be available in its scope, and contain the value of display.text (at assignment), if non-nil, or the default value "", if display.text was nil at assignment. You could use metaUnwrapped in the same fashion as immutable unwrapped in the optional binding examples above:
display.text = metaUnwrapped + digit
Optional chaining
This is slightly off-base w.r.t. your question, but since we're on the subject of optionals and unwrapping, I might as well mention optional chaining.
Optional chaining can be used to access properties of some optional property, given that the optional property is not nil. As an example, say you want to count the number of characters in the display.text, but naturally only if the optional .text property is non-nil. In this case, optional chaining combined with the nil coalescing operator could be a proper method of choice:
let numCharacters = display.text?.characters.count ?? 0
/* if text != nil, returns character count; otherwise, by
nil coalescing operator, returns 0 /*
When I enter a value in the UiTextField and press add button the app works perfectly fine,but when I don't enter a value in the UiTextField, then press the add button the whole app crashes. can someone please help me and show me the light.Thank you in advance and good wishes for you and your family.
This is my code
import UIKit
class ViewController: UIViewController,UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.textFild.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet var textFild: UITextField!
#IBAction func ButtonAwesome(sender: AnyObject) {
let value:Double = Double(textFild.text!)!
let sum:Double = value - 1;
let alert = UIAlertController(title: "km", message: "\(sum)", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Exit", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert,animated: true, completion: nil)
}
func textField(textField: UITextField,shouldChangeCharactersInRange range: NSRange,replacementString stringer: String) -> Bool
{
if (textField.text == "" && (stringer == ".")) {
return false;
}
let countdots = textField.text!.componentsSeparatedByString(".").count - 1
if countdots > 0 && stringer == "."
{
return false
}
return true
}
}
A more robust solution would be to use the nil coalescing operator to assert that the initialization of value never fails.
#IBAction func ButtonAwesome(sender: AnyObject) {
let value = Double(textFild.text ?? "0") ?? 0
let sum:Double = value - 1;
let alert = UIAlertController(title: "km", message: "\(sum)", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Exit", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert,animated: true, completion: nil)
}
This is valid for any of the following "unexpected" values of textField.text: nil, "" (empty) or some character that cannot be used to initialize a Double type variable (e.g. "a"). For all these cases, value is give a value of 0.
As an example, consider the following comparisons between a safe and an un-safe way of solving your initial runtime exception.
We first look at the dangers of forcibly unwrapping optionals - not a safe solution. What if textField.text contains nil or an non-numerical character, e.g. "a"? Result:
var myTextFieldText : String? = nil
/* Example 1: nil value causes runtime error */
if myTextFieldText != "" { // this is 'true' -> enter if closure
let value:Double = Double(myTextFieldText!)!
/* this will fail at run time since we are forcibly (un-safely)
unwrapping an optional containing 'nil' */
}
/* Example 2: non-numeric string character causes runtime error */
myTextFieldText = "a"
if myTextFieldText != "" { // this is 'true' -> enter if closure
let value:Double = Double(myTextFieldText!)!
/* this will fail at run time since we cannot initalize a
Double with a string value "a", hence 'Double(myTextFieldText!)'
returns nil, but since we've appended '!', we, like above,
forcibly tries to unwrap this optional of value nil */
}
You should, generally, always use conditional unwrapping of optionals, to avoid encountering a nil value when forcibly unwrapping optionals, the latter leading to a runtime error.
A more robust version of the example above, making use of the nil coalescing operator:
myTextFieldText = nil
let valueA = Double(myTextFieldText ?? "0") ?? 0 // 0
/* OK, Double(myTextFieldText ?? "0") = Double("0") = 0 */
myTextFieldText = "a"
let valueB = Double(myTextFieldText ?? "0") ?? 0 // 0
/* OK, Double(myTextFieldText ?? "0") = Double("a") = nil (fails)
=> use rhs of outer '??' operator: nil ?? 0 = 0 */
For an alternative method, where you extend UITextField to cover your string to numerical type conversion needs, see Leos neat answer in the following thread:
Swift - Converting String to Int
The thread also contains some other valuable insights w.r.t. reading text as numerical values from UITextField instances.
Finally, when dealing with String to Double value conversion, it might be appropriate to use a fixed precision w.r.t. number of decimal digits in your resulting Double value. For a thorough example of how to do this using NSNumberFormatter and extensions, see:
How to input currency format on a text field (from right to left) using Swift?
Please replace your buttonAwesome method with the following code where you check if textfield is not empty, this will work if textfield has a value:
#IBAction func ButtonAwesome(sender: AnyObject) {
if textFild.text != "" {
let value:Double = Double(textFild.text!)!
let sum:Double = value - 1;
let alert = UIAlertController(title: "km", message: "\(sum)", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Exit", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert,animated: true, completion: nil)
}
}
Since textfield.text is an optional value and as in your case textfield can or cannot have text. So you should test for optional as give below.
if let textIsAvailable = textfield.text
{
print("Text \(textIsAvailable)")
}
Note : The reason for your crash is you are trying to access value which actually doesn't have any value.
Help me with Optional hell in Swift. How to return count of array for key "R". self.jsonObj can be null
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return (self.jsonObj["R"]! as? NSArray)?.count;
}
Let's take this a step at a time.
self.jsonObj may be nil so you need to treat it as an Optional:
self.jsonObj?["R"]
This will either return 1) nil if self.jsonObj is nil or if "R" is not a valid key or if the value associated with "R" is nil 2) an Optional wrapped object of some type. In other words, you have an Optional of some unknown type.
The next step is to find out if it is an NSArray:
(self.jsonObj?["R"] as? NSArray)
This will return an Optional of type NSArray? which could be nil for the above reasons or nil because the object in self.jsonObj was some other object type.
So now that you have an Optional NSArray, unwrap it if you can and call count:
(self.jsonObj?["R"] as? NSArray)?.count
This will call count if there is an NSArray or return nil for the above reasons. In other words, now you have an Int?
Finally you can use the nil coalescing operator to return the value or zero if you have nil at this point:
(self.jsonObj?["R"] as? NSArray)?.count ?? 0
I'm guessing that you'll want to return 0 if there's nothing in the array. In that case, try the Nil Coalescing Operator:
return (self.jsonObj?["R"] as? NSArray)?.count ?? 0;
Edit: As #vacawama's answer points out, it should be self.jsonObj?["R"] instead of self.jsonObj["R"]! in case self.jsonObj is nil.
assuming self.jsonObj is NSDictionary? or Dictionary<String, AnyObject>?
return self.jsonObj?["R"]?.count ?? 0