Each Cell need to have a Section - Parse and Swift - ios

I'm implementing a Feed on my App using Parse.com, basically I'm populating a UITableViewController and everything works fine, BUT, I really like the way Instagram does, seems like the Instagram have a UIView inside each cell that works like a header and that view follows the scroll till the end of cell, I tried to search about that and I'm not successful, after some research I've realized that this feature is equally a Section, so I decide to implement Sections in my querys, I've implemented the code below:
import UIKit
class FeedTableViewController: PFQueryTableViewController {
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loadCollectionViewData()
}
func loadCollectionViewData() {
// Build a parse query object
let query = PFQuery(className:"Feed")
// Check to see if there is a search term
// Fetch data from the parse platform
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
// The find succeeded now rocess the found objects into the countries array
if error == nil {
print(objects!.count)
// reload our data into the collection view
} else {
// Log details of the failure
}
}
}
// 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 = "Feed"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return objects!.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section \(section)"
}
//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! FeedTableViewCell!
if cell == nil {
cell = FeedTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
cell.anuncerPhoto.layer.cornerRadius = cell.anuncerPhoto.frame.size.width / 2
cell.anuncerPhoto.clipsToBounds = true
// Extract values from the PFObject to display in the table cell
if let nameEnglish = object?["name"] as? String {
cell?.title?.text = nameEnglish
}
let thumbnail = object?["Photo"] as! PFFile
let initialThumbnail = UIImage(named: "loadingImage")
cell.photoImage.image = initialThumbnail
cell.photoImage.file = thumbnail
cell.photoImage.loadInBackground()
return cell
}
}
Basically I will need to have a section for each cell, Now I'm successfully have sections working for each cell, but the problem is that the querys is repeating on the first post.
In the backend I have 3 different posts, so, in the App the UItableview need to have 3 posts with different content, with the code above I'm successfully counting the number of posts to know how many section I'll need to have and I declare that I want one post per section, but the app shows 3 sections with the same first post.
Any ideas if I'm capture the correct concept of the Instagram feature and why I'm facing this problem in my querys?
Thanks.

Keep the original UITableViewDataSource method and retrieve the current object using the indexPath.section
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! FeedTableViewCell!
if cell == nil {
cell = FeedTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
cell.anuncerPhoto.layer.cornerRadius = cell.anuncerPhoto.frame.size.width / 2
cell.anuncerPhoto.clipsToBounds = true
let object = objects[indexPath.section]
// Extract values from the PFObject to display in the table cell
if let nameEnglish = object["name"] as? String {
cell?.title?.text = nameEnglish
}
let thumbnail = object["Photo"] as! PFFile
let initialThumbnail = UIImage(named: "loadingImage")
cell.photoImage.image = initialThumbnail
cell.photoImage.file = thumbnail
cell.photoImage.loadInBackground()
return cell
}

Related

iOS Swift: Getting repeated value while updating 2D Array in custom UITableView cell

I have a 2D Array which I want to populate in UITableView Custom Cell in a specific pattern.
//Retrieved from Parse backend
var myArray = [["Name1", "Age1"],["Name2", "Age2"],["Name3", "Age3"]]
//What I need is:
nameArray = ["Name1", "Name2", "Name3"]
ageArray = ["Age1", "Age2", "Age3]
So that I can use indexPath to fill the Name data in the custom UITableView cell For Ex: nameArray[indexPath.row]
I tried using the for in loop,
var nameArray = NSMutableArray()
var ageArray = NSMutableArray()
//Inside CellForRowAtIndexPath
for data in myArray {
self.nameArray.addObject(data[0])
self.ageArray.addObject(data[1])
}
cell.nameLabel.text = "\(nameArray[indexPath.row])"
cell.ageLabel.text = "\(ageArray[indexPath.row])"
But I am getting repetitive name and age label filled with Name1 and Age1 in both the cell. Does anyone know whats wrong in this?
Is there a better way to reload this data as needed?
// UPDATED FULL WORKING CODE Thanks to #l00phole who helped me solve the problem
class NewViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var data = [[String]]()
var cost = Double()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
uploadData()
}
func uploadData() {
let query = PFQuery(className:"Booking")
query.getObjectInBackgroundWithId("X0aRnKMAM2") {
(orders: PFObject?, error: NSError?) -> Void in
if error == nil && orders != nil {
self.data = (orders?.objectForKey("orderDetails"))! as! [[String]]
//[["Vicky","21"],["Luke", "18"],["7253.58"]]
//*****Removing the last element as it is not needed in the tableView data
let count = self.data.count - 1
let c = self.data.removeAtIndex(count)
cost = Double(c[0])!
//******
} else {
print(error)
}
self.reloadTableData()
}
}
func reloadTableData()
{
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:NewTableViewCell = self.tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! NewTableViewCell
// Configure the cell...
cell.nameLabel.text = "\(data[indexPath.row][0])"
cell.ageLabel.text = "\(data[indexPath.row][1])"
return cell
}
You are adding to the nameArray and ageArray every time cellForRowAtIndexPath is called and you are not clearing them first. This seems inefficient and you should only populate those arrays when the input data changes, not when generating the cells.
I don't even think you need those arrays, as you could just do:
cell.nameLabel.text = "\(data[indexPath.row][0])"
cell.ageLabel.text = "\(data[indexPath.row][1])"
You don't have to create separate array for name and age, you can use the existing myArray as below
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:NewTableViewCell = self.tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! NewTableViewCell
// Configure the cell...
let dataArray = myArray[indexPath.row]
cell.nameLabel.text = "\(dataArray[0])"
cell.ageLabel.text = "\(dataArray[1])"
return cell
}
}

