Swift cast if possible - swift

I have this code
let jsonData = try JSONSerialization.jsonObject(with: data, options: []) as! [Any?]
if var first = jsonData[0] as! String?{
if(first=="Error"){
DispatchQueue.main.async(execute: {
self.postNotFoundLabel.isHidden = false
});
}else if(first=="Empty"){
print("Empty")
}
}
What i want to do is to cast jsonData[0] to String if it's possible and if it's not then move on.But instead when it's not possible application stops and gives me an error
Could not cast value of type '__NSDictionaryI' (0x1092054d8) to 'NSString' (0x108644508).
How can i cast only when it's possible?

You are trying to force-cast to an optional String. That's not what you want.
Change:
if var first = jsonData[0] as! String? {
to:
if var first = jsonData[0] as? String {
This tries to cast to String. If jsonData[0] isn't actually a String, you get nil and the if var fails.
And you probably want if let, not if var since you don't seem to be making any change to first.

First of all JSON objects will never return optional values so [Any?] is nonsense.
Second of all the error message says the type cast to string is inappropriate because the type of the result is actually a dictionary.
Solution: Check the type for both String and Dictionary
if let jsonData = try JSONSerialization.jsonObject(with: data) as? [Any],
let first = jsonData.first {
if let firstIsDictionary = first as? [String:Any] {
// handle case dictionary
} else if let firstIsString = first as? String {
// handle case string
}
}
PS: A type cast forced unwrap optional to optional (as! String?) is nonsense, too.

Here's the Swifty way to do what you're doing :)
guard let jsonData = try JSONSerialization.jsonObject(with: data, options: []) as? [Any?], let first = jsonData[0] as? String else {
DispatchQueue.main.async(execute: {
self.postNotFoundLabel.isHidden = false
});
return
}
if(first == "Empty") {
print(first)
}

Don't use as! if you are not sure that casting will succeed. The exclamation mark after the as keyword forces the casting, which throws an error if the casting does not succeed.
Use as? instead, which returns an optional variable of the type you were trying to casting to. If the casting fails, instead of throwing an error, it just returns nil.
let jsonData = try JSONSerialization.jsonObject(with: data) as? [Any]
if var first = jsonData.first as? String{
if(first=="Error"){
DispatchQueue.main.async(execute: {
self.postNotFoundLabel.isHidden = false
});
}else if(first=="Empty"){
print("Empty")
}
}

Related

Swift Cannot assign through subscript: subscript is get only

I am fairly new to the Swift syntax and am receiving this error with my code "Cannot assign through subscript: subscript is get only"
This is from the line: friendDictionary[(friendUID as? String)!] = ["name": friendsData!["name"]]
Any advice on the correct way of doing it would be very helpful.
func getFriendsUIDs() {
if FBSDKAccessToken.currentAccessToken() == nil {
print("failed to start graph request")
return
}else{
}
if FBSDKAccessToken.currentAccessToken() != nil {
}
let parameters = ["fields": "name, id, picture"]
FBSDKGraphRequest(graphPath: "/me/friends", parameters: parameters).startWithCompletionHandler {
(NSURLConnection, result, requestError) in
let friendIds = result["id"] as? NSDictionary
let friendsData = friendIds!["data"] as? [NSDictionary]
var ref: FIRDatabaseReference!
ref = FIRDatabase.database().reference()
ref.child("users").child((FIRAuth.auth()?.currentUser?.uid)!).child("friendUIDs").observeEventType(.Value, withBlock: { (snapshot) in
self.FriendUIDs = NSArray()
self.FriendUIDs = (snapshot.value as? NSArray)!
print(self.FriendUIDs)
var friendDictionary = NSDictionary()
for friendUID in self.FriendUIDs {
friendDictionary[(friendUID as? String)!] = ["name": friendsData!["name"]]
}
self.fetchFriendFeed(friendDictionary)
}) { (error) in
print(error.localizedDescription)
}
}
}
func fetchFriendFeed(friendDictionary: NSDictionary) {
var ref: FIRDatabaseReference!
ref = FIRDatabase.database().reference()
for friendUID in FriendUIDs {
ref.child("users").child(friendUID as! String).child("Agenda").observeEventType(.ChildAdded, withBlock: { (snapshot) in
print(snapshot)
if let dictionary = snapshot.value as? [String: AnyObject] {
let friendPost = FriendPost()
friendPost.picture = friendDictionary[friendUID as! String]? ["picture"] as? String
friendPost.activity = dictionary["activity"] as? String
friendPost.date = dictionary["date"] as? String
friendPost.time = dictionary["time"] as? String
friendPost.friendname = friendDictionary[friendUID as! String]? ["name"] as? String
self.friendPosts.append(friendPost)
dispatch_async(dispatch_get_main_queue(), {
self.collectionView?.reloadData()
Nothing to do with Swift. You've elected to use Objective-C, in effect, by making friendDictionary an NSDictionary. NSDictionary is immutable; you can't assign into it or alter it in any way. That is simply a fact about Objective-C. The Swift var declaration makes no difference to this fact.
A better choice, since you are writing in Swift, would be to use a Swift dictionary, which is [AnyHashable:Any]() (in Swift 3). This will interchange with NSDictionary when you are talking to Objective-C, but it will give you a mutable dictionary because you (rightly) declared it with var.
Have you tried using NSMutableDictionary? That solved the issue for me.
For those who get stuck here, another reason for this happens when you try to assign something that does not conform the actual dictionary, in my example i was doing something like this:
var dict = [Date : UUID]()
let randomUUID = UUID()
dict[randomUUID] = Date.now
whereas I meant to write UUID : Date but I was sleepy so i made a mistake, and Swift gave me a misleading error saying subscript is get-only. So this error also appears with type mismatch for Swift 5.7.

Comparing non optional value leads to error

I am on point where I gotta compare non optional value with nil. But I can't do it because Xcode says:
Comparing non-optional value of type 'Int' to nil always returns false
So I created Struct and then made variable: var products: [Product] = []
How I am able to compare it with nil?:
if products[indexPath.row].snusPortions == nil
{
cell.snusPortionsAmountLabel.text = "N/A"
}else
{
cell.snusPortionsAmountLabel.text = String(products[indexPath.row].snusPortions)
}
I've assigned values to them like this:
let ref = FIRDatabase.database().reference().child("Snuses").queryOrdered(byChild: "Brand").queryEqual(toValue: brandName)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists(){
let enumerator = snapshot.children
while let thisProduct = enumerator.nextObject() as? FIRDataSnapshot
{
print(thisProduct.value) // So I may see what the data is like and know how to extract it
// Chances are you'd have to create a dictionary
let thisProductDict = thisProduct.value as! [String:AnyObject]
let productName = thisProductDict["Products"] as! String
let snusPortions = thisProductDict["PortionsCan"] as? Int
let productObject = Product(snusProductTitle: productName, snusNicotine: snusNicotine, snusPortions: snusPortions!, snusFlavor: snusFlavor, snusWeight: snusWeight!, snusShippingWeight: snusShippingWeight, snusProductImageURL: productURL)
self.products.append(productObject)
print(self.products)
}
self.tableView.reloadData()
}
})
This is Product struct:
struct Product {
var snusProductTitle: String
init()
{
snusProductTitle = ""
}
init(snusProductTitle: String){
self.snusProductTitle = snusProductTitle
}
}
While testing it says snusPortions is nil but I said to make it "N/A" if it is nil, why?
It sounds like you are confusing yourself between the local variable snusPortions and the Product property snusPortions.
In your Product definition, the property snusPortions is an Int. It can never be nil. Hence, in this code:
if products[indexPath.row].snusPortions == nil
... this Product's snusPortions will never be nil, and we will never set the text to "N/A".
Now let's look at your other code:
let snusPortions = thisProductDict["PortionsCan"] as? Int
This is a completely different snusPortions. It can be nil, namely, if thisProductDict lacks a "PortionsCan" key or if its value is not castable to Int.

Ambiguous use of 'continue' Bolts-Swift in swift 3

I'm trying to use bolts in my project.
I'm getting this error when I Try to use bolts with continue.
Ambiguous use of 'continue'
also this is my code.
return PFUser._privateDigitsLoginWithConfiguration(configuration: configuration).continue{ task in
guard let result = task.result as? [String:AnyObject] else {
return nil
}
let requestURLString = result[Constants.requestURLStringKey] as! String
let authorizationHeader = result[Constants.authorizationHeaderKey] as! String
print(Constants)
return PFCloud.callFunction(inBackground: "loginWithDigits", withParameters: ["requestURL": requestURLString, "authHeader": authorizationHeader])
}.continue {
PFUser.become(inBackground: $0.result as! String)
}
Does it help if you put parentheses around the continue blocks? That is, you now use
.continue ({ })
instead of
.continue { }
I had the same problem and after Googling found multiple mentions of this and it helped me. It seems like that became a requirement on a recent Swift version change.
This would be your code with the parentheses:
return PFUser._privateDigitsLoginWithConfiguration(configuration: configuration).continue ({ task in
guard let result = task.result as? [String:AnyObject] else {
return nil
}
let requestURLString = result[Constants.requestURLStringKey] as! String
let authorizationHeader = result[Constants.authorizationHeaderKey] as! String
print(Constants)
return PFCloud.callFunction(inBackground: "loginWithDigits", withParameters: ["requestURL": requestURLString, "authHeader": authorizationHeader])
}).continue ({
PFUser.become(inBackground: $0.result as! String)
})

ambiguous use of subscript swift 2.2

I have a lot of issues in my code with this error. Hopefully if someone can help me here than I can figure out the rest of the problems. I have updated to xcode 7.3 and running swift 2.2.
I have read that the compiler has been "more restrictive", and I have to tell it what the "intermediary" objects are. This is causing me some confusion and would love further explanation.
func getMessage(dictionary:NSDictionary)->String{
var message = String()
if let dict = dictionary["aps"] {
if let message:String = dict["alert"] as? String {
return message
}
else{
message = ""
}
}
return message
}
Another example:
for object in objects {
let getDriver = object.objectForKey("driver")
if let picture = getDriver!["thumbnailImage"] as? PFFile {
self.profilePictures.append(picture)
}
self.requestsArray.append(object.objectId as String!)
}
The type of a dictionary value is always AnyObject. Cast the type to something more specific for example
if let dict = dictionary["aps"] as? [String:AnyObject] {
then the compiler knows that key subscripting is valid and possible
The second example is similar: object is a dictionary and the compiler needs to know that the value for key driver is also a dictionary
if let getDriver = object.objectForKey("driver") as? [String:AnyObject] {
if let picture = getDriver["thumbnailImage"] as? PFFile {
...

Swift: Stuck with a compiler error

While exploring a structure read from a json file, I've got this message on the “if let” line which I'm stuck with:
'String' is not a subtype of '(String, AnyObject)'
The code is as follows:
if let descriptions: Array<Dictionary<String,AnyObject>> = fields["description"] as? Array {
let description = descriptions[0]
if let text:String = description["text"] as? String { // where the error occurs
poi.description = text
}
}
You have to unwrap what's read from the description dictionary:
if let text:String = description["text"]! as? String { // where the error occurs
...
}
But that's not safe, because if the key is not found in the dict, it throws a runtime exception. A safer way is:
if let text:String = (description["text"] as AnyObject?) as? String { // where the error occurs
...
}
However, I presume that you're using NSJSONSerialization to deserialize your json data, so a better way to do that is to stick with obj-c types rather than pure swift data types with generics:
if let descriptions = fields["description"] as? NSArray {
let description = descriptions[0] as NSDictionary
if let text = description["text"] as? String {
let x = text
}
}
More compact and much easier to read.
Use the new syntax and less of it.
Test declarations: Dictionary of Array of Dictionary
// let testFields: [String:[[String:Any]]]
or
// let testFields: [String:[[String:String]]]
let testFields = ["description":[["text":"value"]]]
if let descriptions = testFields["description"] {
let description = descriptions[0]
if let text = description["text"] as String? {
println("text: \(text)")
}
}
Output:
text: value