Update dictionary with previously deleted items - ios

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 :-)

Related

ParseSwift queryConstraint on object

How can i add a queryConstraint on a object?
This is my current code but it returns no objects. I guess my current code is actually to query on arrays and not objects. But I can't find a way to do this for objects.
let query = Device.query()
.where(containsString(key: "apps", substring: "Google"))
This is the database
I recommend looking at the playgrounds to see how to use ParseSwift properly. More specifically, finding objects.
The first problem is apps is an object, which is actually a dictionary. You can’t use a substring constraint on a dictionary or other object. The actual way to do it is:
let objectToFind = [“Google”: “300”]
let query = Device.query("apps" == objectToFind),

Best way to store and refrence lots data in Swift for use in a UITableView

This is a bit confusing so I apologise. But:
I am trying to make an app where the user has the ability to add items to a list of individual items that will be displayed back to them(Something along the lines of a todo list app) as a table view.
However, I have hit a roadblock I need to store several different bits of data for each item(Some Strings, Some ints and a date) in the list.
I think that a class(or struct) would be the best way to do this where an instance of the class holds the information need for each item and then the name of that instance is stored in a list so it can be accessed via the indexPath in the table view.
However, I don't know how I am going to make a new instance of the class for every item because the app could have hundreds of individual items.
I'm sorry, this is so confusing and any help would be appreciated! Feel free to ask for more info
Edit: what I am looking for and I'm sure there's a stupidly easy way of doing it but I'm try to work out how to create an instance of a class when the name of the class is stored in a variable. Ecencialy I want the instance of the class to store the item. To be created when the user inputs the item to be added to the table.
Eg. They enter an item. item1 and the other data that goes along with then I want to be able to store that in instance of the item class but I don't know how to make the name of that instance because the name I want which is item 1 is stored in a variable.
Sorry that's so confusing that's the reason I need help
So first: You can't store the Name of a Class in a Variable and use this variable to get a new instance of a class.
What you need is an Array containing all the different Items. This array is unlimited so you can store as many items in it as you like and you don't need to set a name for each of these Instances.
First create an empty array containing all Items as a property:
var items : [Item] = []
Second call the function populateItemArray() in your viewDidLoad():
private func populateItemArray() {
// Populate the items Array (Are you using CoreData, Realm, ...?)
}
Third, use the Item Array to populate the TableView.
REMEMBER: If your only using one section in your tableView, indexPath.row is always equal to the corresponding item in the array.
E.G. items[indexPath.row]
Hope this helps you!
UPDATE:
Look at this example struct Item. As you can see you can also store a date in it:
struct Item {
// First create all the properties for your struct.
var data1: String
var data2: Int
var data3: String
// You can create properties of any type you want, also of type date.
var dateOfCreation : Date
// Then implement all the methods of your custom Struct Item.
func setDate(with date : Date) {
self.dateOfCreation = date
}
func returnDate() -> Date {
return self.dateOfCreation
}
}

populate array after adding a new child in swift firebase

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.

How to pass json data in swift app between two viewcontrollers

I need help with passing json data.I have json data in this array
var TableData:Array< String > = Array < String >()
In this Array I have Name,Address,Latitude, Longitude
I show Name and Address in a tableView , but I would like to create annotation in different viewController with Latitude and Longitude depending on which cell user taps(Name,Adress,latitude,Longitude shoulld be equal) , so I am asking you if there is some good tutorial in swift , or if you have just some advice.
Thank you.
There are many different ways to pass data from one swift file to another. In the case that there is a rootViewController and a button is clicked to open a new ViewController. Having previously defined an array in the new ViewController, the json parsed array can be passed along using the prepareForSegue method.
Another popular way to pass information between different swift files would be using the AppDelegate. Here you can create instances of different swift classes using a method known as instantiateViewControllerWithIdentifier("identifier"). This can be done by creating a storyboard variable then calling this method by doing storyboard.instantiateViewControllerWithIdentifier("identifier").
let newvc = self.storyboard?.instantiateViewControllerWithIdentifier("newvcIdentifier") as! (UIViewController extended class)
newvc.data = TableData
self.navigationController?.pushViewController(newController, animated: true)
where newvc has a variable declared as follows:
var data: Array <String>!
Another method that can be used is having shared data among all of the classes using a singleton. A singleton can be created very simply in swift3, take a look here for details.
class JSONData {
var json: Array <String>
static let sharedInstance = JSONData()
}
Before segueing to the next vc, you should store the data in the sharedInstance class. This should be done by overriding the prepare method. Documentation on this method can be found here
sharedInstance.json = self.json
Once the data is set in the shared instance, after the new view controller is loaded, this data can be accessed through sharedInstance.json.
Hope this works for you and just comment if you have any other questions!
I would do something like this:
let newController = self.storyboard?.instantiateViewControllerWithIdentifier("newControllerIdentifier") as! NewControllerClassName
newController.data = array
self.navigationController?.pushViewController(newController, animated: true)
It also appears you are using a array of string type that are comma separated.
I would rather create a variable like below
var jsonArray:[[String:String]]?
so I am asking you if there is some good tutorial in swift
http://matteomanferdini.com/how-ios-view-controllers-communicate-with-each-other/
He covers clean code and best practices. Better read this before implementing anything.
or if you have just some advice
Your code needs to be clean. Passing latitude as String it's going to create you a problem later (conversions, code understanding, or even bugs).
Make a new account here and watch uncle Bob. His lessons are valuable. matteomanferdini above follow uncle bob practices.
https://www.safaribooksonline.com/library/view/clean-code/9780134661742/

Array spontaneously emptying

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

Resources