Array values not showing up in custom table cell - ios

I am making a simple weather app and my table view is supposed to show the weeks forecast by showing the day on the left side and the high temp on the right side. My cellForRowAtIndexpath is below. It correctly displays the dayarray in my custom daylabel but the maxarray which contains max temperatures doesn't show up. When I print out the max array values it looks correct and all the numbers are listed there but still does not show up. If I just hard code a value in that text label like "Test" then that will show up but the array doesn't.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! DailyWeatherTableViewCell
cell.daylabel.text = dayarray[indexPath.row] as? String
cell.maxlabel.text = maxarray[indexPath.row] as? String
return cell
UPDATE: My array is set up like this:
dayarray = [dateString1,dateString2, dateString3, dateString4, dateString5, dateString6, dateString7]
maxarray = [max1int, max2int, max3int, max4int, max5int, max6int, max7int]
Its kind of complicated where these values come from but if I print out maxarray, it looks like this:
100
100
92
90
90
89
89

I think the way you cast the Int to String cause the value to nil. Try change to below instead:
cell.maxlabel.text = String(maxarray[indexPath.row])
The different is that String() is create an object of string from the Int value. while the as? operator normally used when you have different type of objects in your array and you want to cast it to specific type. for example
let arr = [1, 21, 3, 5, "Hello world", 1, 2, "food"]
for element in arr {
if let stringValue = element as? String {
print(stringValue)
}
else if let intValue = element as? Int {
print (intValue)
}
}

Related

It throws an error "Index out of range" when I try to remove a value from dictionary

I'm newbie programmer, and not talented yet, I stucked in an error and I can't handle it for days. I have problem with indexpath, when I try to remove something from Dictionary it throws an error, “fatal error: Index out of range“
Briefly, I showed my dictionary and tableview in the below, and numberofrows and members may increase or decrease, I’m adding these members to dictionary when I checked one of them on tableview, and it adds selected one without any problem. But problem begins when I remove one of my selected ones, I think the cause is index numbers, because their index numbers are changing when they included to dictionary. I want to remove exact person that I select, but how it's going to be possible?
For example, when I remove by unchecking person3, there must only person1 and person5 in dictionary. If the code and error is not clear, please let me know.
this is how looks of my tableview, members list;
1. person1 ✔️ // -> index 0
2. person2
3. person3 ✔️ // -> index 2
4. person4
5. person5 ✔️ // -> index 4
selected ones added to dictionary
var selectedUser = [NSDictionary?]()
var friendsDic = [NSDictionary?]()
// Inside of selectedUser after the adding members.
[{
email = “person1#gmail.com";
id = jqvDUcBoV9Y4sxir5kR0dg1; // person1 index is still 0
name = person1;
profileImageUrl = "<null>";
}, {
email = “person5#gmail.com"; // Now person5 index is 1
id = hVfS9EU6LWatAynJNyDmum4A2;
name = person5;
profileImageUrl = "https://firebasestorage.googleapis.com/v0/b/findyourfrienddemo.appspot.com/o/profile_images%2FAE5ED4E4-CF53-4AC4B628.jpg?alt=media&token=eb969e-57290d7e02c9";
}, {
email = “person3#gmail.com"; // and person3 index is 2
id = 6LwvafOJLSQsbhJwu8MJjYI3;
name = person3;
profileImageUrl = "<null>";
}]
And this is my whole code:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
let friendUser: NSDictionary?
friendUser = friendsDic[indexPath.row]
if cell!.isSelected {
cell!.isSelected = false
if cell!.accessoryType == UITableViewCellAccessoryType.none {
cell!.accessoryType = UITableViewCellAccessoryType.checkmark
}
else {
cell!.accessoryType = UITableViewCellAccessoryType.none
}
}
if cell!.accessoryType == UITableViewCellAccessoryType.checkmark {
let named = friendUser?["name"] as! String
let urlImg = friendUser?["profileImageUrl"] as? String
let id = friendUser?["id"] as! String
let email = friendUser?["email"] as! String
let dicc: [String: String?] = ["name": named, "email": email, "id": id, "profileImageUrl": urlImg]
databaseRef.child("selectedfriends").child(id).child(CurrentUserID!).setValue(true)
selectedUser.append(dicc as NSDictionary)
MapPage.selectedUsersInfo = selectedUser as! [NSDictionary]
}
if cell!.accessoryType == UITableViewCellAccessoryType.none {
let id = friendUser?["id"] as! String
databaseRef.child("selectedfriends").child(id).child(CurrentUserID!).setValue(false)
var i = indexPath.row
selectedUser.remove(at: i)
MapPage.selectedUsersInfo = selectedUser as! [NSDictionary]
}
}
The code you posted does not make sense. It looks like you have a data structure friendsDic that is an array of dictionaries containing an entry for every cell in your table view.
When the user selects a cell you extract the fields from that cell's friendsDic entry and use those fields to build a NEW dictionary that you append to the end of an array selectedUser.
When the user deselects a cell you try to use the row of the cell in the table view to remove that entry from selectedUser, but the selectedUser array's elements will not be in any particular order (They'll be in the order in which the user checked them.) Even if they do happen to be in the same order as the entries in the friendsDic array, the array indexes won't match up because the non-selected items from friendsDic won't be in the selectedUser array. That's why you are getting index out of range errors.
It looks to me like your design is flawed and needs to be reworked.
You need to step back and explain what you're trying to do (app function) at a higher level, and then logically how you have attempted to implement that functionality.
EDIT:
Please stop describing your data model as a dictionary. It's not. You have an array. The elements of the array are dictionaries. As Hamish said in his comment, an array of structs would be a better choice, but you could make an array of dictionaries work.
I suggest not trying to maintain a second array of selected items. You can set up the table view to support multiple selection, and then use the method indexPathsForSelectedRows to get an array of index paths of the selected rows.

