Can't display custom cell with PFQueryTableViewController (Swift2) - ios

Using parse.com v1.4 (installed with cocoa pods) with Swift 2 +
I've setup up my PFQueryTableViewController (ParseUI) with a custom cell. I believe everything is hooked up fine, however I can't get the cell to display the value from Parse.com even though I do receive it and can print it (I've debugged it).
I am dequeueing like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! OrderTableViewCell
// Extract values from the PFObject to display in the table cell
if let pfObject = object {
// prints expected value, e.g. 1, 2, 3
print(pfObject["table"])
// shows "Label" which is my label's default text on the SB!!
let table = pfObject["table"] as? String
cell.lblTable.text = table
}
return cell
}
The rest of my PFQueryTableViewController which seems to load data OK from Parse:
My custom cell OrderTableViewCell (with some label IBActions):
SB set-up:
And the result:
How can I get the label to display the actual text? What am I missing? I don't want to revert back to standard UITableView due to the additional features I get with Parse UI.

turns out it was as simple as changing
let table = pfObject["table"] as? String
to
let table = String(pfObject["table"])

Related

Pre-loading custom UITableViewCells then having them be re-used in the tableview

I've seen solutions where there is a need to create all required heavyweight UITableViewCells prior to loading the tableview, which works when you have a relatively small number of rows. In that case, tableviewcells can be created before calling reloadData, stored in an array then used as required in the cellForRowAt method instead of using dequeueReusableCell
let cell = tableView.dequeueReusableCell(withIdentifier: "CustCell") as! CustomCell
However, for my app I can't create all required tableview cells since it could be 500 or more very heavy cells which would balloon the app's memory use.
The tableviewcells contain a WKWebview which loads a web page containing a large amount of Javascript code; loading isn't fast and and the tableviews will generate the cells so quickly that they will effectively attempt to web load at the same time, so that there's a heavy CPU price that can cause errors in loading. Ideally each of the tableview's cells needs to be prepared for use sequentially then added to the tableview.
I need to create the number of cells that this UITableView needs to be visible at any time (plus the few it uses in advance) and reuse them via dequeueReusableCell as the user scrolls.
Can I can pre-create the cells using a method as below then have those cells reused in the tableview? i.e. can I use dequeueReusableCell outside the context of the cellForRowAt method?
func setupCells () {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustCell") as! CustomCell
cell.delegate = self
cellArray.append(cell)
}
Thanks for any ideas
Yes you can initialize Cell outside UITableView Method
var arrVideoCell = [VideoTableViewCell]() //Intialize variable
//Intialization
fileprivate func getNewFeildCell() -> VideoTableViewCell
{
let cell = Bundle.main.loadNibNamed("VideoTableViewCell", owner: nil, options: nil)?.first as! CellName
let urlString = URL(string: "URL")
cell.viwVideo.loadVideoURL(urlString!)
return cell
}
//For Set data in method
func configureAudioData()
{
for _ in 0...4
{
let cell = getNewFeildCell()
arrVideoCell.append(cell)
}
self.tblAudioVideo.reloadData()
}
//Tableview Delegate, DataSource
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = arrVideoCell[indexPath.row]
return cell
}

Swift: Strange downcasting failure

I have a rather strange case of downcasting failure that I cannot understand.
I have almost identical code in two UITableViewControllers. ProjectTableViewController displays list of Project, and its datasource is [Project]. NewsfeedsTableViewController displays list of Newsfeed, but Newsfeed can contain different types of source data, including Project.
Depending on the type of the source data, each cell of NewsfeedsTableViewController is downcasted to appropriate subclass of UITableViewCell.
ProjectTableViewCell a subclass of UITableViewCell, and is used in both ProjectTableViewController and NewsfeedsTableViewController.
Now the interesting thing is, the code works without issue in ProjectTableViewController but crashes in NewsfeedsTableViewController, giving following error message:
Could not cast value of type 'UITableViewCell' (0x102e68128) to 'sample_app.ProjectTableViewCell' (0x1010ce6d0).
I have following codes in each class:
ProjectTableViewController.swift
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let project = projects[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("ProjectTableViewCell") as! ProjectTableViewCell
cell.projectTitle.text = project.title
cell.projectKeywords.text = project.keywords
return cell
}
NewsfeedsTableViewController.swift
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let newsfeed = self.newsfeeds[indexPath.row]
switch newsfeed.newsfeedableType {
case "Project":
let cell = tableView.dequeueReusableCellWithIdentifier("NewsfeedTableViewCell") as! ProjectTableViewCell
let source = newsfeed.newsfeedable as! Project
cell.projectTitle.text = source.title
cell.projectKeywords.text = source.keywords
return cell
default:
let cell = tableView.dequeueReusableCellWithIdentifier("NewsfeedTableViewCell")!
cell.textLabel!.text = newsfeed.newsfeedableType + String(newsfeed.id)
return cell
}
}
I would love to understand what's causing this issue.
The issue was solved by adding another prototype cell of ProjectTableViewCell to the NewsfeedsTableViewController, and using it to display Newsfeed with Project as source.
Which means I will have to add prototype cells for all the source data types, and then configure them on the storyboard. I'm not looking forward to doing that.
I thought I could duck-type through this all, but I guess Swift does not work like that.

