Swift addObject - arrays

So, I'm learning how to get data from DB with JSON and then put the data on some array. Problem accours on last line, citiesArray.addObject(City()), when I need to put all data from object city (id, name, state,...) into array.
I was looking line by line with compiler, and basically everything is fine except that at the end, my array is still empty (its value is nil)?
for (var i=0;i<jsonArray.count;i++){
//Create city objec
var cID: AnyObject? = jsonArray.objectAtIndex(i).objectForKey("id") as NSString
var cName: AnyObject? = jsonArray.objectAtIndex(i).objectForKey("cityName") as NSString
var cState: AnyObject? = jsonArray.objectAtIndex(i).objectForKey("cityState") as NSString
var cPopulation: AnyObject? = jsonArray.objectAtIndex(i).objectForKey("cityPopulation") as NSString
var cCountry: AnyObject? = jsonArray.objectAtIndex(i).objectForKey("country") as NSString
//add city obj (i have City class) to city array
var city = City()
city.cityID = cID as NSString
city.cityName = cName as NSString
city.cityState = cState as NSString
city.cityPopulation = cPopulation as NSString
city.cityCountry = cCountry as NSString
citiesArray.addObject(City())
}

A couple of issues:
You suggested that you were trying to add the city with the following line of code:
citiesArray.addObject(City())
The City() construct will instantiate a new, blank City object. So that line of code would, best case scenario, add a blank City object to your array, which is not what you intended.
When you add the city to your citiesArray, you should simply:
citiesArray.addObject(city)
You say you've defined your citiesArray like so:
var citiesArray: NSMutableArray!
You also need to instantiate an object for this variable (i.e. create an object to which this variable will now point), e.g.:
citiesArray = NSMutableArray()
You are reporting, though, that at the end of this loop, that citiesArray is nil. Really?!? But if you tried to call the addObject method and citiesArray was nil, you could have received a fatal error: "unexpectedly found nil while unwrapping an Optional value".
So, if citiesArray was nil, then jsonArray must have been empty, too. Or for some reason you didn't even get to this loop. I would suggest (a) logging jsonArray; and (b) log or put breakpoint inside this loop and confirm you're even getting in here like you think you are.
Also, check the timing of this (i.e. make sure your statement logging citiesArray is actually taking place after this routine that populates it). I know that sounds crazy, but if you are retrieving the data from some network resource asynchronously, you could have some timing related issues.
Since you're writing Swift code, you might consider using Swift arrays. For example, define your array variable as
var citiesArray: [City]!
And instantiate it with:
citiesArray = [City]()
And add objects to it with:
citiesArray.append(city)

I am pretty sure you need to use the append function:
citiesArray.append(city)
or
if you want to append at the start of the array
citiesArray.insert(city, atIndex: 0)
instead of
citiesArray.addObject(City())
here is a little example: Syntax might not be 100% not on comp with xcode right now.
var strA:String = "apple"
var strB:String = "pineapple"
var strArr = ["kiwi", "mango", "lime"]
strArr.append(strA)
println(strArr.count) //4 ["kiwi", "mango", "lime", "apple"]
citiesArray.insert(strB, atIndex: 0)
println(strArr.count) //5 ["pineapple", "kiwi", "mango", "lime", "apple"]

Related

Simple swift array append not working

I know this is going to be super elementary, but I have this piece of code:
var labels: [String]?
func initVC(image: Images){
self.image = image
let tempLabels = image.label?.allObjects as! [Labels]
for i in 0..<tempLabels.count{
labels?.append(tempLabels[i].label!)
}
}
labels is in the public scope, so the function should have access to it, but when the loop runs through, labels is still nil with no elements.
When I po during debugging, tempLabels is as I expect it to be with 2 string elements.
I'm pretty sure this is a very simple problem, but I guess I'm just out of it right now.
Labels has never been initialised. Change
var labels:[String]?
to
var labels:[String] = []
You are declaring the labels variable but never allowing it to store information. This means that it does not necessarily exist, since it is not initialized, and therefore cannot be used.
For it to be useable, you must initialize it
var labels:[String] = []
Yep, it was super simple.
Changed
var labels: [String]?
To
var labels = [String]()

Swift: Accessing array value in array of dictionaries

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"]

Swift empty array does not have a member named .insert

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)] = []

Modifying an array of dictionaries in Swift