Mapping between array of enums and a dictionary of enums

Here's what I'm trying to do:
Provide a tableView that allows the user to select a formula name (an enum) that will be set as their default
In this view I'll place a checkmark next to the formula that is the current default
Their chosen default formula is what will determine which formula is used to calculate a 1 rep maximum amount (the theoretical amount the user could lift based on actual lifts of lesser weight)
After calculating the value, the user will be able to save a record of the lifts they did, the formula used to calculate the maximum, and the calculated maximum weight.
That record will be saved in Core Data with one of the entities being Lift which will simply be the formula name
I've created a class that I want to handle the work of providing the current default formula to what ever part of the app needs it as well as set the default when a new one is selected.
Here is my enum of the formula names:
enum CalculationFormula: Int {
case Epley
case Brzychi
case Baechle
case Lander
case Lombardi
case MayhewEtAl
case OConnerEtAl
}
and with help from the SO community, I created this class to handle the management of userDefaults:
class UserDefaultsManager: NSUserDefaults {
let formulas = [CalculationFormula.Baechle, CalculationFormula.Brzychi, CalculationFormula.Epley, CalculationFormula.Lander, CalculationFormula.Lombardi, CalculationFormula.MayhewEtAl, CalculationFormula.OConnerEtAl]
let formulaNameDictionary: [CalculationFormula : String] =
[.Epley : "Epley", .Brzychi: "Brzychi", .Baechle: "Baechle", .Lander: "Lander", .Lombardi: "Lombardi", .MayhewEtAl: "Mayhew Et.Al.", .OConnerEtAl: "O'Conner Et.Al"]
let userDefaults = NSUserDefaults.standardUserDefaults()
func getPreferredFormula() -> CalculationFormula? {
guard NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys.contains("selectedFormula") else {
print("No value found")
return nil
}
guard let preferredFormula = CalculationFormula(rawValue: NSUserDefaults.standardUserDefaults().integerForKey("selectedFormula")) else {
print("Wrong value found")
return nil
}
return preferredFormula
}
func setPreferredFormula(formula: CalculationFormula) {
NSUserDefaults.standardUserDefaults().setInteger(formula.rawValue, forKey: "selectedFormula")
}
You can see I have an array of the enums in the order I want them displayed in the tableView and a dictionary of the enums so I can get each enum's string representation to display in each cell of the tableView. Here's how I populate the cell text label which works:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("formulasCell", forIndexPath: indexPath)
let currentFormula = formulas[indexPath.row].formulaName
cell.textLabel?.text = currentFormula
return cell
}
and here's where I'm setting the checkmark anytime a cell in the tableView is selected
func refresh() {
let preferredFormula = defaults.getPreferredFormula()
for index in 0 ... formulas.count {
let indexPath = NSIndexPath(forItem: index, inSection: 0)
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
cell.accessoryType = preferredFormula == index ? .Checkmark : .None
}
}
}
As I mentioned at the beginning, I need to do many different things with this enum but to keep this question focused on one thing, I'll stay with this checkmark example which now doesn't work after creating my UserDefaultsManager class
The problem is obvious - preferredFormula is now an enum and I can't compare that to the index value which is an Int - but the solution is not. I could get the raw value of the enum but the rawValues aren't guaranteed to be in alignment with the cell indexPaths. Some ideas I've had are:
I could probably change the order of the enum cases so their raw values match the order I've put them in my formulas array, but that seems silly and unreliable
I could use the array index values but that seems equally silly and unreliable
If I just use the array, I don't have the string representations of the cases to display in the cells
It seems that using the array and dictionary together is a viable but the best I could come up with is maybe creating another dictionary that maps the enums to Ints but that would have the same issues I just listed.
Any guidance someone could provide would be greatly appreciated.
You seem to have made things a little more complicated than they need to be.
Firstly, you can use a String raw value for your enum and avoid the associated dictionary:
enum CalculationFormula: String {
case Epley = "Epley"
case Brzychi = "Brzychi"
case Baechle = "Baechle"
case Lander = "Lander"
case Lombardi = "Lombardi"
case MayhewEtAl = "Mayhew Et.Al."
case OConnerEtAl = "O'Conner Et.Al"
}
Second, Your UserDefaultsManager doesn't need to subclass NSUserDefaults, it is simply some utility functions. Also, you are doing a lot of checking in getPreferredFormula that you don't need to. I would suggest re-writing that class to use a computed property like so:
class UserDefaultsManager {
static let sharedInstance = UserDefaultsManager()
private var defaultsFormula: CalculationFormula?
var preferredFormula: CalculationFormula? {
get {
if self.defaultsFormula == nil {
let defaults = NSUserDefaults.standardUserDefaults()
if let defaultValue = defaults.objectForKey("selectedFormula") as? String {
self.defaultsFormula = CalculationFormula(rawValue: defaultValue)
}
}
return self.defaultsFormula
}
set {
self.defaultsFormula = newValue
let defaults = NSUserDefaults.standardUserDefaults()
if (self.defaultsFormula == nil) {
defaults.removeObjectForKey("selectedFormula")
} else {
defaults.setObject(self.defaultsFormula!.rawValue, forKey: "selectedFormula")
}
}
}
}
I have made the class a singleton; although this may have an impact on testability it simplifies issues that could arise if the default is changed in multiple places.
The appropriate place to set/clear the check mark is in cellForRowAtIndexPath so that cell reuse is handled appropriately. This code assumes that formulas is an array of CalculationFormula:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("formulasCell", forIndexPath: indexPath)
let currentFormula = formulas[indexPath.row]
cell.textLabel?.text = currentFormula.rawValue
let preferredFormula = UserDefaultsManager.sharedInstance.preferredFormula
cell.accessoryType = currentForumula == preferredFormula ? .Checkmark : .None
return cell
}

