I have 2 classes, I have cats object in the AnimalClass and I am parsing jSON and I want to initialize the cats name from the jSON
class AnimalClass: NSObject {
var cats = [catClass]()
.....
}
And
class catClass: NSObject {
var name : String = ""
init(data : NSDictionary)
{
if let add = data["name"] as? String
{
self.name = add
}
Here I am trying to initialize it in the ViewController.swift
var animals = [AnimalClass]()
for(var i = 0; i < data_array.count; i++)
{
if let add = data_array[i] as? NSDictionary
{
self.animals.append(AnimalClass(data: add)) // this works
self.animals.cats.append(AnimalClass(data: add)) // this doesn't work
}
}
My question is for this line self.animals.cats.append(AnimalClass(data: add)) how can append to cats object which is in the AnimalClass.
You are not able to append AnimalClass to cats because cats is an array of catClass objects. You declared it like this:
var cats = [catClass]()
That's why the code below won't work.
self.animals.cats.append(AnimalClass(data: add))
So you should change it to:
self.animals.cats.append(catClass(data: add))
Moreover, class names in Swift should start with capital letter and I recommend you rename catClass to Cat (also dropping the Class suffix)
You will need to make use the init for your cat class.
change the line:
self.animals.cats.append(AnimalClass(data: add))
to:
self.animals.cats.append(CatClass(data: add))
Related
I have my code below and I am attempting to create new arrays, in which the numbers in the elements increment by 1 whenever the user adds a book. For instance, when the user already has 1 book added and when he adds another one the array should read as ["bookTitle2,"bookAuthor2", "bookPublisher2", "bookNumOfPages2"]
let bookDetails = ["bookTitle", "bookAuthor", "bookPublisher", "bookNumOfPages"]
var bookDetail = ""
var bookNumber = Int()
var bookNumArray = [Int]()
if bookNumArray.contains(bookNumber) {
print("Book already exists")
} else {
while bookNumber < 2 {
bookNumber += 1
bookNumArray.append(bookNumber)
for detail in bookDetails {
bookDetail = "\(detail)" + String(bookNumber)
let newBookArray = [bookDetail]
print(newBookArray)
}
}
}
When I run the code above, this shows up instead:
["bookTitle1"]
["bookAuthor1"]
["bookPublisher1"]
["bookNumOfPages1"]
["bookTitle2"]
["bookAuthor2"]
["bookPublisher2"]
["bookNumOfPages2"]
So I want all the strings that end with 1 in one array and those that end in 2 in another array.
When you do:
for detail in bookDetails {
bookDetail = "\(detail)" + String(bookNumber)
let newBookArray = [bookDetail]
print(newBookArray)
}
For every iteration you are creating a new array with the current detail e.g bookTitle into an array of your string var bookDetail declared outside of this loop's scope.
Also note that newBookArray is a local variable, so it will be destroyed when it gets out of the loop. You would need an array of bookDetail to store the newBookArray.
let bookDetails = ["bookTitle", "bookAuthor", "bookPublisher", "bookNumOfPages"]
var bookDetailArray : [Array<String>] = [] //Your array to store all the bookDetails
var bookDetail : [String] = [] //Your array to store a bookDetail
var bookNumber = Int()
var bookNumArray = [Int]()
Then you can do:
bookDetail.removeAll() //Clear all objects before appending new one
for detail in bookDetails {
bookDetail.append("\(detail) + String(bookNumber)")
}
bookDetailArray.append(bookDetail)
Just a suggestion: As other people said, a dictionary or a class for the bookDetail properties would be a better model in your case. Read up on Object-oriented programming if you ever plan to use a class.
I would do a dictionary or create a class bookDetails with properties like bookTitle, bookAuthor, etc. And then I would create an array of the instances of this class.
If you want to do it your way, Why not create a two-way array, something like:
var arrayFinal = [[""]]
var bookNumber = 0
// Whenever the action is triggered
bookNumber += 1
var bookDetails = ["bookTitle", "bookAuthor", "bookPublisher", "bookNumOfPages"]
for detail in bookDetails
{
detail = "\(detail) +\(bookNumber)"
}
arrayFinal.add(bookDetails)
Or something like that...
I have an array like:-
var arrayData : Array<Dictionary<String, [BottleModel]>> = []
Bottle model :-
class BottleModel: NSObject {
var name : String
var price : Int
var reviews : Int
var category : String
var quantity : String
var id : String
var shopData : ShopModel
}
I want filtered array where price is > 2000
I tried let searchByInts = arrayData.filter({m in m.price < 200})
but getting below error:
Contextual closure
type '(Dictionary) -> Bool' expects 1 argument,
but 0 were used in closure body
How to filter such kind of array based on price
Working code:
let searchByInts = arrayData.filter { $0.values.contains { $0.contains { $0.price > 2000 } } }
By the way please write the following using literals:
var arrayData : [[String : [BottleModel]]] = []
Still no idea if that is what you actually want because your goal is very unclear. You have an array of dictionaries of arrays which actually contain the values you want to filter out. If a BottleModel costs more than 2000 do you want to keep the entire array it is contained in and the dictionary that array is in? You might want to map the entire data into one flat array before or after filtering.
Alternative using flatMap:
let flat = arrayData.flatMap { $0.values.flatMap { $0 } }
let searchByInts2 = flat.filter { $0.price < 200 } // or some other criteria
I have this class
class InboxInterests {
var title = ""
var eventID = 0
var count = ""
var added = 0
init(title : String, eventID : NSInteger, count: String, added : NSInteger) {
self.title = title
self.eventID = eventID
self.count = count
self.added = added
}
}
And i use it like this
var array: [InboxInterests] = [InboxInterests]()
Add item
let post = InboxInterests(title: "test",eventID : 1, count: "test", added: 0)
self.array.append(post)
I want to find the index by eventID key and change the value of added key in the same index
How is that possible?
For me, the above answer did not work. So, what I did was first find the index of the object that I want to replace then using the index replace it with the new value
if let row = self.upcoming.index(where: {$0.eventID == id}) {
array[row] = newValue
}
In Swift 5.0:
if let row = self.upcoming.firstIndex(where: {$0.eventID == id}) {
array[row] = newValue
}
Since you are using a class, use filter and first to find the value:
array.filter({$0.eventID == id}).first?.added = value
In this you:
filter the array down to elements that match the event ID
pick the first result, if any
then set the value
This works since classes are pass by reference. When you edit the return value from array.filter({$0.eventID == id}).first?, you edit the underlying value. You'll need to see the answers below if you are using a struct
EDIT: In Swift 3 you can save yourself a couple of characters
array.first({$0.eventID == id})?.added = value
EDIT: Swift 4.2:
array.first(where: { $0.eventID == id })?.added = value
array.filter {$0.eventID == id}.first?.added = value
The filter operator is not the best in this case, it works for some of you because classes are passed by reference.
Explanation: (You can copy the following code in a playground if you want to verify it).
class Book {
let id: Int
var title = "default"
init (id: Int) {
self.id = id
}
}
var arrayBook = [Book]()
arrayBook.append(Book(id: 0))
arrayBook.append(Book(id:1))
arrayBook.forEach { book in
print(book.title)
}
arrayBook.filter{ $0.id == 1 }.first?.title = "modified"
arrayBook.forEach { book in
print(book.title)
}
Arrays are copied by value not reference, so when you are using filter you are creating a new array (different than the initial), but when you modify the new one, the initial one gets modified too because both are pointing to the same class (classed are passed by reference), so after the filter your array will have changed and the new one gets deallocated. So in this case it will print "default", "default" and then "default, "modified".
What happens if you change class for struct, the value will be passed by value not reference so you will have 2 arrays in memory with different values, so if you go through arrayBooks again it will print before the filter "default","default", and then "default", "default" again. Because when you are using the filter you are creating and modifying a new array that will get deallocated if you do not store it).
The solution is using map, creating a new array with all the values but with the modified items or fields that we want and then replace our array with the new one. This will print "default", "default" before the map, and then "default", "modified"
This will work with structs, classes and everything that you want :).
struct Book {
let id: Int
var title = "default"
init (id: Int) {
self.id = id
}
}
var arrayBook = [Book]()
arrayBook.append(Book(id: 0))
arrayBook.append(Book(id:1))
arrayBook.forEach { book in
print(book.title)
}
arrayBook = arrayBook.map{
var mutableBook = $0
if $0.id == 1 {
mutableBook.title = "modified"
}
return mutableBook
}
arrayBook.forEach { book in
print(book.title)
}
array = array.map { $0.eventID == id ? newValue : $0 }
If you conform your class to Equatable then this would work:
extension Array where Element: Equatable {
#discardableResult
public mutating func replace(_ element: Element, with new: Element) -> Bool {
if let f = self.firstIndex(where: { $0 == element}) {
self[f] = new
return true
}
return false
}
}
Use like this:
array.replace(prev, with: new)
Well first of all we all know that finding an index of an array is easy but I got stump finding an index of an item in an array which contains multiple structs.
This is my class:
class Patient{
private var id: Int
private var name: String
private var gender: String
private var mileage: Double
//global variable
var globalPatientID:Int{
return id
}
var globalPatientName:String{
return name
}
var globalPatientGender:String{
return gender
}
var globalPatientMileAge:Double{
return mileage
}
init(id:Int, name:String, gender:String, mileage:Double){
self.id = id
self.name = name
self.gender = gender
self.mileage = mileage
}
}
This is my array:
let AppUserID = prefs.objectForKey("AppUserID")
for var i=0; i<nou; ++i{
numberOfUsersExisting = nou
if (AppUserID as? String == json[0][i]["App_ID"].stringValue){
print("Assigning AppUserID")
appUserMileage = json[0][i]["Mileage"].doubleValue
}
pSample += [Patient(id: json[0][i]["ID"].intValue, name: json[0][i]["Name"].stringValue, gender: json[0][i]["Gender"].stringValue, mileage: json[0][i]["Mileage"].doubleValue)]
pSample.sortInPlace({$0.globalPatientMileAge < $1.globalPatientMileAge})
}
So pSample is initially a blank array and it appends a class of items through a loop.
The sortInPlace function helps me to sort pSample based on globalPatientMilaAge.
So this got me thinking, how do I get the index of my AppUserID(which I cast it as a String) from the array of class?
I tried using this function but it doesn't seems working because I'm looping through classes instead of items inside a class.
appUserRanking = pSample.indexOf("\(AppUserID)")
The body of indexOf can be a closure like the map and filter functions
appUserRanking = pSample.indexOf{$0.globalPatientID == AppUserID}
PS: It's pretty inefficient to get one object from json (json[0][i]) 6 times in the repeat loop.
Assign the object to a variable
let object = json[0][i]
and use it for example
if (AppUserID as? String == object["App_ID"].stringValue){
Do like this,
let pSampleFiltered = pSample.filter {$0.globalPatientID == AppUserID}
if pSampleFiltered.count > 0 {
if let index = pSample.indexOf(pSampleFiltered.first!) {
// Do your stuff here
}
}
In Swift 3 and above mapping works like this
appUserRanking = pSample.index(where: {$0.globalPatientID == AppUserID})
If I declare a class property as:
var list = Dictionary<String, StructType[]>()
and then try to add a value from within a class method with:
var structType = StructType()
list[ "A" ] = [ structType ]
I get a runtime EXC_BAD_INSTRUCTION error. However, if I declare the dictionary within the class method and add a value there is no error.
It has something to do with the dictionary having values which are arrays. If I change the declaration to something simpler, like:
var list = Dictionary<String, String>()
then within the class method:
list["A"] = "some string"
works without any issues.
Any ideas?
UPDATE:
I've also tried declaring:
var list = Dictionary<String, String[]>()
and there is no issue referencing the list within a class method.
list[ "A" ] = [ "String1", String2" ]
Also the class declaration:
var list = Dictionary<String, SomeStruct>()
can be referenced within a class method.
UPDATE 2:
The struct is defined as:
struct Firm {
var name = ""
}
If you create your list and class in the following way it should work fine:
struct StructType {
var myInt = 0;
}
class MyClass {
var list = Dictionary<String, StructType[]>()
func myFunc () {
var structType = StructType()
list[ "A" ] = [ structType ]
}
}
var a = MyClass()
a.myFunc()
The following code appears to work for me in a playground.
struct StructType {
}
var list = [String:[StructType]]()
var structType = StructType()
list["A"] = [structType]