Appending Class Objects to Array [Swift] - arrays

I have a RestAPI that pulls JSON data from a webpage, and because I want to follow MVC programming standards, I want to fetch this data through a "Data List" class that instantiates the RestAPI Class.
I have a class called "Card", which provides the basic structure of a type of data object. I have a class called "CardList" whose initialization creates an Array of the "Card" Classes.
However, I'm having trouble appending Card Class data to my CardList Array.
Here is the code for CardList Class:
class CardList {
var cards: [Card]
static var sharedInstance = CardList()
//MARK - Initalize
private init(){
//Dummy Data
let helm = Card(name: "Helm of Testing", cost: 10, type: "Equipment", subType: "Head Armor", description: "Some say the Helmet of Testing helps keep it's wearers mind clear.")
//Add to Array
var c = [helm]
let items: NSMutableArray = []
//Get API Array
RestApiManager.sharedInstance.getElements { (json: JSON) in
let results = json["results"]
for (_, subJson) in results {
let card:AnyObject = subJson["card"].object
items.addObject(card)
}
for var i = 0; i < items.count; ++i{
let data:JSON = JSON(items[i])
let newCard = Card(name: data["title"].stringValue, cost: Int(data["cost"].string!)!, type: data["type_id"].stringValue, subType: data["subtype_id"].stringValue, description: data["description"].stringValue)
c.append(newCard)
}
}
cards = c.sort { $0.cost < $1.cost }
}
//END Class
}
So basically on initialization, this class creates a dummy Card, adds it to an array called "c". An array called "items" is created. There RestApiManager returns JSON data, for every type of data returned in the results, it gets added into the "items" array.
We then loop through the "items" array, reading it as JSON (I'm using the SwiftyJSON plugin/code snip) and creating a new "Card" Class for each item in the array. We then append the "Card" to the "c" Array.
Finally we take the Card Array "cards" and set it equal to the "c" Array sorted by it's value cost.
The Problem:
After running the code, the "cards" Array only returns the dummy card named "helm", and none of the data added to the "c" array.
Notes:
Yes, my Api is working, if I print the values in the "for var i = 0" loop, it is printing correct values. If I print the "c.count" in the same loop, I get two (The API is only returning 1 other data set, or "Card"). If I print the "c.count" outside of that loop, after the loop, it says there is only 1 item in the Array when there should be two (the dummy data and the data returned from the JSON call).
So, it's clearly something with my syntax. Or maybe I'm making things more complicated than they need to. I'm fairly new to Swift and slightly confused. I just need someone else to look at my code.
Thank you in advance.

RestApiManager.sharedInstance.getElements works asynchronously.
The block containing the data is executed after the init function exits.
Move the code to assign and sort the array into the block.
...
for var i = 0; i < items.count; ++i{
let data:JSON = JSON(items[i])
let newCard = Card(name: data["title"].stringValue, cost: Int(data["cost"].string!)!, type: data["type_id"].stringValue, subType: data["subtype_id"].stringValue, description: data["description"].stringValue)
c.append(newCard)
}
cards = c.sort { $0.cost < $1.cost }
}
}

Related

how do I get rid of this simple SwiftUI error?

I just wanna get all the records from the transaction variable and save it to an array.i tried and all I am getting is this constant error. please help me, I just wanna all models(records) to be saved on an array.
Type '()' cannot conform to 'View'
#State private var transactions: [Transactions] = [Transactions]()
ForEach(transactions, id: \.self) { transaction in
timexxx[0] = transaction.timexx ?? "0"
Text(timexxx[0] ?? "0")
}
enter image description here
Like what #multiverse has suggested
ForEach loop expects some sort of View but you are giving it or attempting to give an "array" (it only wants View)
Here is an updated code where you give the ForEach what it wants and you append to your timexxx array
ForEach(Array(transactions.enumerated()), id: \.offset) { (offset, transaction) in
Text(transaction.timexx ?? "\(offset)")
.onAppear {
timexxx[offset] = transaction.timexx ?? "\(offset)"
}
}
Update
for your question
"how do I do this with a simple "For" loop ? let's say I wanna do this operation in a simple class."
This is how it's done.
I removed the view Text.
for (i, transaction) in transactions.enumerated() {
timexxx[i] = transaction.timexx ?? "0"
}
Ok , so this is an error i faced as well, when i was learning SwiftUI( i am still a beginner), so now we need to understand , what does this error actually means, in this case the ForEach loop expects some sort of View but you are giving it or attempting to give an "array" (it only wants View)....
If you want values to be transferred to an array just simply create a function and do it .....
say you have a class and inside of which you do
#Published var song = [Song]()
then what you do is inside a function like loadData()
objects is the array whose elements you want transferred and most likely those elements belong to a Struct like Song here(if not its even simpler just use what ever type it has like Int, String etc.), this way all your elements will get transferred to song from objects
func loadData() {
song = objects.map {
artist in
Song(album: artist.album, artistImage: artist.artistImage)
}
}
Here i add the simplest possible way to transfer from one array to other
var objects = [1,2,3,4,5]
var song = [Int]()
func loadData() {
song = objects.map { $0 }
}
loadData()
print(song)
//[1,2,3,4,5]

How to pull all objects from an array of unknown length and place them into a state variable in React?