value of type results has no member realm swift2

I have data saved in a Realm that I am trying to display in a custom tableview cell. Here is the code.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> JobTableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("JobCell") as! JobTableViewCell
//var jobs: Results<Job>?
let jobs = realm.objects(Job) as String
cell.nameLabel?.text = jobs.name
cell.addressLabel?.text = jobs.address
cell.phoneLabel?.text = jobs.phone
cell.emailLabel?.text = jobs.email
return cell
}
I am getting the error "Value of type'Results<(Job)> (aka 'Results) has no member 'name'. This error repeats on all four label lines.
I have tried to cast the type to String which eliminates the errors on the label lines, but creates a new error "Cannot convert value of type '(Job)' ... to expected argument type 'T.Type'
I am new to this so please excuse me if my post is not done correctly.
The problem is on this line:
realm.objects(Job) as String
The you're trying to convert Results<Job> to a string, which is not a compatible type.
You probably want to apply the values of the item in some Realm Results at the index of indexPath.row to your cell's UI components like this:
let job = realm.objects(Job)[indexPath.row]
cell.nameLabel?.text = job.name
cell.addressLabel?.text = job.address
cell.phoneLabel?.text = job.phone
cell.emailLabel?.text = job.email

Swift: app crashes after deleting a column in Parse

In Parse I accidentally deleted a column called "likes" that counts the number of a likes a user receives for their blog post. I created the column again with the same name but now when I run my app it crashes and I receive this message "unexpectedly found nil while unwrapping an Optional value". It points to my code where its suppose to receive the "likes" in my cellForRowAtIndexPath. I pasted my code below. Is there any way I could fix this issue and stop it from crashing?
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath?) -> PFTableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("BCell", forIndexPath: indexPath!) as! BlogCell
if let object : PFObject = self.blogPosts.objectAtIndex(indexPath!.row) as? PFObject {
cell.author.text = object["blogger"] as? String
cell.post.text = object["blogPost"] as? String
let dateUpdated = object.createdAt! as NSDate
let dateFormat = NSDateFormatter()
dateFormat.dateFormat = "h:mm a"
cell.timer.text = NSString(format: "%#", dateFormat.stringFromDate(dateUpdated)) as String
let like = object[("likes")] as! Int
cell.likeTracker.text = "\(like)"
}
return cell
}
I would inspect what's going on with the object if I were you. You clearly aren't getting data that you expected to be there. As a stopgap, you can change let like = object["likes"] as! Int to
if let like = object["likes"] as? Int {
cell.likeTracker.text = "\(like)"
}
If you do that, you will also want to implement the prepareForReuse method in BlogCell to set that label's text to nil or else you might have some weird cell reuse bugs.
Where you delete a column from uitableview , you need to delete data from data source, and update the delete index or reload the whole table .
Look for if you are missing that step

