I am new to Swift.
I am trying to get some data from a webservice and to loop the JSON data to make a simple array.
DataManager.getDataFromEndpoint{ (endpointData) -> Void in
let json = JSON(data: endpointData)
if let programsOnAir = json["data"]["data"]["on_air"].array{
var onAirArray = []
for onAir in programsOnAir {
var eventName = onAir["event_name"].string
var eventCover = onAir["event_cover"].string
var tuple = (name: eventName!, cover: eventCover!)
onAirArray.insert(tuple, atIndex: 1)
}
println(onAirArray)
}
}
I get an error where the member .insert does not exist
BUt if I init the array like this var onAirArray = [name: "something, cover: "somethingelse"] then it works.
I need to work with empty arrays and I need to be them mutable, because I have no idea what I may get from the JSON given by the API endpoint.
What am I doing wrong?
The problem is with this line:
var onAirArray = []
Since you haven't given the array an explicit type, this is creating a new instance of NSArray, which doesn't have a method called insert. Which is why this is probably the exact error message you're receiving.
'NSArray' does not have a member named 'insert'
To fix this, explicitly state the type of your array.
var onAirArray: [(String, String)] = []
Related
I ran into an issue with arrays in Swift. The problem is that it's a value type in Swift. I'm trying to find a workaround.
Here is the code that I have:
class Object: Codable{
var name : String?
}
var objects: Array<Object>?
objects = Array<Object>()
if var obj = objects { // <----- Creates a copy of array here
let o = Object()
o.name = "1"
objects?.append(o)
print(obj) //<----- this one is missing "o" object
print(objects)
}
I cannot use NSMutableArray because I have an array inside another codable class.
What's everybody's experience on this one? If somebody can share a solutions for that.
Getting used to arrays as value types isn't too tough really. If i were you my version of the code would just look like this
var objects: Array<Object>?
objects = Array<Object>()
if var unwrappedObjs = objects {
let o = Object()
o.name = "1"
unwrappedObjs.append(o)
objects = unwrappedObjs
}
or alternatively maybe this:
var objects: Array<Object>?
objects = Array<Object>()
if objects != nil {
let o = Object()
o.name = "1"
objects?.append(o)
}
Lastly you could always try making your own "ReferenceArray" class that wraps the array APIs and gives you reference semantics but that seems like overkill. Sooner rather than later, arrays as value types will seem natural to reason about.
bitwit already mentioned this to a point, but I think that your biggest mistake is simply not accepting the new object as the source. Unless it's important to retain the Array<Object>? you should replace it with the Array<Object> one.
var objects: Array<Object>?
objects = Array<Object>()
if var objects = objects { // <----- Creates a copy of array here
let o = Object()
o.name = "1"
objects.append(o) // objects is now the non-optional one
print(objects)
}
If it needs to be in the same scope, use guard:
var objects: Array<Object>?
objects = Array<Object>()
guard var objects = objects else { // <----- Creates a copy of array here
fatalError()
}
let o = Object()
o.name = "1"
objects.append(o) // objects is now the non-optional one
print(objects)
If you absolutely need an array to be referenced, you can make a container class:
public class ReferenceContainer<Element> {
public var element: Element
init(_ element: Element) {
self.element = element
}
}
I've got a server response returning
(
{
agreementId = "token.virtual.4321";
city = AMSTERDAM;
displayCommonName = "bunch-of-alphanumeric";
displaySoftwareVersion = "qb2/ene/2.7.14";
houseNumber = 22;
postalCode = zip;
street = "";
}
)
how do I get the value of agreementId? response['agreementId'] is not working. i've tried some example code with .first but I cannot get it working.
Some extra information, I do a http call to a server with alamofire. I try to parse the json to a constant response:
let response = JSON as! NSDictionary
However that returns a error message
Could not cast value of type '__NSSingleObjectArrayI' (0x1083600) to 'NSDictionary' (0x108386c).
So now parse the json to an array, which seems to be working. The code above is what
let response = JSON as! NSArry
print(response)
spits out.
Now I only need to retrieve the value from the key "agreementId" and I have no clue how to do that.
In swift you need to use Swift's native type Array/[] and Dictionary/[:] instead of NSArray and NSDictionary, if you specify the type like above means more specific then the compiler won't complain. Also use optional wrapping with if let or guard let to prevent crash.
if let array = JSON as? [[String:Any]] {//Swift type array of dictionary
if let dic = array.first {
let agreementId = dic["agreementId"] as? String ?? "N/A"//Set default value instead N/A
print(agreementId)
//access the other key-value same way
}
}
Note: If you having more than one object in your array then you need to simply loop through the array to access each dictionary of array.
if let array = JSON as? [[String:Any]] {//Swift type array of dictionary
for dic in array {
let agreementId = dic["agreementId"] as? String ?? "N/A"//Set default value instead N/A
print(agreementId)
//access the other key-value same way
}
}
I am currently struggling with obtaining a value from an array inside an array of dictionaries. Basically I want to grab the first "[0]" from an array stored inside an array of dictionaries. This is basically what I have:
var array = [[String:Any]]()
var hobbies:[String] = []
var dict = [String:Any]()
viewDidLoad Code:
dict["Name"] = "Andreas"
hobbies.append("Football", "Programming")
dict["Hobbies"] = hobbies
array.append(dict)
/// - However, I can only display the name, with the following code:
var name = array[0]["Name"] as! String
But I want to be able to display the first value in the array stored with the name, as well. How is this possible?
And yes; I know there's other options for this approach, but these values are coming from Firebase (child paths) - but I just need to find a way to display the array inside the array of dictionaries.
Thanks in advance.
If you know "Hobbies" is a valid key and its dictionary value is an array of String, then you can directly access the first item in that array with:
let hobby = (array[0]["Hobbies"] as! [String])[0]
but this will crash if "Hobbies" isn't a valid key or if the value isn't [String].
A safer way to access the array would be:
if let hobbies = array[0]["Hobbies"] as? [String] {
print(hobbies[0])
}
If you use a model class/struct things get easier
Given this model struct
struct Person {
let name: String
var hobbies: [String]
}
And this dictionary
var persons = [String:Person]()
This is how you put a person into the dictionary
let andreas = Person(name: "Andreas", hobbies: ["Football", "Programming"])
persons[andreas.name] = Andreas
And this is how you do retrieve it
let aPerson = persons["Andreas"]
There are several posts on SO like this, and the only solution suggested that would seem to work is manually removing and inserting a property at the same index.
But this feels messy, and some posts suggest it's possible in Xcode 7 to directly update dictionary properties if inside an array of dictionaries.
However, it's not working for the code below, generating the Cannot assign to immutable expression of type [String:AnyObject] error.
// Class vars
var userDict = [String:AnyObject]()
var accounts = [[String:AnyObject]]()
func setHistory(index: Int, history: [String]) {
(userDict["accounts"] as! [[String:AnyObject]])[index]["history"]! = history
(userDict["accounts"] as! [[String:AnyObject]])[index]["history"] = history
userDict["accounts"][index]["history"] = history
userDict["accounts"][index]["history"]! = history
}
All four lines inside of setHistory try to do the same thing, and all fail.
Right now the way you are doing this:
userDict["accounts"] as! [[String:AnyObject]])[index]["history"]
you are working with an immutable container.
You are going to have to design it like this:
func setHistory(index: Int, history: [String]) {
//this line copies from user dict, it is not a pointer
var account = userDict["accounts"] as! [[String:AnyObject]];
//this line sets the new history
account[index]["history"] = history;
//this line will update the dictionary with the new data
userDict["accounts"] = account
}
I think you are better off with a class to model your data.
Anyhow, you can call an old friend from ObjC, NSMutableDictionary:
var userDict = [String: AnyObject]()
var accounts = [NSMutableDictionary]()
accounts.append(["history": ["history1.1", "history1.2"]])
accounts.append(["history": ["history2.1", "history2.2"]])
userDict["accounts"] = accounts
func setHistory(index: Int, history: [String]) {
userDict["accounts"]![index].setObject(history, forKey: "history")
}
setHistory(0, history: ["history1.1", "history1.2", "history1.3"])
print(userDict)
I created an array of dictionary, but I have an error, when I tried to add my object (a dictionary) to my array.
I have this error "AnyObject does not have a member named 'append'"
var posts=[Dictionary<String,AnyObject>]()
var post=Dictionary<String,AnyObject>()
var attachment=Dictionary<String,AnyObject>()
...
post=["id":"a", "label":"b"]
attachment=["id":"c", "image":"d"]
var newPost = [post, attachment]
posts.append(newPost) <- AnyObject does not have a member named 'append'
I don't understand. Maybe I haven't initialize the array correctly ?
UPDATE / SOLVED
var posts=[Dictionary<String,Dictionary<String,AnyObject>>]()
var post=Dictionary<String,AnyObject>()
var attachment=Dictionary<String,AnyObject>()
...
post=["id":"a", "label":"b"]
attachment=["id":"c", "image":"d"]
var newPost = ["post":post, "attachment":attachment]
posts.append(newPost) <- AnyObject does not have a member named 'append'
EDIT : newPost is a instance of dictionary and posts an array of dictionaries
append is to add an item, whereas you are trying to append another array (post is an array of dictionaries). You can use the += operator:
posts += newPost
or use the extend method (which is equivalent to the += operator):
posts.extend(newPost)
or add elements individually:
posts.append(post)
posts.append(attachment)
If you want each post to be an array of post and argument:
var posts=[[Dictionary<String,AnyObject>]]()
Also, you can define the type for post and attachment without creating empty objects:
var post:Dictionary<String,AnyObject>
var attachment:Dictionary<String,AnyObject>