I am trying to get the value for first record which is "2018-05-04 09:00:00 +0000". When I print out `firstRecord', I get an optional value in the terminal:
optional(2018-05-04 09:00:00 +0000).
Then I tried to unwrap it like so:
if dailyArray.count == 0 {
print("no record was found")
}else{
guard let firstRecord : String = dailyArray[0]["startTime"] as! String else {return}
let firstRecordArray = firstRecord.components(separatedBy: " ")
print("data exist \(firstRecordArray[0])")
}
And now Xcode is giving me an error saying that you are trying to unwrap a none optional value.
Any idea where am I making a mistake?
Do like this
guard !dailyArray.isEmpty, let firstRecord = dailyArray[0]["startTime"] as? String else { return }
let firstRecordArray = firstRecord.components(separatedBy: " ")
print("data exist \(firstRecordArray[0])")
In your code you are typecasting forcely thatswhy
["startTime"] as! String
this means that the value is Strictly string while ? says it can be string
If you're going to use optional chaining, then you may as well use .first (returns an optional, nil on empty array) rather than [0] (returns value, crashes on empty array):
guard !dailyArray.isEmpty else {
print("no record was found")
return
}
guard let firstRecord = dailyArray.first?["startTime"] as? String else {
return
}
let firstRecordArray = firstRecord.components(separatedBy: " ")
print("data exist \(firstRecordArray[0])")
You can use optional chaining and the if let syntax to unwrap the variable and make the code much more concise and clear:
// dailyArray should be declared as or typecast to [[String : String]]
guard !dailyArray.isEmpty else {
print("no record was found")
exit(1) // or return if in func
}
if let firstRecord = dailyArray.first?["startTime"]?.components(separatedBy: " ") {
print("data exists: \(firstRecord.first)")
}
else {
print("no start time date was found")
}
Related
I am trying to check if an input from a textfield exists in the NSDictionary but I am not sure how to do this.
let nsdict = snapshot.value as? NSDictionary
let values = nsdict?.allValues
Once I Do this i am not sure on how to cast the values to a string to check with a user input textfield.
For example doing this:
if values.contains(userIinput.text){
print("Found")
}
You can apply a filter. In the following code I create a dictionary, and then I filter looking for the userInput.text. Every value that matches will get stored in the new dictionary matches. If matches is > 0, the input already exists and you will have a dictionary with the keys that have the userInput.text as value. Also, you can check if it matches more than once.
You need to verify that $0.value is an String or that the userInput is not nil because if the user input is nil and the $0.value of the dictionary is not an String it will be will and return a match.
let dict: [String : Any] = ["first" : "String", "Second" : 2]
let matches = dict.filter{
guard let value = $0.value as? String else { return false }
value == userInput.text
}
matches.count
If you just want to check if it already exists you can just
guard let userInput = userInput else { return }
if (!dict.filter{ $0.value as? String == userInput }.isEmpty) {
print ("Found")
}
In the first example I'm verifying that $0.value is an String if not I am returning that it does not match, and in the second I am checking that the userInput is not nil, if not it finishes the function there (you can use and if let if you prefer)
unable to build swift project because of this error.
// showing error with inputs.flatmap
fileprivate func makeShippingAddressDictWith(inputs: [TextFieldData]) -> [String: String] {
var shippingDict: [String: String] = [:]
let _ = inputs.flatMap { input in
if let shippingFieldType = input.type as? ShippingDictKeyable.Type {
shippingDict[shippingFieldType.shippingDictKey] = input.text
}
return nil
}
// FIXME: these empty values are the result of a poorly designed request in GDKECommerce
shippingDict["email"] = ""
shippingDict["second_name"] = ""
shippingDict["suffix"] = ""
shippingDict["title"] = ""
shippingDict["salutation"] = ""
shippingDict["company_name"] = ""
return shippingDict
}
}
You could use .forEach instead of .flatMap. Then you would not have to worry about a return type that you are ignoring anyway (with let _ =).
Combining this with a filter would produce a cleaner functional statement if that's what you're after:
inputs.map{ ( $0.text, $0.type as? ShippingDictKeyable.Type) }
.filter{ $1 != nil }
.forEach{ shippingDict[$1!.shippingDictKey] = $0 }
// FIXME: these empty values are the result of a poorly designed request in GDKECommerce
let blankAttributes = ["email", "second_name", "suffix", "title", "salutation", "company_name"]
blankAttributes.forEach{ shippingDict[$0] = "" }
Or use a for loop as suggested by Hamish.
If performance is a factor, the compiler will produce faster code with the for loop than with map/filter/forEach.
Note that, if you want to go crazy with functional style, Swift 4 will let you return the whole dictionary in a single line:
return [String:String]( uniqueKeysWithValues:
inputs.map{ ($0.type as? ShippingDictKeyable.Type, $0.text) }
.filter{ $0.0 != nil }
.map{($0!.shippingDictKey,$1)}
+ ["email", "second_name", "suffix", "title", "salutation", "company_name"]
.map{($0,"")}
)
This may only work in the playground though cause real projects tend to complain about expressions being too complex more often.
I'm actually trying to parse a Json object with Swift3 on Xcode8.1.
This is my code:
if let objData = objJson["DATA"] as! NSDictionary? {
var msg: String = ""
if let tmp = objData.object(forKey: "Message") {
msg = tmp as! String
} else {
print("NIIILLLLL")
}
}
I'm getting this error message: Could not cast value of type 'NSNull' (0x4587b68) to 'NSString' (0x366d5f4) at this line msg = tmp as! String.
I'm not understanding why I'm getting this error because the type of tmp is Any and it should display the print instead of convert tmp as! String
Thank you for the help,
You can add casting in let.
if let tmp = objData.object(forKey: "Message") as? String {
msg = tmp
}
With Swift 3, for example:
fileprivate var rawNull: NSNull = NSNull()
public var object: Any {
get {
return self.rawNull
}
}
You can check field object as:
if self.object is NSNull {
// nil
}
So to answer your question in why you are getting that error, in your code "tmp" is not nil its something of type NSNull (if you want to know more about NSNull check the docs) but its basically "A singleton object used to represent null values in collection objects that don’t allow nil values."
The rest is just you are force casting which I recommend avoiding this is a safer way to do what you are doing.
guard let objData = objJson["DATA"] as? [String: Any], let msg = objData["Message"] else { return }
// now you can use msg only if exists and also important keeping its unmutable state
I want to initialize a enum from a variable of type String?, like:
guard let rawId = request.queryParameters["id"] else {
return
}
guard let id = MyIdentifier(rawValue: rawId) else {
return
}
In this case, request.queryParameters["id"] returns String?. Then after I ensure that it is String in rawId, I convert it into an enum instance id.
However, the code is dirty and I want to write it in one-line if at all possible.
However, I don't like to make it unwrapped via forced optional unwrapping, because if it can not be transformed to String, the app would end up with an error, since rawValue: only takes String. I meant something like the following, which I don't like:
guard let id = MyIdentifier(rawValue: request.queryParameters["id"]!) else {
return
}
So is it still possible to define the guard let in one-line, maybe using where and/or case in guard?
You have two conditions there, trying to combine them into one condition is not always possible.
In your exact case I believe an empty id will behave the same as a nil id, therefore nil coalescing can be used:
guard let id = MyIdentifier(rawValue: request.queryParameters["id"] ?? "") else {
return
}
However, there is nothing dirty about splitting two checks into two statements. Code is not written to be short, it's written to be clear:
guard let rawId = request.queryParameters["id"],
let id = MyIdentifier(rawValue: rawId) else
return
}
Also, there is nothing wrong with creating a custom initializer for your enum:
init?(id: String?) {
guard let id = id else {
return nil
}
self.init(rawValue: id)
}
and then
guard let id = MyIdentifier(id: request.queryParameters["id"]) else {
return
}
Try this:
You can simply combine both the statements into a single statement ,i.e,
guard let id = request.queryParameters["id"], let id2 = MyIdentifier(rawValue: id) else {
return
}
I'm trying to use swift reflection to check for changes in objects so I can send only changed properties up to the server. Some of my properties are optional. To compare those values, I need to unwrap them but, of course, you can ONLY unwrap actual values, not nil values. So, I need to check if one of the values is nil before I compare them.
In my playground, I tried the following:
import UIKit
class myClass
{
var fieldOne:String?
var fieldTwo:Int?
var fieldThree:Float?
}
var oneMyClass = myClass()
oneMyClass.fieldOne = "blah"
oneMyClass.fieldThree = 3.5
var oneOtherClass = myClass()
oneOtherClass.fieldOne = "stuff"
oneOtherClass.fieldTwo = 3
let aMirror = Mirror(reflecting: oneMyClass)
let bMirror = Mirror(reflecting: oneOtherClass)
for thing in aMirror.children
{
for thing2 in bMirror.children
{
if thing.label! == thing2.label!
{
print("property: \(thing.label!)")
print("before: \(thing.value)")
print("after: \(thing2.value)")
print("")
//let myTest = thing.value == nil ? "nil" : "not nil"
}
}
}
And it generates the following output:
property: fieldOne
before: Optional("blah")
after: Optional("stuff")
property: fieldTwo
before: nil
after: Optional(3)
property: fieldThree
before: Optional(3.5)
after: nil
As you can see, the expected properties are displayed as "nil". However, if you uncomment the let statement, you get an error stating:
playground52.swift:37:38: error: value of type 'Any' (aka 'protocol<>') can never be nil, comparison isn't allowed
And yet, we know from the output that it IS nil. How can this be and what can I do about it?
Based on this answer, I recommend using if case Optional<Any>.some(_).
For example:
aMirror.children.forEach {
guard let propertyName = $0.label else { return }
if case Optional<Any>.some(_) = $0.value {
print("property: \(propertyName) is not nil")
} else {
print("property: \(propertyName) is nil")
}
}
Thats look like some sort of bug. Look at that
let x = childMirror.value == nil ? "Nil" : "Not Nil" //dont compile.
let y = { (value:Any?) in
return value == nil ? "Nil" : "Not Nil"
}
let z = y(childMirror.value) //compile, but doesn't evaluate.
I guess the problem is because Any can store a Optional, but can't be wrapped around one. Try this:
func getValue(unknownValue:Any) -> Any {
let value = Mirror(reflecting: unknownValue)
if value.displayStyle != .Optional || value.children.count != 0 {
return "Not Nil"
} else {
return "Nil"
}
}