How to display two cells each with different functionality in the same tableView simultaneously?

I have tableView.
I have tableViewCellOne. tableViewCellOne allows text input and image input by the user which gets saved in a database. This part works fine.
I want to build tableViewCellTwo. This cellTwo has a different function than cellOne. cellTwo will retrieve this data and display it.
I want both cells to be visible at the same time. tableViewCellOne above, and tableViewCellTwo below, on the same tableView. Here is the relevant portion of the code I wrote. The way that it works as of now, it only displays tableViewCellOne which is not my intent. This code is written in my TableViewController.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
if (indexPath.row == 0) {
let cellIdentifier = "MyTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! MyTableViewCell
// Fetches the appropriate data for the data source layout.
let data = myData[indexPath.row]
cell.MyData1.text = data.1
cell.MyData2.image = data.2
cell.MyData3.text = data.3
return cell
} else {
let cellIdentifier = "TheirDataTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! TheirDataTableViewCell
// Fetches the appropriate data for the data source layout.
let data = theirData[indexPath.row]
cell.TheirData1.text = data.1
cell.TheirData2.image = data.2
cell.TheirData3.text = data.3
return cell
}
}
With this if else statement, I am trying to say: when we are loading cell 1 then load the following data, when we are loading cell2 then load the following other data. But I think instead its interpreting it as: if (something) load cell1, if (something else) load cell2. I could be way off base with that diagnosis though.
How do I display two cells each with different functionality in the same tableView simultaneously?

Update Custom UITableViewCell UILabel after asynchronous Parse query

Can't think of a good name for the question...if you can think of a better one, please feel free to edit it :)
I am building an iOS app using Swift and Parse.com.
In my app, I have a main PFQueryTableViewController which loads some data from my Parse cloud into some custom UITableViewCells.
One of the values that I want for a label on the cells takes a while for Parse to return and so I am getting it using findObjectsInBackgroundWithBlock().
In my cellForRowAtIndexPath when I'm loading my table, I have the following code:
// Set cells for each row of table
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
var cell: CustomTableViewCell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! CustomTableViewCell
// Get Course Object objectID to hand to getCourseGrade function
var anObjectID: String = object!.objectId!
cell.setCell(name: object!["objectName"] as! String, code: object!["objectCode"] as! String, grade: getObjectGrade(anObjectID))
return cell
}
In the code above, I am calling a function called getObjectGrade to pass a value across to my setCell() function which sets up the customTableViewCells as it builds the UITableView which runs as below (simplified):
func getObjectGrade(objectIdString: String) -> Float {
// Set a starting value of objectGrade
var objectGrade: Float = -1
//...I set up a PFQuery
query?.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in
//...here I am retrive the value I need from Parse --> valueFromParse
objectGrade = valueFromParse
})
return objectGrade
}
NOW, I am VERY AWARE that this will NOT work...obviously the code does not wait for my findObjectsInBackgroundWithBlock() code to run and so returns the objectGrade before it has been updated.
MY QUESTION: How could I set the value of the label of my cell once the findObjectsInBackgroundWithBlock() code section DOES complete?
SOLVED! I moved the "getObjectGrade" function to my CustomTableViewCell file and called it from there. :) If anyone has this issue and needs help, just comment and i'll try :)

Overriding UITableView in Parse with Swift

All,
In swift while using Parse as my backend, I have created a class which inherits from PFQueryTableViewController. I see my data going into a tableview - thats fine.
I am trying to customise my cells a bit, and I overriding CellForRowAtIndexPath - like below :
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!, object: PFObject!) -> PFTableViewCell!
{
var cellIdentifier = "eventCell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? PFTableViewCell
if cell == nil {
cell = PFTableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: cellIdentifier)
}
// configure cell
var CellTitle = object.objectForKey("Title") as String
cell?.textLabel = CellTitle
}
}
As the object using comes back as [AnyObject] in swift, I have created a variable and I have casted it to a string. And then I am trying to show that string in Cell.textlabel.
I am getting the error : Cannot assign to the result of this expression.
Can anyone please show me the right direction on this.
I think the problem is that you're attempting to assign a String directly to cell?.textLabel UILabel. Instead try changing this line:
cell?.textLabel = CellTitle
to this
cell.textLabel?.text = CellTitle
so you're setting the text property of the UILabel instead.

Resources