I have made a struct in which I'm passing my data. The data is in an array. I'm running a for loop to get the value out from it but I'm not getting full values. Suppose there is 5.0 value in an array when the loop runs. It first shows me 5, then ., and then 0. I want it to give 5.0 to me rather than seperate values.
My loop is this:
for price in ItemDataSource.sharedInstance.items[indexPath.row].price! {
print(price)
}
It shows this in console:
This is my class for Items:
class Item : NSObject {
var name : String?
var price : String?
var itemDdescription : String?
}
class ItemDataSource : NSObject {
var items = [Item]()
static let sharedInstance = ItemDataSource()
private override init() {}
}
Here I'm passing my values to it:
let item = Item()
item.name = itemName
item.price = String(result)
item.itemDdescription = String(describing: description)
ItemDataSource.sharedInstance.items.append(item)
Explanation:
ItemDataSource.sharedInstance.items[indexPath.row].price! is a String, iterating over it means to iterate over the characters that are in it. So if the `ItemDataSource.sharedInstance.items[indexPath.row].price!" is "5.0", it will print "5", "." and then "0".
To get the price for the given row, just use
let price = ItemDataSource.sharedInstance.items[indexPath.row].price!
as #John Ottenlips suggested.
Your loop may be unnecessary. indexPath.row will increase and allow you to iterate through your items in this delegate method. If you are just trying to get one price per cell try
let price = ItemDataSource.sharedInstance.items[indexPath.row].price!
print(price)
A general code smell is having a for loop inside a method you are returning a cell in.
Related
I have the following 2 class / structs:
class ConversationDetails {
var messages: [ChatMessage]?
var participants: [User]?
}
class User: Codable {
init (email: String) {
self.email = email
}
// system
var id: String?
var verifiedaccount: Int?
var rejected: Int?
...
}
I've further got the var conversationDetails = ConversationDetails () and I'm populating it with an API call. That all works fine.
I'd like to map the participants array inconversationDetailsand access the id property of each participant like so:
let recipient_ids = self.conversationDetails.participants.map( { (participant) -> String in
return participant.id
})
In my understanding, map iterates over the entire participants array, which is an array of User objects and I can access each item via participant.
However, I get Value of type '[User]' has no member 'id' for return participant.id.
Where is my misunderstanding?
Your participants var is optional, so you need to add question mark to access array. Without it, you try to call map on optional.
This is working code:
let recipientIds = conversationDetails.participants?.map( { (participant) -> String in
return participant.id
})
or shorter:
let recipientIds = conversationDetails.participants?.map { $0.id }
Also, you can use compactMap to remove nils from recipientIds array and have [String] array instead of [String?]:
let recipientIds = conversationDetails.participants?.compactMap { $0.id }
The first problem is that participants is optional so you need to add a ? when accessing it
conversationDetails.participants?
then when mapping you should use compactMap since id is also an optional property
let recipient_ids = conversationDetails.participants?.compactMap { $0.id }
Another variant is to not have an optional array but instead initialize it to an empty array. This is actually a much better way to handle collection properties because you can have a cleaner code by initializing them to an empty collection
var participants = [User]()
and then do
let recipient_ids = conversationDetails.participants.compactMap { $0.id }
This is a little hard to explain, but I'll try my best. I am trying to update a Dictionary inside another Dictionary properly. The following code almost does what I need.
var dictionary = Dictionary<String, [Int : Int]>()
func handleStatsValue(tag: Int ) {
let currentValue: Int = dictionary["Score"]?[tag] ?? 0
dictionary["Score"] = [
tag : currentValue + 1
]
}
However, it seems the dictionary is overridden when the tag value changes (e.g. 1 to 2). I need Dictionary to have multiple dictionaries inside of it. Any tips or suggestions are deeply appreciated.
Edit: I'm trying to have multiple dictionaries nested inside a dictionary. It seems whenever the tag value is changed, the dictionary is overridden.
One way to write this would be:
func handleStatsValue(tag: Int) {
dictionary["Score", default: [:]][tag, default: 0] += 1
}
or, written without [_:default:]
func handleStatsValue(tag: Int) {
var scoreDictionary = dictionary["Score"] ?? [:]
scoreDictionary[tag] = (scoreDictionary[tag] ?? 0) + 1
dictionary["Score"] = scoreDictionary
}
However, it's not a good idea to use nested dictionaries to keep your data. Use a custom struct instead and try to avoid tags too:
struct DataModel {
var score: [Int: Int] = [:]
}
I think you need something like this to either increase the value for an existing tag or add a new tag if it doesn't exist
func handleStatsValue(tag: Int ) {
if var innerDict = dictionary["Score"] {
if let value = innerDict[tag] {
innerDict[tag] = value + 1
} else {
innerDict[tag] = 1
}
dictionary["Score"] = innerDict
}
}
Although the code looks a bit strange with the hardcoded key "Score", maybe it would be better to have multiple simple dictionaries instead, like
var score: [Int, Int]()
or if you prefer
var score = Dictionary<Int, Int>()
class Employee{
var id:Int
var name:String
var salary:Int
init(){
self.id=0
self.name=""
self.salary=0
}
func getInfo(){
self.name=readLine()!
self.id=Int(readLine()!)!
self.salary=Int(readLine()!)!
}
}
var count=0
var flag="y"
var empData:[Employee]=[]
repeat{
count+=1
empData[count]=Employee()
empData[count].getInfo()
flag=readLine()!
}while(flag=="y") `
I have a class Employee with properties id , nam and salary. The function getInfo() is used to get information from user. I want to read data until the flag!="y" . I am getting index out of range error.
What is the right way of inputting data? Can we index the objects ?
You need to append to your array to make it increase in size. Replace
empData[count]=Employee()
with
empData.append(Employee())
to avoid index out of range error
Update
To make your code a little less horrible I would do
repeat {
var employee = Employee()
employee.getInfo()
empData.append(employee)
flag=readLine()!
}while( flag == "y" )
The subscript operator cannot be used to add elements to an array index which doesn't exist yet. You either need to initialize the array with an element count if you know at the time of initialization how many elements your array will have or use the append operator to add new elements to the array after the last index.
You don't even need the count variable, as you can simply access empData.last safely after calling append and adding a new Employee to the Array.
var flag="y"
var empData:[Employee]=[]
repeat {
empData.append(Employee())
empData.last!.getInfo()
flag=readLine()!
} while(flag=="y")
I would advise you to seriously reconsider your implementation as it is really unsafe at the moment. You are not validating user input in any way, hence your getInfo function can easily cause runtime errors if the user input is not in the expected form. Moreover, creating an empty initializer for Employee doesn't make sense, you could simply create a failable initializer, where you read the input and if the input is not of the correct form, make the initializer return nil.
class Employee{
let id:Int
let name:String
let salary:Int
init?(){
guard let name = readLine() else { return nil }
self.name = name
guard let idString = readLine(), let id = Int(idString) else { return nil }
self.id = id
guard let salaryString = readLine(), let salary = Int(salaryString) else { return nil}
self.salary = salary
}
}
var flag="y"
var empData:[Employee]=[]
repeat {
if let employee = Employee() {
empData.append(employee)
} else {
// Display error message to the user
}
flag=readLine() ?? ""
} while(flag=="y")
I have the following Realm Objects
class Patient: Object {
#objc dynamic var name: String?
let list = List<RString>()
}
class RString: Object {
#objc dynamic var stringValue: String?
}
I need to filter Patient objects that have an RString component in List with stringValue = "test"
Is something like this possible?
patients = realm?.objects(Patient.self).filter("name = 'name1' AND #% IN list", RString(stringValue: 'test'))
You need to use a SUBQUERY to be able to access the properties of the elements of a List in an NSPredicate. The SUBQUERY will evaluate true for every Patient whose list property includes at least 1 RString element whose stringValue matches the provided String.
patients = realm?.objects(Patient.self).filter("name = %# AND SUBQUERY(list,$element,$element.stringValue == %#).#count>0", "name1", "test")
I'm new to this forum! I am having a little bit of trouble sorting my Person's array with the use of UILocalizedIndexedCollation.
Code
I created the following class:
#objc class Person : NSObject {
#objc var firstName: String!
#objc var lastName: String!
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
With the help of this class, I created a bunch of instances to be displayed and sorted alphabetically on the table view by their last names.
For me to do so, I created the following function:
func partitionObjects(array:[AnyObject], collationStringSelector:Selector) -> ([AnyObject], [String]) {
var unsortedSections = [[AnyObject]]()
//1. Create a array to hold the data for each section
for _ in self.sectionTitles {
unsortedSections.append([]) //appending an empty array
}
//2. Put each objects into a section
for item in array {
let index:Int = self.section(for: item, collationStringSelector:collationStringSelector)
unsortedSections[index].append(item)
}
//3. sorting the array of each sections
var sectionTitles = [String]()
var sections = [AnyObject]()
sectionTitles.append("Frequently Requested")
for index in 0 ..< unsortedSections.count { if unsortedSections[index].count > 0 {
sectionTitles.append(self.sectionTitles[index])
sections.append(self.sortedArray(from: unsortedSections[index], collationStringSelector: collationStringSelector) as AnyObject)
}
}
return (sections, sectionTitles)
}
With this function, I am able to assign my array of Person and array of titles to the returning values of the function:
var sectionTitles = [Person]()
var personsWithSections = [[Person]]()
var contacts = [Person]()
#objc func setUpCollation(){
let (arrayPersons, arrayTitles) = collation.partitionObjects(array: self.persons, collationStringSelector: #selector(getter: Person.lastName))
self.personsWithSections = arrayPersons as! [[Person]]
self.sectionTitles = arrayTitles
}
With this, I am able able to set up my whole table view and it works great. I get every person sorted up by their last name to their corresponding alphabetical section.
The Issue, Specifically
The problem is that if the user has only inputed their first name and not their last name, that Person object gets appended to the last section of the array, where objects with last names that start with numbers or special characters go.
How can I append these object's with only first names to the corresponding alphabetical
section if the user doesn't input a last name? The same goes with
numbers.
As you can see, my collationsStringSelector takes Person.lastName, I was thinking maybe I could create a computed variable that would return the right person's property under some conditions? I am not sure how I would do so. It would be nice to have some guidance or help!
ps: NEW to the forum! if I'm doing something wrong let me know guys! thanks