I imported data from another file (so I technically think it's an object containing an array of objects) called { groupData }. At the moment, the array contains only 5 objects, but it is variable in length and could contain more. Each object looks like this:
{
name: "A Name",
img: "https://imgURL.goes.here",
details: "This is a fun group about fun things.",
likes: 45,
},
My goal is to take each object from the array, modify the data, and place the objects into an empty stateful array called "groups". I want each object to look like this before it goes into the new "groups" array:
{
name: "A Name",
img: "https://imgURL.goes.here",
details: "This is a fun group about fun things.",
hasNotification: Boolean,
userIsAdmin: Boolean,
},
I thought of destructuring the array, but this solution is not scalable if things are going to be added to the array:
const [groupZero, groupOne, groupTwo, groupThree, groupFour] = groupData;
What is the most efficient way to accomplish this? Thank you!!
I am not exactly sure what you need because of the lack of context. But you can use a for loop to iterate through each object in the array.
If it is fine to moderate the existing data:
for (data of groupData){
delete data.likes;
data.hasNotification = true; // or false
data.userIsAdmin = true; // or false
}
setState(groupData); // if you are using useState hooks
If you do not want to change original data:
// create a deep clone of groupData
const newGroup = JSON.parse(JSON.stringify(groupData));
for (data of newGroup){
delete data.likes;
data.hasNotification = true; // or false
data.userIsAdmin = true; // or false
}
setState(newGroup);
Adjust the setState section accordingly if you are using class components

Put all maps inside one list

My problem with Flutter is when I'm converting an array to a list, there is every item is a separated list and I want all the items in just one list.
Example output when putting 2 items:
[{title: ITEM1}, {title: ITEM2}]
I want to put like this:
[{title: ITEM1, title: ITEM2}]
I hope you guys understand the problem
void _addPecas() {
if ((_pecasController.text.isEmpty) ||
((_pecasController.text.trimLeft() == ("")))) {
print("Campo Vazio");
} else {
setState(() {
Map<String, dynamic> newPeca = Map();
newPeca["title"] = _pecasController.text.trimLeft();
_pecasController.text = "";
_pecasList.add(newPeca);
print(_pecasList);
});
}
}
if [{title: ITEM1, title: ITEM2}] is what you want to achieve,
The problem here is that you are creating a new Map called newPeca every time your function runs. .
Map<String, dynamic> newPeca = Map();
So by the time you set your values you call _pecasList.add(newPeca); that new map will be appended to your List thus you get [{title: ITEM1}, {title: ITEM2}]
Working with the assumption that you want only one Map in _pecaList, _newPeca should always reference that one Map
Map<String, dynamic> newPeca = _pecaList[0]
then you can add your desired values newPeca["title"] = _pecasController.text.trimLeft();
One more problem you'll run into, you want to have duplicate keys in the Map, which is not possible.
The newer value in the map will overwrite the existing one.
E.g
newPeca[title] = "Item 1"
newPeca[title] = "Item 2"
newPeca[title] will end up being Item 2
As I understood, you are asking for one Map inside List and add values into that Map and finally add it into a List. Here is how you can do it:
Map<String, dynamic> newPeca = Map();
if (_pecasController.text.isEmpty ||
_pecasController.text.trimLeft() == ("")) { // you had too much unwanted brackets here
print("Campo Vazio");
} else {
setState(() {
newPeca["title"] = _pecasController.text.trimLeft(); // you have to have unique key if you want to keep in one Map. See the dart pad example I have provided a link below
_pecasController.text = "";
// _pecasList = [newPeca]; // this is also working without outside .add() but if the list is long, im not recommending this.
print(_pecasList);
});
}
// outside the iteration
_pecasList.add(newPeca);
Edit simple dart example in dartpad
Update:
Make sure this: Map<String, dynamic> newPeca = Map(); outside the iteration. This way you are not creating Map for each and every iteration. You are adding to same map and that map you should add after each iteration to the List or just create empty list assign as a new list in each and every iteration(Btw, not the performant way).
Secondly, when you add to the list inside iteration each and every time map will add to the list.
Finally, Even if you make those right, your map will not take same value as title because the reason is your key of the map entry is title and you cannot have duplicate keys inside map and the list should be outside the iteration.

Find the element in custom array and append the value in one of its property(which is also an array) of custom array in swift

#objc class CplModel:NSObject {
var cplModel:UserCplModel = UserCplModel(json: [:])
var courseData:[CourseModel] = [CourseModel]()
var feedData:[FeedsModel] = [FeedsModel]()
var assessmentData:[AssessmentModel] = [AssessmentModel]()
var userCourseData:[UserCourseModel] = [UserCourseModel]()
init(jsonUserCPlModel:[String:Any]){
if let value = jsonUserCPlModel[""] as? [String:Any]{
self.cplModel = UserCplModel(json: value)
}
}
init(jsonAssessmentAndCourseData:[String]) {
}
}
I am making three Firebase calls and all three are interlinked and want to populate data in above model.
Here comes the issue:
For 1st API call I need to populate only cplModel:UserCplModel property
For 2nd ApI call I need to populate courseData:[CourseModel] and assessmentData:[AssessmentModel]
But the index should remain the same for every populating data.
I mean to say is for 1st index of cplModel, I need to insert the courseData or assessmentData but the response of 2nd API comes later and I need to insert the data in particular index only.

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

Resources