Parse.com Query Not Loading - ios

I'm creating an app with displays parse data in a table view. I downloaded a template from https://github.com/Bizzi-Body/HowToDisplayImagesInTableViewFromParse it all worked fine when I ran it but when I put my Parse app id in and Client id it just shows a loading screen (see Screenshot)
So I thought it might be a problem with the app template so downloaded a different one and edited it, but the same problem happen, so I'm think its something wrong with my parse account settings.
import UIKit
class TableViewController: PFQueryTableViewController {
// Initialise the PFQueryTable tableview
override init!(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Configure the PFQueryTableView
self.parseClassName = "Photo"
self.textKey = "updatedAt"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
// Define the query that will provide the data for the table view
override func queryForTable() -> PFQuery! {
var query = PFQuery(className: "Photo")
query.orderByAscending("updatedAt")
return query
}
//override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject) -> PFTableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as CustomCell!
if cell == nil {
cell = CustomCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
// Extract values from the PFObject to display in the table cell
cell.username.text = object["user"] as String!
cell.itemdetail.text = object["description"] as String!
cell.price.text = object["Price"] as String!
var thumbnail = object["Image"] as PFFile
var initialThumbnail = UIImage(named: "question")
cell.productimage.image = initialThumbnail
cell.productimage.file = thumbnail
cell.productimage.loadInBackground()
return cell
}
}

If you enabled Parse LocalDatastore a quite similar issue is here:
https://github.com/ParsePlatform/ParseUI-iOS/issues/26
So try to disable LocalDatastore or update ParseSDK

I think the problem is that the Custom Cell class name does not match the Custom Cell Class detailed in the story board.
If your custom cell class is called "CustomCell" (i.e. - in "CustomCell.swift") you need to make sure that in the story board the custom class setting for the prototype cell is also "CustomCell".
Maybe this changed when you created your one custom class/cell

Related

Removing views from superview in cell

I have a cell class 'NewsCell' (subclass of UITableViewCell) that I use for two different kinds of news: OrganizationNews and ProjectNews. These news has common things, but some of elements are different. Namely, when my cell is used for ProjectNews I want to hide Organization's logo, when it is for OrganizationNews I want to hide Project's name button.
I have 'configureCell(_, forNews, ofProject)' method. I call it in 'NewsViewController'. I used 'removeFromSuperview' method, because I need to rearrange my elements in 'NewsCell'. Changing 'isHidden' value won't give me that effect.
So, that is the issue. I have 'Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value' exception in the lines projectNameButton.removeFromSuperview() or logoImageView.removeFromSuperview().
What should I do?
// NewsViewController.swift
func configureCell(_ cell: NewsCell, forNews news: News, ofProject project: Project? = nil) {
//...
if news is OrganizationNews {
cell.projectNameButton.removeFromSuperview()
} else if news is ProjectNews {
cell.logoImageView.removeFromSuperview()
}
// ...
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let news = newsCollection[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.newsCell, for: indexPath) as! NewsCell
configureCell(cell, forNews: news)
cell.delegate = self
return cell
}
A UITableView or UICollectionView are built on the reuse concept, where the cells are reused and repopulated when you work on it.
When you try to call dequeReusableCell(withIdentifier:), it sometimes returns something that is created before. So, suppose you dequed before something which had all controls, then removed one (removeFromSuperview), then tried to deque again, the new dequed one may NOT have the subview.
I think the best solution for you is making two different cells.
Example:
class BaseNewsCell: UITableViewCell {
// Put the common views here
}
class OrganizationNewsCell: BaseNewsCell {
// Put here things that are ONLY for OrganizationNewsCell
}
class ProjectNewsCell: BaseNewsCell {
// Put here things that are ONLY for ProjectNewsCell
}
Then deque them from 2 different identifier by two different storyboard cells, xibs.
Or
class BaseNewsCell: UITableViewCell {
// Put the common views here
}
class OrganizationNewsCell: BaseNewsCell {
// This happens when this kind of cell is created for the first time
override func awakeFromNib() {
super.awakeFromNib()
someNonCommon.removeFromSuperview()
}
}
class ProjectNewsCell: BaseNewsCell {
override func awakeFromNib() {
super.awakeFromNib()
someOtherNonCommon.removeFromSuperview()
}
}
Note: This violates Liskov's principle (one of the SOLID principles), because you remove functionality from superclass in the subclass.
Change the removing lines as below,
if news is OrganizationNews {
cell.projectNameButton?.removeFromSuperview()
} else if news is ProjectNews {
cell.logoImageView?.removeFromSuperview()
}
This will fix the issue. But a good approach would be to create separate classes for each cell. You can create a base class to keep common logic there.
You shouldn't remove the subview from the outside of the cell. Let's refactor your code.
NewsCell.swift
final class NewsCell: UITableViewCell {
enum Kind {
case organization
case project
}
var logoImageView: UIImageView?
let nameLabel = UILabel()
var kind: NewsCell.Kind {
didSet {
if kind != oldValue {
setupLogoImageView()
self.setNeedsLayout()
}
}
}
init(kind: NewsCell.Kind, reuseIdentifier: String?) {
self.kind = kind
super.init(style: .default, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - Positioning
extension NewsCell {
override func layoutSubviews() {
super.layoutSubviews()
// Your layouting
switch kind {
case .organization:
// Setup frame for organization typed NewsCell
case .project:
// Setup frame for project typed NewsCell
}
}
}
// MARK: - Setup
extension NewsCell {
private func setupLogoImageView() {
logoImageView = kind == .organization ? UIImageView() : nil
}
}
How to use:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let news = newsCollection[indexPath.row]
var cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.newsCell) as? NewsCell
if cell == nil {
cell = NewsCell(kind: .organization, reuseIdentifier: TableViewCellIdentifiers.newsCell)
}
cell!.kind = news is Organization ? .organization: .project
return cell!
}

swift - rendering table view is slow

I'm have a table view and I'm using the tableView.dequeueReusableCellWithIdentifier to reuse the cells but still tableView is very slow.
and by slow, I mean it takes about 500 milliseconds to put 9 of my views in the tableView. and it's tested on apple A7 X64 processor so it must be pretty slower on older processors.
the reason that it's slow is because there are a few sub views and constraints.
but I've seen more complex tableCells with better performance, so there must be something I can do.
like caching a cell or something else??
any ideas?
sample code
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
tableView.registerNib(UINib(nibName: "ChatCell", bundle: nil), forCellReuseIdentifier: "ChatCell")
let cell = tableView.dequeueReusableCellWithIdentifier("ChatCell") as! ChatCell
return cell
}
the reason that it's slow is because there are a few sub views and constraints.
Personally, I don't suggest you use constraints in cell, especially when there're many subviews, it'll cost much CPU time and lead the scrolling lag. Instead, you can calculate manually based on cell frame.
And for more suggestion, i suggest you take time to read this post: Simple Strategies for Smooth Animation on the iPhone.
The call to registerNib is normally done only once in viewDidLoad, not every time you are asked for a cell in cellForRowAtIndexPath. Not sure how slow that call is, but it might be the reason for your slow response.
I think you are using effects (like shadow or round corners or etc) or having heavy calculations on UI
Edit: Code Sample added
//Add in your init func
tblView.registerClass(MSCustomVerticalListCell.self, forCellReuseIdentifier: NSStringFromClass(MSCustomVerticalListCell))
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tblView.dequeueReusableCellWithIdentifier(NSStringFromClass(MSCustomVerticalListCell), forIndexPath: indexPath) as! MSCustomVerticalListCell
//add data binding
cell.item = dataSource[indexPath.row]
return cell
}
Your data binding class (Data Model):
class MSC_VCItem
{
var Title:String!
var Action:String!
var SubTitle:String!
var Icon:String!
init(title:String!,subTitle:String!,icon:String!,action:String!)
{
self.Title = title
self.SubTitle = subTitle
self.Icon = icon
self.Action = action
}
}
And Finally you custom table cell:
class MSCustomVerticalListCell : UITableViewCell {
let padding = 5
let imageWidth = 50
var customImageView: UIImageView!
var customTitleLabel: UILabel!
var customSubtitleLabel: UILabel!
var item: MSC_VCItem? {
didSet {
if let it = item {
customTitleLabel.text = it.Title
customSubtitleLabel.text = it.SubTitle
UIImage.loadFromCacheOrURL(it.Icon, callback: { (image: UIImage) -> () in
self.customImageView.image = image
})
setNeedsLayout()
}
}
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.backgroundColor = UIColor.clearColor()
customTitleLabel = UILabel(frame: CGRectZero)
self.addSubview(customTitleLabel)
customSubtitleLabel = UILabel(frame: CGRectZero)
contentView.addSubview(customSubtitleLabel)
customImageView = UIImageView(frame: CGRectZero)
customImageView.image = UIImage(named: "default")
contentView.addSubview(customImageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
//Write your UI here like bg color or text color
}
}

Swift/Parse: Elements in table view cell with nil value displaying values from other cells

My project has a table view (specifically a PFQueryTableView as I'm using Parse for my backend), which displays either text or a picture (in addition to some standard elements like the poster's profile picture and name). Think of this as a Facebook-like feed where posts can either contain text or an image. This means that in my "Yell" class (posts), either the "yellText" (text in post) or the "pictureFromCamera" (picture in post) value will be nil. These are loaded into a custom table view cell (prototype cell) containing a label for the text, and a PFImageView for the images. This allows me to change the formatting of the cell using if/else statements depending on whether or not the "postText" or the "postImage" for the given cell is nil. This works when I open the view controller, and it looks like this:
When I use the pull to refresh function, the images are placed in cells in which they are not meant to be:
And this is what the my object looks like in Parse:
My code for the container view containing the PFQueryTableView is as follows:
class YellContentTableViewController: PFQueryTableViewController {
var posterFirstName: String!
var hasUpvoted: Bool?
// Initialise the PFQueryTable tableview
override init(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Configure the PFQueryTableView
self.parseClassName = "Yell"
self.textKey = "yellText"
self.pullToRefreshEnabled = true
self.paginationEnabled = true
if (self.paginationEnabled == true){
self.objectsPerPage = 20
}
}
// Define the query that will provide the data for the table view
override func queryForTable() -> PFQuery {
var query = PFQuery(className: "Yell")
query.orderByDescending("createdAt")
return query
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomTableViewCell!
if cell == nil {
cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CustomCell")
}
if let posterFirstName = object?["posterFirstName"] as? String {
cell.customPosterFirstName.text = posterFirstName
}
//Display poster's profile picture
var initialThumbnail = UIImage(named: "Temporary")
cell.customPosterProfilePicture.image = initialThumbnail
if let thumbnail = object?["posterProfilePicture"] as? PFFile {
cell.customPosterProfilePicture.file = thumbnail
cell.customPosterProfilePicture.loadInBackground()
}
if let score = object?.valueForKey("voteCount") as? Int {
cell.yellVotes.text = "\(score)"
}
let yellText = object?["yellText"] as? String
if (yellText == "a"){
cell.customYellText.text = ""
var pictureFromCamera = object?["pictureFromCamera"] as? PFFile
tableView.rowHeight = 90
cell.customPictureFromCamera.file = pictureFromCamera
cell.customPictureFromCamera.loadInBackground()
}
if (yellText != "a"){
tableView.rowHeight = 60
if let yellText = object?["yellText"] as? String {
cell.customYellText.text = yellText
cell.customPictureFromCamera.file = nil
}
}
return cell
}
And for the prototype cell:
class CustomTableViewCell: PFTableViewCell {
#IBOutlet weak var customPictureFromCamera: PFImageView!
#IBOutlet weak var customYellText: UILabel!
#IBOutlet weak var customPosterFirstName: UILabel!
#IBOutlet weak var customPosterProfilePicture: PFImageView!
These outlets are connected to imageViews and labels in a prototype cell in the storyboard.
As you may notice, the determinant of whether or not the CustomTableViewCell is formatted as being a picture cell or a text cell is an if/else statement regarding whether or not yellText == A. At first this was based on an if/else statement regarding if customPictureFromCamera == nil. When I did that however, yellTexts from other cells would be entered into picture cells (where the yellText element in the Parse object is undefined/nil). My quick and dirty solution to this was to set yellText as "a" for all picture posts ("Yells"), set the if/else statement to depend of if yellText == "a", and if yes, set yellText = "" so that no text shows in the picture cells. This works, but is obviously not an elegant solution. I considered a similar approach for my picture issue (uploading a small file to the pictureFromCamera element in the Parse object so that it is no longer set to undefined/nil), but it would be terribly inefficient, so I'm hoping to find a better solution.
So, does anyone have any idea as to why refreshing the PFQueryTableView leads nil values for a given cell being replaced by values from other cells?
One way to solve the problem is to implement func prepareForReuse() in your table cell class such that it resets all elements of the cell to reasonable values. That way, you can be sure that each cell is cleared out before it's reused, so old values won't show up.
Another option is to ensure that you set every element of the cell in your tableView(_ tableView:,cellForRowAtIndexPath:) method. This is reasonable if you're not using a custom cell class, for example.

Passing objectId via prepareForSegue using Parse PFQueryTableViewController

This is very likely a simple answer. I am using PFQueryTableViewController to populate a table view. I want to pass the Parse objectId of the current row to my crDetailViewController but can't figure out how. The variable I'm trying to pass is called critterId.
I've updated my code to reflect Race B's #race-b suggestion below and it enables the build to succeed but I get a breakpoint error when I select an actual cell it creates a breakpoint. When I look at the debug code it shows a value of nil for the object, so it's not getting passed somehow since by definition there's an entity selected, otherwise how would the cell be selectable in the first place? Thanks for help!
import UIKit
class crTableViewController: PFQueryTableViewController {
// Initialise the PFQueryTable tableview
override init!(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Configure the PFQueryTableView
self.parseClassName = "CritterType"
self.textKey = "Name"
self.imageKey = "mainPhoto"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
// Define the query that will provide the data for the table view
override func queryForTable() -> PFQuery! {
var query = PFQuery(className: "CritterType")
return query
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 65
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("crDetailSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue,
sender: AnyObject?) {
if segue.identifier == "crDetailSegue" {
let detailViewController = segue.destinationViewController
as! crDetailViewController
let myIndexPath = self.tableView.indexPathForSelectedRow()
let row = myIndexPath!.row
println(row)
println(myIndexPath)
detailViewController.critterId = self.objectAtIndexPath(myIndexPath)
}
}
}
There should be an objectAtIndexPath that you can use that will return the object at whatever indexPath.row that you want.
Parse puts the data into an array called objects so to pass the object instead of the ID use the following code:
detailViewController.critter = self.objects[indexPath.row]

UILabels not updating in custom prototype cell of UITableViewController

Have tried several variations and watched different tutorials but cannot get my custom prototype cell to change from the defaulted text "label" in my tableviewcontroller. I have defined these labels as IBOutlets in the custom prototype file which is appropriately linked. I'm sure I missing something elementary here. Any thoughts?
import UIKit; import Parse
class UserRecordsTableViewController: PFQueryTableViewController {
// Initialise the PFQueryTable tableview
override init!(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Configure the PFQueryTableView
self.parseClassName = "Event"
self.textKey = "category"
self.textKey = "duration"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
// Define the query that will provide the data for the table view
override func queryForTable() -> PFQuery! {
var query = PFQuery(className: "event")
query.orderByAscending("category")
return query
}
//override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject) -> PFTableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as UserRecordsTableViewCell!
if cell == nil {
cell = UserRecordsTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
// Extract values from the PFObject to display in the table cell
cell.durationEventLabel.text = object["duration"] as? String
// Date for cell subtitle
return cell
}
}
Here is my cell:
import UIkit
class UserRecordsTableViewCell: PFTableViewCell {
#IBOutlet weak var dateEventLabel: UILabel!
#IBOutlet weak var catEventLabel: UILabel!
#IBOutlet weak var durationEventLabel: UILabel!
}
And under class in IB I have selected UserRecordsTableViewCell.
I have decided the best approach to my desired look is to go with PFTableViewCell provided by parse framework and simply only show two items. Main category and date as subtitle. This is opposed to creating a custom cell which works well with text and image label but not well with two text keys. Followed this tutorial and was great:
https://medium.com/swift-programming/ios-swift-parse-com-tutorial-set-up-xcode-project-part-2-of-3-31a17d1c6581

Resources