I'm currently working on an app, and for some reason an array is spontaneously emptying.
I first mention it at the top of the file:
let scaleTypes = [String]()
I then populate it (I verify it's populated by running a println of the array):
let scaleTypes = scaleTypesDict.valueForKey("Types")! as! [String]
println(scaleTypes.count)
When I access the array (when populating the contents of UITableViewCells):
cell.textLabel!.text = scaleTypes[indexPath.row]
I get fatal error: Array index out of range. I've done a println of the array count directly before I access the array, and found that it's emptied itself (it prints 0). The array is not mentioned elsewhere in the file. I use a similar variable name in another view controller in this app, but I highly doubt that that is causing the issue. Anyone got anything?
EDIT: If viewing the entire source code would help, it can be found here: https://gitlab.carson-greene.com/cgreene/scales-ios/tree/dev/Scale%20Randomizer. Unfortunately, I haven't commented things well; be warned. The file that this error happens in is the SRSettingsViewController.swift file.
You are declaring two different variables called scaleTypes.
The first is a member variable, which since you declare with let and then initialize to be empty, will never contain anything.
Then, in your viewDidLoad you are declaring a new, local variable called scaleTypes. You put values in it, but it only exists while your viewDidLoad function is running, where it masks the member variable. When that function exits, it disappears.
Elsewhere in other functions, when you access scaleTypes, you are accessing that empty member variable.
If instead you declare your member variable with var, and then drop the let in front of the assignment in viewDidLoad, you’ll assign the values to the member variable as you’re hoping.
The second time you write let scaleTypes, you are declaring a new array, local to the method it's in.
Change your first let to var, and then append the values later instead of making a new array.
Also, you shouldn't use valueForKey(). Just use the keyed subscripts:
// Declare the variable as mutable
var scaleTypes = [String]()
// Later, add new variables…
if let newScales = scaleTypesDict["Types"] as? [String] {
scaleTypes += newScales
}
Remove the let before populating the array, you're creating a local scoped array with the same name
Related
This is my code to populate my 'Consumables' array (called in my viewDidLoad):
//---------------------- POPULATE CONSUMABLE ARRAY --------------------------------//
private func populateConsumableArray(){
//let the object populate itself.
self.ref?.child("Consumables").observe(.childAdded, with: { snapshot in
let dataChange = snapshot.value as? [String:AnyObject]
let aRequest = Consumable(aDict: dataChange!)
self.consumableArray.append(aRequest)
self.consumableTable.reloadData()
})
}
The Consumable object class is shown below
public class Consumable{
private var type:String
private var count:String
private var sku:String
init (aDict: [String: AnyObject]){
self.type = aDict["Type"] as! String
self.count = aDict["Count"] as! String
self.sku = aDict["SKU"] as! String
}
The data populates my table view just fine... Below is a picture of the code working...
As you can see by the two images above, the code loads the data just fine... The array is populated just fine as well, not shown because it's not directly related to the problem.
Below is a picture of the database structure:
Now when a new consumable is added via my add function the child added only grabs the first attribute added to the consumable item. (also not included, because I'm sure that is working fine, since it populates the firebase database online, which I will show)
The first attribute being 'Type', I switched the order of how things are added to firebase, added 'Count' first and count ended up being the only attribute grabbed. See the image below for what I mean...
Adding a test consumable:
Now you can see that 'Type' is the only attribute being grabbed and stored in the dataChange dictionary, rather than 'Type', 'Count' and 'Sku'.
This is what my firebase database looks like at the above breakpoint so I know that consumables are being added just fine to firebase, it's just a problem with grabbing them when a new child is added to the 'Consumable' parent:
And then, of course, the failure occurs in my Consumable object init function, since 'Count' and 'Sku' are not in the passed dictionary. See below for the fault:
If I close and reload the application, the table view loads with all the data, even the data I previously added that crashed the app. So my question, why does my populateConsumableArray function not grab all the children of the "Consumables" parent?
For the heck of it, I'll add my addConsumableToFirebase() function below, just in case that is the problem for some reason...
Before I start please post code as text not as pictures, so we can actually copy and paste it if needed... (you mostly did but the issue was indeed in the last pic you posted lol)
Now, looking at the Firebase documentation looks like:
setValue(_:) says:
The effect of the write will be visible immediately and the corresponding events will be triggered. Synchronization of the data to the Firebase Database servers will also be started.
Which is why you're seeing it call immediately with only the Type.
Instead try the provided function for updating multiple value at the same time:
func updateChildValues(_ values: [AnyHashable : Any])
Edit:
Removed a part about probably causing a retain cycle since you don't capture self weakly, but as pointed out in the comments, it doesn't apply here.
I am currently having trouble filling up an array of customClass.
I try to fill it with a jsonFile. During my json parsing (using swiftyJSON) i loop and fill my array.
The problem is, at the end of my loop, it is still empty. I tested it in different ways, and here is my code:
That's the file where the problem is. In my loop I fill an Annotation, that I add with append to my array. The problem is what my print return. Here is a part of it:
It's just a small part of a huge jsonfile. And, my tmpAnnot.name is correctly printed every iteration. But when it comes to my Array, nothing.
So I'm completly lost and hope you could help me ^^
(And for the information, here is my custom class) :
And btw, I tried to print my array.count, and it's nil too
Im so sorry if the question has been posted. I couldn't find it in the entire website.
Change your JSONAnnotationList declaration to be an non-optional and assign it an empty array
var JSONAnnotationList: [UGOAnnotation] = []
You see, you have never created an array so there was nothing to be printed.
The whole point of optionals is to use them sparingly, not everywhere.
I have created a UITableView that pulls data from php mysql and passes data back in JSON format. In one of my variables passed in JSON format it's going to contain the value of:
variable = "cell.username.text = signupDate as String"
Is it possible and if so how would I run this variable so that its value '"cell.username.text = signupDate as String"` would run like it normally would if it wasn't inside the variable?
I hope this makes sense and any help would be appreciated. Thanks.
What Im Specifically Trying To Accomplish
MySQL : Data stored as interests separated by commas.
Ex: "Outdoors, Coding, Videogames, etc."
Reformat Interest in PHP : Before sent as JSON to swift I will reformat interests
Note: I am using a cocoa pod called Tag List View
interests variable = "cell.interestsTag.addTag(“ Outdoors”); cell.interestsTag.addTag(“ Coding”); cell.interestsTag.addTag(“ Videogames”);"
Swift3 : Receive JSON variable as
var variable : NSString = (membersArray[(indexPath as NSIndexPath).row] as AnyObject).value(forKey: "variable") as! NSString
when I print variable I get exactly what I want:
cell.interestsTag.addTag(“ Outdoors”); cell.interestsTag.addTag(“ Coding”); cell.interestsTag.addTag(“Videogames”);
This is code inside the variable that needs to be run inside of my tableviewcell. Just can't figure out how to run the variable so it runs the code inside. If its even possible.
I have two dictionaries. Both declared in a viewController, both based on a model structure class.
// ItemDictionary
var ItemDictionary = ItemModel()
var JSONDictionary = ItemModel()
JSON data is fed into the JSONDictionary and then this data is passed to ItemDictionary which feeds a table within ViewDidLoad.
self.ItemDictionary = self.JSONDictionary
All good. The table is nicely populated from JSON data. I can also delete items from the table and the ItemDictionary. However, when I try and add items back by referring to the original dictionary (JSONDictionary) the item has gone.
I understand this is expected. If Dictionary1 = Dictionary2, a new dictionary is not actually created. Only an second address. So if you change Dictionary1, Dictionary2 also changes.
A practical example could be setting a price range. You can reduce the range and have less items displayed on the table. But you can't replace previously deleted items if you wanted to increase the price range. I do not want to recall the JSON script each time I edit the range. Advice appreciated.
As confirmed by the OP, ItemModel is a class and not a Dictionary. To fix this you need to make ItemModel a real Dictionary and thus a value type. This is probably the preferred choice but will be more work.
An alternative would be to add an convenience initializer to the ItemModel class that instantiates a new copy of itself and call that instead of setting self.ItemDictionary = self.JSONDictionary.
Something like this.
init(model: ItemDictionary) -> ItemDictionary {
// copy properties
}
Then create the new copy.
self.ItemDictionary = ItemDictionary(self.JSONDictionary)
Later you can reinitialize ItemDictionary with the same call.
Try this code out-
var dictionary1 = ["name": "Magnus"]
var dictionary2 = dictionary1
dictionary2.removeAll()
print("\(dictionary2) \(dictionary1)")
The output is :-
[:] ["name": "Magnus"]
Thus 2 new dictionaries are being created. If you refer to the Swift documentation, You will find that in swift, references are hardly present.
Some other portion of code might be responsible. Hope this helps :-)
Today I faced a very strange issue in Objective C, if anybody can help me figure out, i would really appreciate it. Let me explain the scenario.
Below is the case:
I make a webservice call and get NSArray of Objects and cached in Global class.
I have a local NSArray in view controller which is nothing but assigned from Global class array. Like this
self.listOfObjects = [GlobalCache sharedInstance].listOfObjects
self.listOfObjects is strong and nonatomic.
In a scenario I updated an object in self.listofobjects, lets say nameProperty of the object in array. Its updated in self.listOfObjects and when i print object using command
po ((ObjectType*)self.listOfObjects[0]).name
its fine and printing the updated value.
But when i see the value in GlobalCache of the same objects, Its not reflecting sometimes its still having old values.
self.listOfObjects is just reference to the GlobalCache listOfobject. (No where it is copied from global cache to local object)
Could it be a memory problem?