Realm date-query

In my RealmSwift (0.92.3) under Xcode6.3, how would I
// the Realm Object Definition
import RealmSwift
class NameEntry: Object {
dynamic var player = ""
dynamic var gameCompleted = false
dynamic var nrOfFinishedGames = 0
dynamic var date = NSDate()
}
The current tableView finds the number of objects (i.e. currently all objects) like follows:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let cnt = RLM_array?.objects(NameEntry).count {
return Int(cnt)
}
else {
return 0
}
}
First question: How would I find the number of objects that have a date-entry after, let's say, the date of 15.06.2014 ?? (i.e. date-query above a particular date from a RealmSwift-Object - how does that work ?). Or in other words, how would the above method find the number of objects with the needed date-range ??
The successful filling of all Realm-Objects into a tableView looks as follows:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("NameCell") as! PlayersCustomTableViewCell
if let arry = RLM_array {
let entry = arry.objects(NameEntry)[indexPath.row] as NameEntry
cell.playerLabel.text = entry.player
cell.accessoryType = entry.gameCompleted ? .None : .None
return cell
}
else {
cell.textLabel!.text = ""
cell.accessoryType = .None
return cell
}
}
Second question: How would I fill into the tableView only the RealmSwift-Objects that have a particular date (i.e. for example filling only the objects that have again the date above 15.06.2014). Or in other words, how would the above method only fill into the tableView the objects with the needed date-range ??
You can query Realm with dates.
If you want to get objects after a date, use greater-than (>), for dates before, use less-than (<).
Using a predicate with a specific NSDate object will do what you want:
let realm = Realm()
let predicate = NSPredicate(format: "date > %#", specificNSDate)
let results = realm.objects(NameEntry).filter(predicate)
Question 1: For the number of objects, just call count: results.count
Question 2: results is an array of NameEntrys after specificNSDate, get the object at indexPath. Example, let nameEntry = results[indexPath.row]
For creating a specific NSDate object, try this answer: How do I create an NSDate for a specific date?

Resources