UITableView going out of view

i have a UITableView with multiple selection enabled with checkmarks. When i make selection that are all visible in the view, i don't run into any errors. However, if i scroll down further and place a selected item out of view, i get errors and even though the row stays selected, the checkmark goes away.
import Foundation
import Parse
import UIKit
class customerMenuVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var menuTV: UITableView!
var menuItems: [String] = ["Hello"]
var menuPrices: [Double] = [0.0]
var orderSelection: [String] = []
var priceSelection: [Double] = []
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return menuItems.count
}
func tableView(tableView: UITableView, numberOfColumnsInSection section: Int) -> Int
{
return 1;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell:UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "mycell")
cell.textLabel!.text = "\(menuItems[indexPath.row])\t $\(menuPrices[indexPath.row])"
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
//tableView.deselectRowAtIndexPath(indexPath, animated: true)
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell!.accessoryType = .Checkmark
orderSelection.append(cell!.textLabel!.text!)
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)
{
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell!.accessoryType = .None
}
override func viewDidLoad() {
super.viewDidLoad()
menuTV.allowsMultipleSelection = true
let resMenu = resUser.sharedInstance
var resName = resMenu.nameStr
var resID = resMenu.idStr
var menuQ = PFQuery(className: "menu")
menuQ.getObjectInBackgroundWithId(resID){
(menus: PFObject?, error: NSError?) -> Void in
if error == nil && menus != nil {
let items: [String] = menus?.objectForKey("menuItems") as! Array
let prices: [Double] = menus?.objectForKey("menuPrices") as! Array
self.menuItems = items
self.menuPrices = prices
self.menuTV.reloadData()
}
}
}
#IBAction func continueButton(sender: AnyObject) {
let selections = menuTV.indexPathsForSelectedRows() as! [NSIndexPath]
var indexCount = selections.count
println(indexCount)
var x = 0
while x < indexCount
{
println(x)
let currentCell = menuTV.cellForRowAtIndexPath(selections[x]) as? UITableViewCell?;
println(x)
println(selections[x].row.description)
orderSelection.append(currentCell!!.textLabel!.text!)
println(orderSelection[x])
x++
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
This is how table views work.
When a cells scrolls off-screen, it gets tossed into the recycle queue and then used again to display data for a different indexPath in your data.
Any time the user makes any changes to the data for a cell you should save it to your data model (usually an array of information, or maybe an array of arrays if you're using a sectioned table view.) Then you should tell the table view to redisplay the changed cell. The cellForRowAtIndexPath method picks up the changed data and shows the changes to the cell. If the cell scrolls off-screen and then scrolls back on-screen, it gets displayed with the correct settings.
This applies to keeping track of which cells are selected as well.

Trying to display data on a UITableView from parse

I'm trying to display data from parse onto a UITableView but it's only displaying a blank UITableView (no data being shown)
I have a University class in parse, as well as a universityEnrolledName column name
here is the code
import UIKit
import Parse
import ParseUI
class viewUniversityList: PFQueryTableViewController {
#IBOutlet var uiTableView: UITableView!
override init(style: UITableViewStyle, className: String!){
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
self.parseClassName = "University"
self.textKey = "universityEnrolledName"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
override func queryForTable() -> PFQuery {
var query = PFQuery(className: "University")
query.orderByAscending("universityEnrolledName")
return query;
}
override func viewDidLoad() {
super.viewDidLoad()
uiTableView.delegate = self
uiTableView.dataSource = self
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 0
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! PFTableViewCell!
if cell == nil {
cell = PFTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
if let universityEnrolledName = object?["universityEnrolledName"] as? String{
cell?.textLabel?.text = universityEnrolledName
}
if let classEnrolledName = object?["classEnrolledName"] as? String{
cell?.detailTextLabel?.text = classEnrolledName
}
return cell;
}
/*
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
// Delete the row from the data source
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} else if editingStyle == .Insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the item to be re-orderable.
return true
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
}
does anyone have any advice on displaying the universityEnrolledName data from the University class (from Parse)? Thanks!
Here,
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return 0
}
This method is used to display number rows in a tableview. Since you are returning 0, which means you are telling to your table view that your table should have zero row's.
Similarly
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 0
}
By default table view have one section, if you are explicitly providing some value it will be overridden.
So in both case you should return some positive number greater than zero.
The below method should return UITableViewCell, but you wrote PFTableViewCell. So change it.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! PFTableViewCell!
if cell == nil {
cell = PFTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
if let universityEnrolledName = object?["universityEnrolledName"] as? String{
cell?.textLabel?.text = universityEnrolledName
}
if let classEnrolledName = object?["classEnrolledName"] as? String{
cell?.detailTextLabel?.text = classEnrolledName
}
return cell;
}
override func viewDidLoad() {
super.viewDidLoad()
//Conform to the TableView Delegate and DataSource protocols
uiTableView.delegate = self //set delegate
uiTableView.dataSource = self // set datasource
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 0 //set count of section
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0 //set count of rows
}
Refere this:
how-to-make-a-simple-table-view-with-ios-8-and-swift
This might helps you :)
I don't write swift so forgive any syntax issues, but I expect you want something more like:
import UIKit
import Parse
import ParseUI
class viewUniversityList: PFQueryTableViewController {
#IBOutlet var uiTableView: UITableView!
override init(style: UITableViewStyle, className: String!){
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
self.parseClassName = "University"
self.textKey = "universityEnrolledName"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
override func viewDidLoad() {
super.viewDidLoad()
uiTableView.delegate = self
uiTableView.dataSource = self
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func queryForTable() -> PFQuery {
var query = PFQuery(className: "University")
query.orderByAscending("universityEnrolledName")
return query;
}
override func textKey() -> NSString {
return "universityEnrolledName"
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell {
var cell = super.tableView(tableView, dequeueReusableCellWithIdentifier:indexPath, object:object) as! PFTableViewCell!
if let classEnrolledName = object?["classEnrolledName"] as? String{
cell?.detailTextLabel?.text = classEnrolledName
}
return cell;
}

Swift index 0 beyond bounds for empty array in tableview

I'm trying to populate tableview with parse with 2 labels connected to the the main tv controller with PFTableViewCell
when I add the (numberOfSectionsInTableView + numberOfRowsInSection ) the app crash
but when I deleted it it works but it show nothing.
This the table view cell
class courseCell: PFTableViewCell {
#IBOutlet var name: UILabel!
#IBOutlet var location: UILabel!
}
This the table view controller
class courseTVC: PFQueryTableViewController {
override init!(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder:NSCoder)
{
super.init(coder:aDecoder)
self.parseClassName = "courses"
self.textKey = "Location"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
override func queryForTable() -> PFQuery! {
var query = PFQuery(className: "courses")
query.orderByDescending("Location")
return query
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!, object: PFObject!) -> PFTableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell" , forIndexPath : indexPath) as? courseCell
if cell == nil
{
cell = courseCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
}
cell!.name.text = object["Price"] as! String!
cell!.location.text = object["Location"] as! String!
return cell!
}
I don't know how to fix this issue
Looking at the documentation for PFQueryTableViewController, https://www.parse.com/docs/ios/api/Classes/PFQueryTableViewController.html it looks like you shouldn't be overriding those two methods.
– tableView:cellForRowAtIndexPath:object: should be called already for all the rows in your table based on your objects. You shouldn't override numberOfSectionsInTableView and numberOfRowsInSection because the Parse controller handles all of that for you. You are overriding these methods and hardcoding a number which causes Parse to try to fetch and object for a row that is out of bounds (it doesn't exist). It looks like there are actually no objects in your datasource.

Value's from plist to tableView

I'm trying to use a plist to fill my tableView. I've currently written this code. I'm not having any errors and I can run the app fine. The problem is the tableview remains empty. My println returns all the value's from my plist tho. If I request them outside my viewDidLoad function nothing comes up tho. Any idea what I'm doing wrong? Sorry for asking an almost similar question as my previous one. It's just that I'm trying to teach myself a new language.
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var artists: Array<String> = []
var stages: Array<String> = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let path = NSBundle.mainBundle().pathForResource("TableRowInfo", ofType: "plist")!
let dict = NSDictionary(contentsOfFile:path)!
artists = dict["Artist"] as Array<String>
stages = dict["Stage"] as Array<String>
println(artists)
println(stages)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return artists.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("InfoCell", forIndexPath: indexPath) as? UITableViewCell
if cell == nil {
cell = UITableViewCell(style: .Subtitle, reuseIdentifier: "InfoCell")
cell!.accessoryType = .DisclosureIndicator
}
cell?.textLabel?.text = artists[indexPath.row]
cell?.detailTextLabel?.text = stages[indexPath.row]
return cell!
}
}
Thanks in advance.

Resources