I am trying to reload my table view using
self.tableView.reloadData()
It works properly if I'm loading static datasource using array. Everything work properly.
But when I try to use my query function with parse, it loads a new cell but the contents of the tableview cell doesn't change. If I re-open the app, the cells will update properly.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "EmpPostTVCellIdentifier"
let cell: EmpPostTVCell? = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as? EmpPostTVCell
//If datasource
if dataSource.isEmpty{
fetchDataFromParse()
print("no posts")
}
let itemArr:PFObject = self.dataSource[indexPath.row]
cell?.companyPostLabel.text = (PFUser.currentUser()?.objectForKey("companyName")!.capitalizedString)! as String
cell?.occupationPostLabel.text = itemArr["occupation"]!.capitalizedString as String
cell?.countryPostLabel.text = itemArr["country"]!.capitalizedString as String
let companyImage: PFFile?
companyImage = PFUser.currentUser()?.objectForKey("profileImageEmployer") as? PFFile
companyImage?.getDataInBackgroundWithBlock({ (data, error) -> Void in
if error == nil{
cell?.companyLogoImage.image = UIImage(data: data!)
}
})
let dateArr = createdByDate[indexPath.row]
let strDate = Settings.dateFormatter(dateArr)
cell?.closingDateLabel .text = strDate
return cell!
}
I am using pull to refresh my tableviews contents using this code
func refresh(sender:AnyObject)
{
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.fetchDataFromParse()
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
})
}
with or without the dispatch_asynch function the results remains the same. It just add new tableviewcell but the contents in it does not change. Any ideas guys?
edit 1 :
func fetchDataFromParse() {
// MARK: - JOB POST QUERY
if PFUser.currentUser()?.objectId == nil{
PFUser.currentUser()?.saveInBackgroundWithBlock({ (success, error) -> Void in
let query = PFQuery(className: "JobPost")
//creating a pointer
let userPointer = PFUser.objectWithoutDataWithObjectId(PFUser.currentUser()?.objectId)
query.whereKey("postedBy", equalTo: userPointer)
query.orderByDescending("createdAt")
let objects = query.findObjects()
for object in (objects as? [PFObject])!{
//print(object.objectId)
self.dataSource.append(object)
self.createdByDate.append((object.objectForKey("closingDate") as? NSDate)!)
print(self.dataSource)
print(self.createdByDate)
}
})
} else {
let query = PFQuery(className: "JobPost")
//creating a pointer
let userPointer = PFUser.objectWithoutDataWithObjectId(PFUser.currentUser()?.objectId)
query.whereKey("postedBy", equalTo: userPointer)
query.orderByDescending("createdAt")
let objects = query.findObjects()
for object in (objects as? [PFObject])!{
//print(object.objectId)
self.dataSource.append(object)
self.createdByDate.append((object.objectForKey("closingDate") as? NSDate)!)
print(self.dataSource)
print(self.createdByDate)
}
}//end of PFUser objectID == nil else clause
}
Let's see the content of the fetchDataFromParse() function where I presume you're filling the self.dataSource array
Try to call self.tableview.reloadData() when fetchDataFromParse() is finished.
Check whether your dataSource array is empty at the end of your fetchDataFromParse method
PFUser.currentUser()?.saveInBackgroundWithBlock is an asynchronus method. So your tableView cell is having no data.
Related
I have an issue where if a user types into the search bar too fast the program will crash with the following message
fatal error: index out of range
referring to the line var podInfo = podcastResults[row] which is part of the cellForRowAtIndexPath method. The search box is above a UITableView which is populated from the NSURLSession results.
Please see the code below.
class SearchTVC: UITableViewController, UISearchBarDelegate {
#IBOutlet weak var searchBar: UISearchBar!
var podcastResults = [[String: String]]()
var tempDict = [String: String]()
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
print("search being typed")
if searchText.characters.count >= 3 {
let searchesArray:Array = searchText.componentsSeparatedByString(" ")
//request search method to start
search(searchesArray)
}
}
func search(searchqueries: Array<String>){
let URL = iTunesSearcher().searchQuery(searchqueries) //This just complies the URL using a method in anothr class
let task = NSURLSession.sharedSession().dataTaskWithURL(URL) {
(data, response, error) in
print("URL downloaded")
//clear results and temp dict, so that new results can be displayed
self.tempDict.removeAll()
self.podcastResults.removeAll()
let data = NSData(contentsOfURL: URL) //urlString!
let json = JSON(data: data!)
for (key, subJson) in json["results"] {
if let title = subJson["collectionCensoredName"].string {
self.tempDict = ["title": title]
} else { print("JSON - no title found") }
if let feedURL = subJson["feedUrl"].string {
self.tempDict.updateValue(feedURL, forKey: "feedURL")
} else { print("JSON - no feedURL found") }
if let artworkUrl60 = subJson["artworkUrl60"].string {
self.tempDict.updateValue(artworkUrl60, forKey:"artworkURL60")
} else { print("JSON - no artwork url found") }
self.podcastResults.append(self.tempDict)
}
//Running request on main thread
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
}
task.resume()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath)
let row = indexPath.row
var podInfo = podcastResults[row]
cell.textLabel?.text = podInfo["title"]
return cell
}
Any help would be much appreciated as I just can't figure it out.
Cheers.
Michael
I'm assuming that the number of rows you return in your UITableViewDataSource is self.podcastResults.count.
If so, what you need to do is turn this:
let row = indexPath.row
var podInfo = podcastResults[row]
cell.textLabel?.text = podInfo["title"]
into
let row = indexPath.row
if row < podcastResults.count {
var podInfo = podcastResults[row]
cell.textLabel?.text = podInfo["title"]
}
This will ensure that no matter when the cell is requested the index will never be out of bounds (and I think this happens after you remove all the elements from the array in the request handler).
Try reloading the table when you remove all the elements from your array ie. self.tempDict.removeAll()
self.podcastResults.removeAll() it seems that table is not refreshed and still shows the elements which are now actually removed.
Each cell in the cell loads and image and some text from parse.com
but when i'm scrolling it shows wrong image before the loaded image and wrong usernames. The timeago and messages works properly.
I have read about prepareForReuse() method but its not working.
Any ideas ?
UITableViewController:
let cell = tableView.dequeueReusableCellWithIdentifier("chatcell", forIndexPath: indexPath) as? PTATableViewCell
cell.delegate = self
cell.setPanGesture(.LeftToRight, mode: .Exit, color: UIColor.whiteColor(), view: viewWithImage(named: "infostart"))
cell.leftToRightAttr.triggerPercentage = 0.4
cell.leftToRightAttr.rubberbandBounce = false
cell.leftToRightAttr.viewBehavior = .DragWithPan
let targetObject = rooms[indexPath.row] as PFObject
let targetUser = users[indexPath.row] as PFUser
let mm = rooms[indexPath.row]
cell.mesaj.text = mm.objectForKey("Message") as! String
cell.timeAgo.text = "\(targetObject.updatedAt!.formattedAsTimeAgo())"
let userget = PFUser.query()
userget!.whereKey("objectId", equalTo: targetUser.objectId!)
userget!.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
if let fUser = objects!.last as? PFUser {
let namee = fUser.objectForKey("name") as! String
let agee = fUser.objectForKey("age") as! Int
cell.nameUser.text = "\(namee), \(agee)"
if let pica = fUser.objectForKey("dpSmall") as? PFFile {
pica.getDataInBackgroundWithBlock({ (data:NSData?, error:NSError?) -> Void in
if error == nil {
cell.userdp.image = UIImage(data: data!)
cell.userdp.layer.borderColor = colorText.CGColor
circleBorder(cell.userdp)
}
})
Customviewcell:
public override func prepareForReuse() {
super.prepareForReuse()
nameUser.text = "Loading..."
userdp.image = nil
timeAgo.text = nil
mesaj.text = nil
likedtext.text = nil
removeSwipingView()
stateOptions = .None
leftToRightAttr = PTATableViewItemStateAttributes()
rightToLeftAttr = PTATableViewItemStateAttributes()
}
Cells in the table view are reused. Since you're fetching the new image and usernames in the background, the previous contents of the cell (that is being reused) will be shown until the new content is fetched and replaced. Notice how the message and time ago is set on the cell synchronously (in this case, not inside the findObjectsInBackgroundWithBlock callback), which is why it works.
Seems like PFQuery has a method to cancel operation. https://parse.com/docs/ios/api/Classes/PFQuery.html#/c:objc(cs)PFQuery(im)cancel
Try this.
Define query as property of PTATableViewCell
let userget = PFQuery?
and cancel operation before doing another. Something like that:
if cell.userget != nil {
cell.userget.cancel()
}
cell.userget = PFUser.query()
cell.userget!.whereKey("objectId", equalTo: targetUser.objectId!)
...
I'm writing an app in Swift where the first scene has a TableView, I have it setup to display the title and it works fine, I also have it setup to count occurrences in a CloudKit database(or whatever its called) but it performs the count in async so the table defaults to show 0 in the detail pane.
I need to know how to make the app wait before it sets the value for the right detail until the count is completed or how to change them afterwards.
I have attached the code I used to perform the count etc, if I am doing this wrong or inefficiently please let me know
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.hidesBackButton = true;
self.textArray.addObject("Link 300")
self.textArray.addObject("Link 410")
self.textArray.addObject("Link 510")
let container = CKContainer.defaultContainer()
let publicData = container.publicCloudDatabase
let query = CKQuery(recordType: "Inventory", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
publicData.performQuery(query, inZoneWithID: nil){results, error in
if error == nil {
for res in results {
let record: CKRecord = res as! CKRecord
if(record.objectForKey(("TrackerModel")) as! String == "Link 300"){
self.count300 = self.count300++
}else if(record.objectForKey(("TrackerModel")) as! String == "Link 410"){
self.count410 = self.count410++
}else if(record.objectForKey(("TrackerModel")) as! String == "Link 510"){
self.count510 = self.count510++
}
}
}else{
println(error)
}
}
self.detailArray.addObject(self.count300.description)
self.detailArray.addObject(self.count410.description)
self.detailArray.addObject(self.count510.description)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.textArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->UITableViewCell {
var cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
cell.textLabel?.text = self.textArray.objectAtIndex(indexPath.row) as? String
cell.detailTextLabel?.text = self.detailArray.objectAtIndex(indexPath.row) as? String
return cell
}
Many thanks - Robbie
The closure associated with the performQuery will complete asynchronously - that is after viewDidLoad has finished. You need to make sure that you reload your table view once the query has completed and you have the data. You also have a problem because you are updating your totals outside the closure - this code will also execute before the data has loaded.
Finally, make sure that any update to the UI (such as reloading the table view) is dispatched on the main queue
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.hidesBackButton = true;
self.textArray.addObject("Link 300")
self.textArray.addObject("Link 410")
self.textArray.addObject("Link 510")
let container = CKContainer.defaultContainer()
let publicData = container.publicCloudDatabase
let query = CKQuery(recordType: "Inventory", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
publicData.performQuery(query, inZoneWithID: nil){results, error in
if error == nil {
for res in results {
let record: CKRecord = res as! CKRecord
if(record.objectForKey(("TrackerModel")) as! String == "Link 300"){
self.count300++
}else if(record.objectForKey(("TrackerModel")) as! String == "Link 410"){
self.count410++
}else if(record.objectForKey(("TrackerModel")) as! String == "Link 510"){
self.count510++
}
}
self.detailArray.addObject(self.count300.description)
self.detailArray.addObject(self.count410.description)
self.detailArray.addObject(self.count510.description)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
}else{
println(error)
}
}
}
I have a Parse query that returns a set of users (PFUsers). I place them in an array so that they can be used to populate a tableView. However, when I load the tableView I get the following error message: Could not cast value of type 'PFObject' to 'NSArray'. Here's the relevant code (I cut out some stuff to make it easier to read). It's heavily condensed but I can create a full gist of needed.
The error is caught on the line: self.realMatches = result as! [PFObject]
import UIKit
class MatchesViewController: BaseViewController {
var realMatches: [PFObject] = []
func loadMatches() {
if let user = self.user {
query{
(results: [AnyObject]?, error: NSError?) -> Void in
if error != nil {
println(error)
} else {
if results != nil {
self.matchesResults = results!
for result in results!{
if result.objectId != self.currentUser!.objectId {
self.realMatches = result as! [PFObject]
}
}
for result in results! {
self.user1 = result["user1"] as! PFUser
self.user2 = result["user2"] as! PFUser
}
self.tableView.reloadData()
}
}
}
} else {
println("current user doesnt exist")
}
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MatchCell", forIndexPath: indexPath) as! UITableViewCell
let object = matchesResults[indexPath.row]
return cell
How can I safely store the PFUsers in an array to be used for the tableView?
Thanks!!
result is a single PFObject that you have extracted from the array of results array using a for loop.
You should simply say
self.realMatches = result as! PFObject
but self.realMatches is an array, so that assignment won't work either. You can append the result to the array using
self.realMatches.append(result as! PFObject)
I am having issues setting with Parse data and a UITableView. Everytime I run the application, whether on the simulator or my phone, the app stops working and the only thing the console shows is (lldb). When checking the debugger, only following two lines of code are highlighted.
findTimelineData.findObjectsInBackgroundWithBlock{
and
self.timelineData = array as NSMutableArray
Both have the error: Thread 1: EXC_BREAKPOINT (code=EXC_I386_BPT,subcode=0x0) and im not quite sure what that means...
Here are snippets of my code:
override func viewDidAppear(animated: Bool)
{
self.loadData()
}
func loadData()
{
timelineData.removeAllObjects()
var findTimelineData : PFQuery = PFUser.query()
findTimelineData.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]!, error: NSError!)-> Void in
if error == nil
{
println("No error")
if let object = objects as? [PFObject!]
{
for object in objects
{
self.timelineData.addObject(object)
}
}
let array : NSArray = self.timelineData.reverseObjectEnumerator().allObjects
self.timelineData = array as NSMutableArray
self.tableView.reloadData()
}
}
}
and these would be the cells that i'm trying to load, but the code never gets this far...
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
println("loading cell")
let postCell : LocationTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as LocationTableViewCell
let post : PFObject = self.timelineData.objectAtIndex(indexPath.row) as PFObject
postCell.imageView.image = post.objectForKey("currentLocation") as? UIImage
postCell.userInfo.text = post.objectForKey("FirstLastName") as? String
// Configure the cell...
return postCell
}
for the full code: http://pastebin.com/MN7qcFhq
this worked for me:
in your code just only replace
self.timelineData = array as NSMutableArray
to
self.timelineData = NSMutableArray(array: array)
Aren't you missing an s in:
if let object = objects as? [PFObject!]
{
for object in objects
{
self.timelineData.addObject(object)
}
}
Should be:
if let objects = objects as? [PFObject!]
{
for object in objects
{
self.timelineData.addObject(object)
}
}
Hey Buddy I got you on this one. I had the same issues but I got help and got it figured out.
This is your Load Function
Try this
func loadData(){
timelineData.removeAll(keepCapacity: false)
var findTimelineData:PFQuery = PFQuery(className:"Sweets")
findTimelineData.findObjectsInBackgroundWithBlock
{
(objects:[AnyObject]! , error:NSError!) -> Void in
if error == nil
{
self.timelineData = objects.reverse() as [PFObject]
//let array:NSArray = self.timelineData.reverseObjectEnumerator().allObjects
println(objects)
// self.timelineData = array as NSMutableArray
self.tableView.reloadData()
}
}
}
Then go to your
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
And change
let sweet:PFObject = self.timelineData.objectAtIndex(indexPath.row) as PFObject
To This
let sweet: PFObject = self.timelineData[indexPath.row] as PFObject
Whats going on is you are mixing some Obj C with Swift , the code you are following was probably written in Beta so make sure you go back and learn the differences. If you are still having problems check all your conditions if(error != nil) should not be in your code.