Why do I get an error when I used valueForKey... I am using same trick like in objectiveC ...
In ObjectiveC, the code is
self.strSubscribe =[responseObject[#"subscribe"] valueForKey:#"subscribe_ids"];
In Swift , the code is
self.strSubscribe = responseObject["subscribe"].valueForKey["subscribe_ids"] as! String
I declare the variables like
var arraySubCategory : NSMutableArray! = NSMutableArray()
var strSubscribe:String!
And I tried to access the value from below response
{
subscribe =
{
"subscribe_ids" = "1,14";
}
}
Edit
It works using Amit and Eric's solution but now for following data
{
data = (
{
"subscribe_ids" = "1,14";
}
);
}
let dictionary = responseObject["data"][0] as! Dictionary<String,AnyObject>
self.strSubscribe = dictionary["subscribe_ids"] as! String
OR//
if let dic = responseObject["data"][0] as? [String:String], let ids = dic["subscribe_ids"] {
self.strSubscribe = ids
}
but it gives me error:
could not find member 'subscript'
Swift doesn't know the type of responseObject["subscribe"], you have to help the compiler a bit; for example:
if let dic = responseObject["subscribe"] as? [String:String], let ids = dic["subscribe_ids"] {
self.strSubscribe = ids // "1,14"
}
UPDATE:
It's still the same problem: the compiler doesn't know the type of responseObject["data"], so when you try to access the subscript there's an error (because you know it's a dictionary inside the array, but the compiler doesn't).
One solution is to give the type to the compiler by declaring an array of dictionaries in the if let condition:
if let arr = responseObject["data"] as? [[String:String]], let ids = arr[0]["subscribe_ids"] {
self.strSubscribe = ids
}
Notice that it's [[String:String]] (array of dictionaries), not [String:String] (dictionary).
Write like this.
let dictionary = responseObject["subscribe"] as! Dictionary<String, AnyObject>
self.strSubscribe = dictionary["subscribe_ids"] as! String
Since responseObject["subscribe"] will give a AnyObject? output and AnyObject does not have any member called valueForKey.
Related
I'm trying to extract the info from a json array and i'm getting this error
"Cannot subscript a value of type '[[String : Any]]' with an index of type 'String'"
here
if let rev = place.details?["reviews"] as? [[String:Any]] {
if let ver = rev["author_name"] as? String { // <- IN THIS LINE I GET THE ERROR
}
}
i know that if i cast the type as [String : Any] instead of [[String:Any]] it will work, but in this case i have to cast it as an array of arrays otherwise it doesn't read the json, so how can i solve the problem?
[[String:Any]] is an array. It can be only subscripted by Int index.
You have to iterate over the array for example:
if let reviews = place.details?["reviews"] as? [[String:Any]] {
for review in reviews {
if let authorName = review["author_name"] as? String {
// do something with authorName
}
}
}
You can't access an item in an array with a String. You have to use Int
[[String:Any]] This is an array of dictionaries.
[[String:Any]] is a two dimensional Array. It can be only subscripted using Int index.
It is better to use a forEach loop, e.g.
if let reviews = place.details?["reviews"] as? [[String:Any]] {
reviews?.forEach { review in
if let authorName = review["author_name"] as? String {
// do something with authorName
}
}
}
I think you are mixing up dictionaries and arrays here.
If you want to access an element in an array, you have to use an Int index like this
let a = ["test", "some", "more"] // your array
let b = a[0] // print(b) = "test"
If you want to access an element in a dictionary, you can access it via its key, in your case a String
let dict: [String: Any] = ["aKey": "someValue"]
let value = dict["aKey"] // print(value) = "someValue"
In your case you have an array of dictionaries, each of them containing information about a review. If you want to access the author of one of your reviews, you have to first get the review dictionary out of your array like this:
if let reviews = place.details?["reviews"] as? [[String:Any]],
let review = reviews[0] {
// here you can access the author of the review then:
if let author = review["author_name"] as? String {
// do something
}
}
Instead of accessing just the first review like in my example, you can also loop via the array to access all of the reviews one by one
Hello i have variables but gives all of them Optional(). How can i resolve them my codes under below.
Json append codes for koltuklar koltuklaridler array under below you can see
for name in json as! [AnyObject] {
let SeatName = name["SeatName"]
let SeatDesignId = name["SeatDesignId"]
self.koltuklar.append("\(SeatName)*\(SeatDesignId)*")
if let blogs = json["SeatDetail"] as? [[String: AnyObject]] {
for blog in blogs {
let TicketTypeId = blog["TicketTypeId"]
let TicketTypeName = blog["TicketTypeName"]
let Amount = blog["Amount"]
self.koltuklaridler.append("\(SeatDesignId)*\(TicketTypeId)*\(TicketTypeName)*\(Amount)*")
}
}
Under below you can see tableview inside codes ( That codes doing open koltuklar index path item after search id inside koltuklaridler and when found take some varibles from it )
var koltuklar = [""]
var koltuklaridler = [""]
if let myStrings:String! = koltuklar[indexPath.row]{
print("\(myStrings!)")
let myStringArrf = myStrings.componentsSeparatedByString("*")
print("\(myStringArrf)")
if let koltukisims:String! = String(myStringArrf[0]) {
cell.koltukName.text = koltukisims
}
print(" STR - \(myStringArrf[1] as String!)")
if let index = koltuklaridler.indexOf(myStringArrf[1] as String!) {
let myStringdetaysecilen = koltuklaridler[index]
print("myStringdetaysecilen \(myStringdetaysecilen)")
}
Also my json file
[
{
"SeatDesignId": 16484,
"SeatName": "A6",
"SaloonId": 148,
"SeatDetail": [
{
"TicketTypeId": 1,
"TicketTypeName": "Okay",
"Amount": 13
}
]
},
Output
Optional("A17")*Optional(16254)*
["Optional(\"A17\")", "Optional(16254)", ""]
STR - Optional(16254)
All variables output Optional i try everything but doesn't fix.
As mentioned in my comments, whenever you use String Interpolation "\(...)" make sure that all optional strings are unwrapped. Values read from dictionaries are always optional.
This code unwraps all optional strings
for name in json as! [[String:AnyObject]] {
guard let SeatName = name["SeatName"] as? String,
SeatDesignId = name["SeatDesignId"] as? Int else {
continue
}
self.koltuklar.append("\(SeatName)*\(SeatDesignId)*")
if let blogs = json["SeatDetail"] as? [[String: AnyObject]] {
for blog in blogs {
if let TicketTypeId = blog["TicketTypeId"] as? Int,
TicketTypeName = blog["TicketTypeName"] as? String,
Amount = blog["Amount"] as? Int {
self.koltuklaridler.append("\(SeatDesignId)*\(TicketTypeId)*\(TicketTypeName)*\(Amount)*")
}
}
}
Edit: I updated the casting to the actual types according to the JSON
Now declare both arrays as empty string arrays.
var koltuklar = [String]()
var koltuklaridler = [String]()
and remove the optional binding in the first line
let myStrings = koltuklar[indexPath.row]
print("\(myStrings)")
...
By the way: Your way to "serialize" the strings with asterisks and deserialize it in the table view is very, very clumsy and inefficient. Use a custom class or struct for the data records.
Your problem is that you are creating a string from values from dict without a if let statement so it returns an optional value:
for name in json as! [AnyObject] {
if let SeatName = name["SeatName"],
let SeatDesignId = name["SeatDesignId"] {
self.koltuklar.append("\(SeatName)*\(SeatDesignId)*")
}
if let blogs = json["SeatDetail"] as? [[String: AnyObject]] {
for blog in blogs {
if let TicketTypeId = blog["TicketTypeId"],
let TicketTypeName = blog["TicketTypeName"],
let Amount = blog["Amount"] {
self.koltuklaridler.append("\(SeatDesignId)*\(TicketTypeId)*\(TicketTypeName)*\(Amount)*")
}
}
}
There is a two way of operate optional.
unwrapped using "!" but in this chances of crash if value is nil.
unwrapped using term call "optional binding" using "if let" condition.
if let var = "assigned your optional variable"{
print(var)
}
You will get your variable without optional.
I'm having a lot of frustration with Swift when it comes to working with Dictionaries and NSDictionaries.
I am pulling data from a server. One of the values is a Bool.
I started with a Swift Dictionary and moved to NSDictionary out of frustration. However, I still cannot get the values from the dictionary.
All of the following fail with contradictory errors:
let unread:Bool = data!["unread"] as! Bool
let unread:Bool = data?["unread"] as! Bool
let unread:Bool = data?.objectForKey("unread") as! Bool
let unread:NSNumber = data?["unread"] as! NSNumber
error: Could not cast value of type 'NSTaggedPointerString' (0x110c1eae8) to 'NSNumber' (0x10e0ab2a0).
Okay, looks like that data is coming in as a String... let's try:
let unreadStr:String = data!["unread"] as! String
let unreadStr:NSString = data!["unread"] as! NSString
error: Could not cast value of type '__NSCFBoolean' (0x1097413b8) to 'NSString' (0x106bcdb48).
So I'm confused. When I try to convert it to a Bool it says I cannot convert a String to a Number. When I try to convert it to a String, it says I cannot convert a number to a string.
Here is what the data looks like:
Optional({
senderId = 10154040;
sent = 1460844986973;
text = "Test Message 1";
unread = false;
})
You should try something along these lines:
let data: [String : Any] = ["first" : "test", "second" : 2, "third" : true]
let first = data["first"] as! String
let second = data["second"] as! Int
let third = data["third"] as! Bool
print(first)
print(second)
print(third)
I apologise for the title of this question. I have no idea what else to call it.
So... When calling the following:
let testData: [NSObject : AnyObject] = getTestData()
print(testData)
I get this output:
[data: {"TypeId":7,"DataList":null,"TypeName":"This is a test"}]
How would I be able to access the value 7 for the key "TypeId"?
EDIT:
Please note that it's holding { } brackets, not only [ ], thus a cast to NSDictionary is not possible as far as I have tried.
Kind regards,
Anders
You can achieve plist-like nested structures using Any type for dictionary values which is Swift's somewhat counterpart to Objective-C's id type but can also hold value types.
var response = Dictionary()
response["user"] = ["Login": "Power Ranger", "Password": "Mighty Morfin'"]
response["status"] = 200
Any seems to be better than AnyObject because in the above code response["status"] is of type Swift.Int, while using value type of AnyObject it is __NSCFNumber.
The way most people do it is to parse annoying JSON data as custom objects. That should be done as soon as you get the JSON. Ideally, data as JSON should not be used outside your communication code, example:
First, let's define a class to hold your server data:
class MyServerObject {
let typeId: Int
let typeName: String
let dataList: [AnyObject]?
init(dictionary: Dictionary<String, AnyObject>) {
let dataDictionary = dictionary["data"] as! Dictionary<String, AnyObject>
self.typeId = dataDictionary["TypeId"] as! Int
self.typeName = dataDictionary["TypeName"] as! String
self.dataList = dataDictionary["DataList"] as? [AnyObject]
}
}
Note that init method is already parsing the JSON. This doesn't have to be done in init, you could also create a static parse method that will return a new instance.
Usage:
// demo data
let jsonString = "{\"data\": {\"TypeId\":7,\"DataList\":null,\"TypeName\":\"This is a test\"}}"
let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)!
let json = try! NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
// parsing
let myServerObject = MyServerObject(dictionary: json as! Dictionary<String, AnyObject>)
// now we can simply read data as properties
print(myServerObject.typeId)
print(myServerObject.typeName)
One of the good thing about this solution is that we can check the JSON format and all the properties are parsed with the correct types.
Parsing can be hierarchical, for example, if your dataList contains complex objects, let's call them DataListItem, your parsing method can parse each item separately and put them into a [DataListItem], e.g.
if let dataListJSON = dataDictionary["DataList"] as? [Dictionary<String, AnyObject>] {
self.dataList = dataListJSON.map({ DataListItem($0) })
}
Also note that when parsing as! will crash the app when the format is invalid. as? will return nil if the types don't match. as? is very useful for types that can be nil because they are parsed as NSNull instances.
taking in account your data ...
print(testData)
/*
[data: {
DataList = null;
TypeId = 7;
TypeName = "This is a test";
}]
*/
// DataList type should be declared somewhere
class DataList {}
// parse data or set default value, if 'key' doesn't exist
if let data = testData["data"] as? [String:AnyObject] {
let dataList = data["DataList"] as? DataList // nil
let typeId = data["TypeId"] as? Int ?? 0 // 7
let typeName = data["TypeName"] as? String ?? "" // This is test
}
I have the following class which populates all the "Breakfast" entries from a JSON file. Note that in my JSON file, "ingredients" is an array and "instructions" could be an array of arrays.
In the "Populate" function below, Swift is reporting 2 errors saying, "Type 'String' has no member "PopulateArray". "Type 'AnyObject' has no member "PopulateArray".
How do I fix this?
Here's the Swift Source.
import Foundation
class Breakfast
{
var id:String = ""
var name:String = ""
var image:String = ""
var servings:String = ""
var ingredients:[String] = []
var instructions:[AnyObject] = []
func Populate(dictionary:NSDictionary) {
id = dictionary["id"] as! String
name = dictionary["name"] as! String
image = dictionary["image"] as! String
servings = dictionary["servings"] as! String
ingredients = String.PopulateArray(dictionary["ingredients"] as! [NSArray])
instructions = AnyObject.PopulateArray(dictionary["instructions"] as! [NSArray])
}
class func PopulateArray(array:NSArray) -> [Breakfast]
{
var result:[Breakfast] = []
for item in array
{
let newItem = Breakfast()
newItem.Populate(item as! NSDictionary)
result.append(newItem)
}
return result
}
}
The JSON Source can be found here: JSON Source
Neither String nor AnyObject seem to declare a method PopulateArray (unless it's in class extension you haven't included)
If your JSON has contains an array of strings for the "ingredients" key, then it will be an NSArray of NSString, which can be trivially converted to [String]:
ingredients = dictionary["ingredients"] as! [String]
Likewise, if your JSON always contains an array of AnyObject ([AnyObject]) you can populate it with:
instructions = dictionary["instructions"] as! [AnyObject]
Typically when working with JSON, you'll want to use NSJSONSerialization to convert top level JSON data into their corresponding Swift types, here's a quick example of getting data, running it through a serializer and then accessing the JSON data by casting it into known Swift data types:
if let someJsonData = someOptionalData {
if let jsonTopLevelDictionary = try? NSJSONSerialization.JSONObjectWithData(someJsonData, readingOptions: NSJSONReadingOptions.MutableContainers) as? [String:AnyObject] {
if let stringsArr = jsonTopLevelDictionary!["keyWithArrayOfStrings"] as? [String] {
for string in stringsArr {
// do stuff
}
}
}
}
There are a few different ways to skin this cat, you can even check out something like SwiftyJSON which helps parse JSON data into their native swift types.