I’m new to Swift and have been having some troubles figuring out some aspects of Arrays and Dictionaries.
I have an array of dictionaries, for which I have used Type Aliases - e.g.
typealias myDicts = Dictionary<String, Double>
var myArray : [myDicts] = [
["id":0,
"lat”:55.555555,
"lng”:-55.555555,
"distance":0],
["id":1,
"lat": 44.444444,
"lng”:-44.444444,
"distance":0]
]
I then want to iterate through the dictionaries in the array and change the “distance” key value. I did it like this:
for dict:myDicts in myArray {
dict["distance"] = 5
}
Or even specifically making sure 5 is a double with many different approaches including e.g.
for dict:myDicts in myArray {
let numberFive : Double = 5
dict["distance"] = numberFive
}
All my attempts cause an error:
#lvalue $T5' is not identical to '(String, Double)
It seems to be acting as if the Dictionaries inside were immutable “let” rather than “var”. So I randomly tried this:
for (var dict:myDicts) in myArray {
dict["distance"] = 5
}
This removes the error and the key is indeed assigned 5 within the for loop, but this doesn't seem to actually modify the array itself in the long run. What am I doing wrong?
The implicitly declared variable in a for-in loop in Swift is constant by default (let), that's why you can't modify it directly in the loop.
The for-in documentation has this:
for index in 1...5 {
println("\(index) times 5 is \(index * 5)")
}
In the example above, index is a constant whose value is automatically
set at the start of each iteration of the loop. As such, it does not
have to be declared before it is used. It is implicitly declared
simply by its inclusion in the loop declaration, without the need for
a let declaration keyword.
As you've discovered, you can make it a variable by explicitly declaring it with var. However, in this case, you're trying to modify a dictionary which is a struct and, therefore, a value type and it is copied on assignment. When you do dict["distance"] = 5 you're actually modifying a copy of the dictionary and not the original stored in the array.
You can still modify the dictionary in the array, you just have to do it directly by looping over the array by index:
for index in 0..<myArray.count {
myArray[index]["distance"] = 5
}
This way, you're sure to by modifying the original dictionary instead of a copy of it.
That being said, #matt's suggestion to use a custom class is usually the best route to take.
You're not doing anything wrong. That's how Swift works. You have two options:
Use NSMutableDictionary rather than a Swift dictionary.
Use a custom class instead of a dictionary. In a way this is a better solution anyway because it's what you should have been doing all along in a situation where all the dictionaries have the same structure.
The "custom class" I'm talking about would be a mere "value class", a bundle of properties. This was kind of a pain to make in Objective-C, but in Swift it's trivial, so I now do this a lot. The thing is that you can stick the class definition for your custom class anywhere; it doesn't need a file of its own, and of course in Swift you don't have the interface/implementation foo to grapple with, let alone memory management and other stuff. So this is just a few lines of code that you can stick right in with the code you've already got.
Here's an example from my own code:
class Model {
var task : NSURLSessionTask!
var im : UIImage!
var text : String!
var picurl : String!
}
We then have an array of Model and away we go.
So, in your example:
class MyDict : NSObject {
var id = 0.0
var lat = 0.0
var lng = 0.0
var distance = 0.0
}
var myArray = [MyDict]()
let d1 = MyDict()
d1.id = 0
d1.lat = 55.55
d1.lng = -55.55
d1.distance = 0
let d2 = MyDict()
d2.id = 0
d2.lat = 44.44
d2.lng = -44.44
d2.distance = 0
myArray = [d1,d2]
// now we come to the actual heart of the matter
for d in myArray {
d.distance = 5
}
println(myArray[0].distance) // it worked
println(myArray[1].distance) // it worked
Yes, the dictionary retrieved in the loop is immutable, hence you cannot change.
I'm afraid your last attempt just creates a mutable copy of it.
One possible workaround is to use NSMutableDictionary:
typealias myDicts = NSMutableDictionary
Have a class wrapper for the Swift dictionary or array.
class MyDictionary: NSObject {
var data : Dictionary<String,Any>!
init(_ data: Dictionary<String,Any>) {
self.data = data
}}
MyDictionary.data

swift setting string from array element error

So im grabbing a property from core data, using a dictionary. And it grabs it just fine. However, when I try to take that single returned attribute and assign it to the navigationitem.title it throws some nasty error. Am I missing something here..
Its not actually outputting an error message in the console but instead is giving me this:
Thread 1: EXC_BREAKPOINT(code+exc_I386_BPT.....
on this line.
0x10707a5f3: nopw %cs:(%rax,%rax)
Also its saying
0 swift_dynamicCastObjCClassUnconditional
code:
override func viewDidLoad() {
super.viewDidLoad()
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext
let frequest = NSFetchRequest(entityName: "Round")
frequest.propertiesToFetch = NSArray(object: "course")
frequest.returnsObjectsAsFaults = false
frequest.returnsDistinctResults = true
frequest.resultType = NSFetchRequestResultType.DictionaryResultType
var fetchedArray = context.executeFetchRequest(frequest, error: nil)
//this is the line that throw the error...why won't it let me set the title to the array of the single returned result?
self.navigationItem.title = fetchedArray[0]
println(fetchedArray)
}
Without a specific error message you are receiving, this is just a guess...
NSArray un untyped contents (that is to say that elements are of type AnyObject), so the compiler probably doesn't think you can set AyObject as a string. So likely need something like:
self.navigationItem.title = fetchedArray[0] as String
Or:
self.navigationItem.title = String(fetchedArray[0])
To start, I would check couple of things to see if the problem is in the fetched array or in the navigation item:
what exactly is returned in fetchedArray[0]? Is is a string? A nil? Something else? Does it actually have anything at index 0? After checking if fetchedArray is not nil and has any elements, you could use "\(fetchedArray[0])"
What is the state of navigationItem? Is it actually instantiated at the time you are trying to set it's title property? I would suggest checking it for nil. You can also try assigning it a string like this: self.navigationItem.title = "Hello" and see if it fails.

Resources