trying to get from my UITableViewController to the detail view controller with these PFObjects...thanks in advance!
error i can't seem to reconcile..."Cannot subscript a value of type 'String' with an index of type 'String'"
I want the queried objects to present on the detail view controller...
here is my query and my prepare for segue...i can't seem to access the objects in the prepare for segue...
var customerName = [String]()
var customerAddress = [String]()
var query = Pfuser.query
query.whereKey("userId",equalTo:adminFollowingUser)
query.findObjectsInBackgroundWithBlock({ (adminObjects, error) -> Void in
if let objects = adminObjects {
for object in objects {
self.customerName.append(object["customerName"] as! String)
self.customerAddress.append(object["customerStreetAddress"] as! String)
// Here is the prepare for segue....
override func prepareForSegue(segue: UIStoryboardSegue, sender:
AnyObject?)
{
if (segue.identifier == "thesePools")
{
let employeeDetailVC: EmployeeDetailViewController = segue.destinationViewController
as! EmployeeDetailViewController
// indexPath is set to the path that was tapped
let indexPath = self.tableView.indexPathForSelectedRow
let customerNameLabel = self.customerName[indexPath!.row]
let customerAddressLabel = self.customerAddress[indexPath!.row]
employeeDetailVC.customerString = customerNameLabel
employeeDetailVC.addressString = customerAddressLabel
here is my detail view controller receiving the Strings.
//DetailViewController
var customerString = String()
var addressString = String()
override func viewDidLoad() {
super.viewDidLoad()
self.customerLabel.text = customerString
self.addressLabel.text = addressString
var currentObject = String() is a string and you set it to a string in the prepareForSegue.This should do the trick:
self.customerTextField.text = curentObject
And remove all the other stuff.
Try that
let nav = segue.destinationViewController as! CustomerDetailViewController
var indexPath :NSIndexPath = self.tableview.indexPathForSelectedRow()!
var object = self.CustomerName[indexPath.row] as! String
nav.currentobject = object
I would recommend using a PFQueryTableViewController.
This is a UI object that is provided by Parse and loads data from your class 50x faster.
Here is an example of how to create it:
import UIKit
class YourTableViewController: 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 = "yourClass"
self.textKey = "yourObject"
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: "yourClass")
query.orderByAscending("yourObject")
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 CustomTableViewCell!
if cell == nil {
cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
// Extract values from the PFObject to display in the table cell
cell.info.text = object["info"] as String
// Date for cell subtitle
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateForText = object["date"] as NSDate
cell.date.text = dateFormatter.stringFromDate(dateForText)
return cell
}
// 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].
var detailScene = segue.destinationViewController as YourDetailViewController
// Pass the selected object to the destination view controller.
if let indexPath = self.tableView.indexPathForSelectedRow() {
let row = Int(indexPath.row)
detailScene.currentObject = objects[row] as? PFObject
}
}
At the end make sure to also created a custom cell class.
Related
When a table cell is selected, I want it to populate the textfields on my detail view after segue.
Here is one way I found on this site (I've tried other ways I saw here but had errors/ issues translating the code to use with core data and/or custom cells) that doesn't return errors but does not fill out the fields
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
//(print(tableView.dequeueReusableCell(withIdentifier: "PartyCell", for: indexPath)))
// get selected row (party)
let party = parties[indexPath.row] as NSManagedObject
// create custom cell
let cell = tableView.dequeueReusableCell(withIdentifier: "PartyCell",
for: indexPath) as! PartyCell
// Update the custom cell labels with information from record
cell.nameLabel?.text = party.value(forKeyPath: "name") as? String
cell.sizeLabel.text = party.value(forKeyPath: "size") as? String
cell.contactLabel.text = party.value(forKeyPath: "contact") as? String
cell.locationLabel.text = party.value(forKeyPath: "location") as? String
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
// Create a variable that you want to send based on the destination view controller
// Get a reference to the data by using indexPath shown below
let party = parties[indexPath.row]
// Create an instance of DestinationViewController and pass the variable
let destinationVC = DetailViewController()
destinationVC.nameField.text = party.value(forKeyPath: "name") as? String
destinationVC.sizeField.text = party.value(forKeyPath: "size") as? String
destinationVC.contactField.text = party.value(forKeyPath: "contact") as? String
destinationVC.locationField.text = party.value(forKeyPath: "name") as? String
// Let's assume that the segue name is called playerSegue
// This will perform the segue and pre-load the variable for you to use
destinationVC.performSegue(withIdentifier: "mySegue", sender: self)
}
And here is the detail view with the outlet connections established
import Foundation
import UIKit
import CoreData
class DetailViewController: UIViewController
{
//let party = NSEntityDescription.insertNewObjectForEntityForName("Party", inManagedObjectContext: managedObjectContext) as! Party
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var sizeField: UITextField!
#IBOutlet weak var contactField: UITextField!
#IBOutlet weak var locationField: UITextField!
override func viewWillAppear(_ animated: Bool)
{
}
}
Three fatal mistakes:
DetailViewController() is not the instance in the storyboard.
Even if it was the outlets are not connected yet right after initializing the controller.
You have to perform the segue on the main view controller, not on the DetailViewController.
The solutions:
In didSelectRowAt call self.performSegue and pass the managed object as sender
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
performSegue(withIdentifier: "mySegue", sender: parties[indexPath.row])
}
In DetailViewController declare a NSManagedObject property.
class DetailViewController: UIViewController
{
var party : NSManagedObject!
...
Implement prepare(for segue and assign the NSManagedObject object to the temporary property.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "mySegue" else { return }
let detailViewController = segue.destination as! DetailViewController
detailViewController.party = sender as! NSManagedObject
}
In viewDidLoad of DetailViewController assign the properties to the outlets.
override func viewDidLoad()
{
super.viewDidLoad()
nameField.text = party.value(forKey: "name") as? String
sizeField.text = party.value(forKey: "size") as? String
contactField.text = party.value(forKey: "contact") as? String
locationField.text = party.value(forKey: "location") as? String
}
You can just add a var in your detailviewcontroller:
class DetailViewController: UIViewController {
var party: Party!
}
using segue to pass the selected party; so in didSelectRowAt
let destinationVC = UIStoryboard(name: "yourStory", bundle: nil).instantiateViewController(withIdentifier: "yourId") as! DetailViewController()
destinationVC.party = selectedParty
destinationVC.performSegue(withIdentifier: "mySegue", sender: self)
then in your viewDidLoad of your DetailViewController setup your outlets:
override func viewDidLoad() {
super.viewDidLoad()
nameField.text = party.something
//and so on!
}
first i come from France so sorry for my english.
Second, I'm new in developpement and i have develop a code for add data and after show them with Core Data. it works.ok
but after i want update but i have a problem i don't know why i can't update my value. There is an error : "fatal error: unexpectedly found nil while unwrapping an Optional value"
i have try many solution since 1 week, but can't find the problem. Thanks if someone can help me ! even a little help :)
this is my code (swift 2.3) :
for show in table view :
import UIKit
import CoreData
class ProduitTableViewController: UITableViewController {
#IBOutlet var table: UITableView!
var produits = [NSManagedObject]()
func refreshStories(refreshControl: UIRefreshControl) {
produits.removeAll()
fetchData()
self.table.reloadData()
refreshControl.endRefreshing()
}
override func viewDidLoad() {
super.viewDidLoad()
self.fetchData()
self.table.addSubview(self.refreshControl!)
self.refreshControl?.addTarget(self, action: #selector(ProduitTableViewController.refreshStories(_:)), forControlEvents: UIControlEvents.ValueChanged)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func fetchData() {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
//2
let fetchRequest = NSFetchRequest(entityName: "Produits")
let sort = NSSortDescriptor(key:"dateAjout", ascending:true)
fetchRequest.sortDescriptors = [sort]
//3
do {
let results = try managedContext.executeFetchRequest(fetchRequest)
produits = results as! [NSManagedObject]
} catch let error as NSError {
print("Donnees non recu \(error), \(error.userInfo)")
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.produits.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")
let produit = produits[indexPath.row]
cell!.textLabel!.text = produit.valueForKey("nom") as? String
/*
let id = produit.valueForKey("id") as? String
let date = produit.valueForKey("date") as? NSDate
let localNotification = UILocalNotification()
localNotification.userInfo = ["id" : id!]
localNotification.soundName = UILocalNotificationDefaultSoundName
localNotification.alertBody = "expiré"
localNotification.fireDate = date
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
UIApplication.sharedApplication().applicationIconBadgeNumber += 1
*/
return cell!
}
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let supprimer = UITableViewRowAction(style: .Normal, title: "Suppr.") { action, index in
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let moc = appDelegate.managedObjectContext
// 3
moc.deleteObject(self.produits[indexPath.row])
appDelegate.saveContext()
// 4
self.produits.removeAtIndex(indexPath.row)
tableView.reloadData()
}
supprimer.backgroundColor = UIColor.redColor()
let update = UITableViewRowAction(style: .Normal, title: "Modifier") { action, index in
}
update.backgroundColor = UIColor.blueColor()
return [supprimer]
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// the cells you would like the actions to appear needs to be editable
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "showDetail" {
if let destination = segue.destinationViewController as? DetailViewController {
let row = table.indexPathForSelectedRow?.row
let produit = produits[row!]
let nom = produit.valueForKey("nom") as? String
let id = produit.valueForKey("id") as? String
let detail = produit.valueForKey("detail") as? String
let date = produit.valueForKey("date") as? NSDate
let time = date
let formatter = NSDateFormatter()
formatter.dateFormat = "dd-MM-YY HH:mm"
let formatteddate = formatter.stringFromDate(time!)
destination.dataNom = nom!
destination.dataId = id!
destination.dataDetail = detail!
destination.dataDate = formatteddate
}
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if table.cellForRowAtIndexPath(indexPath) != nil {
self.performSegueWithIdentifier("showDetail", sender: self)
}
}
}
for show detail of the cell :
import CoreData
import UIKit
class DetailViewController: UIViewController {
#IBOutlet var Label: UILabel!
#IBOutlet var Detail: UITextView!
#IBOutlet weak var Date: UILabel!
#IBOutlet weak var Id: UILabel!
var dataNom = ""
var dataDetail = ""
var dataDate = ""
var dataId = ""
override func viewDidLoad() {
super.viewDidLoad()
Label.text = dataNom
Detail.text = dataDetail
Date.text = dataDate
Id.text = dataId
// Do any additional setup after loading the view
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "ModifierDetail" {
if let destination = segue.destinationViewController as? ModifierViewController {
destination.modifierNom = dataNom
destination.modifierId = dataId
destination.modifierDetail = dataDetail
destination.modifierDate = dataDate
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// 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.
}
*/
}
And the last for update/modify my detail:
import UIKit
import CoreData
class ModifierViewController: UIViewController {
#IBOutlet weak var Nom: UITextField!
#IBOutlet weak var Detail: UITextView!
#IBOutlet weak var Date: UITextField!
var Produits: NSManagedObject!
var managedContext: NSManagedObjectContext!
var modifierNom = ""
var modifierDetail = ""
var modifierDate = ""
var modifierId = ""
override func viewDidLoad() {
super.viewDidLoad()
Nom.text = modifierNom
Detail.text = modifierDetail
Date.text = modifierDate
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func Annuler(sender: UIBarButtonItem) {
navigationController?.popViewControllerAnimated(true)
}
#IBAction func Modifier(sender: UIButton) {
let fetchRequest = NSFetchRequest(entityName:"Produits")
fetchRequest.predicate = NSPredicate(format: "nom = %#", modifierNom)
do {
let list = try managedContext.executeFetchRequest(fetchRequest) as! [Produit]
if list.count == 0 // Check notificationId available then not save
{
let newManagedObject = NSEntityDescription.insertNewObjectForEntityForName("Produits", inManagedObjectContext: managedContext)
newManagedObject.setValue(modifierNom, forKey: "nom")
}
// success ...
} catch let error as NSError {
// failure
print("Fetch failed: \(error.localizedDescription)")
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
i have create this other file:
import Foundation
import CoreData
#objc(Produit)
class Produit: NSManagedObject {
#NSManaged var nom:String!
}
As you mentioned in the comment, this line causes the crash:
let list = try managedContext.executeFetchRequest(fetchRequest) as! [Produit]
That line is not safe, because you don't know, if casting to [Prodiut]will always be successful.
In general, you should never force-cast (as!) or force-unwrap (!) something when you don't know 1000%, that it will succeed.
To cast safely, you can use guard:
guard let list = try managedContext.executeFetchRequest(fetchRequest) as! [Produit] else {
//do some error handling here and then return
return
}
After that, you can safely use list.
It's really important to understand, what optionals are and how to handle them safely without crashes.
I'm trying to make a Query with a Pointer in Parse. I have two classes "Discover" and "DiscoveryDetails". I want to get the discovery details of an object that's picked from the discovery class.
Discovery Class
DiscoveryDetails Class - with the discoverID as the pointer.
The discovery objects are displayed in a DiscoveryTableView and on selecting one of the items, I want to query the objects of with an ID related to that selection in a DiscoveryDetailsTableView.
The DiscoveryTableView shows the objects as they appear in the class but the DiscoveryDetailsTableView shows all the objects instead of those related to the Cell I selected.
This is my didSelectRowAtIndexPath Code in the DiscoveryTableView:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let mainStoryboard = UIStoryboard(name: "Discovery", bundle: nil)
let discoveryDetailView = mainStoryboard.instantiateViewControllerWithIdentifier("discoveryDetailTVC") as! DiscoveryDetailTableViewController
let object = self.objectAtIndexPath(indexPath)
discoveryDetailView.titleString = object?.objectForKey("workoutName") as! String
discoveryDetailView.describtionString = object?.objectForKey("workoutDetails") as! String
discoveryDetailView.numberOfWorkouts = object?.objectForKey("numberOfWorkouts") as! Int
discoveryDetailView.imageFile1 = object?.objectForKey("image1") as! PFFile
discoveryDetailView.imageFile2 = object?.objectForKey("image2") as! PFFile
discoveryDetailView.imageFile3 = object?.objectForKey("image3") as! PFFile
let row = indexPath.row //we know that sender is an NSIndexPath here.
let selectedObj = objects![row] // some var where you hold your data
discoveryDetailView.varInDDT = selectedObj
self.navigationController?.pushViewController(discoveryDetailView, animated: true)
}
In my DiscoveryDetailsTableView I have this code:
var titleString: String!
var describtionString: String!
var numberOfWorkouts: Int!
var imageFile1: PFFile!
var imageFile2: PFFile!
var imageFile3: PFFile!
var varInDDT : PFObject?
//MARK: Query for Table with the details
override func queryForTable() -> PFQuery {
let discoveryQuery = PFQuery(className: "DiscoveryDetails")
discoveryQuery.cachePolicy = .CacheElseNetwork
discoveryQuery.whereKey("discoveryID", equalTo: PFObject(withoutDataWithClassName: "Discovery", objectId: "\(varInDDT!.objectId!)"))
discoveryQuery.orderByDescending("createdAt")
return discoveryQuery
}
override func viewDidLoad() {
super.viewDidLoad()
//Header Display
let imagesArray = [imageFile1, imageFile2, imageFile3]
let imagePicked = randomIntergerInRange(0, high: imagesArray.count)
titleLabel.text = titleString.uppercaseString
self.subtitleLabel.text = describtionString
self.numberOfWorkoutsLabel.text = "\(numberOfWorkouts!) Workouts"
//Pick a random Image from the Images
imagesArray[imagePicked].getDataInBackgroundWithBlock({ (imageData, error) -> Void in
if error == nil
{
if let imageData = imageData
{
let image = UIImage(data:imageData)
self.backgroundImage.image = image
}
}
})
...
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
var discoveryDetailItemsCell:DiscoveryDetailTableViewCell! = tableView.dequeueReusableCellWithIdentifier("DiscoveryDetailTableViewCell") as? DiscoveryDetailTableViewCell
...
discoveryDetailItemsCell.titleLabel.text = object?.objectForKey("exerciseName") as? String
discoveryDetailItemsCell.titleLabel.textColor = UIColor.whiteColor()
discoveryDetailItemsCell.durationAndSetsLabel.text = "\((object?.objectForKey("durationOrSets"))!)"
discoveryDetailItemsCell.minAndSetLabel.text = "mins"
...
return discoveryDetailItemsCell
}
There may be similar questions out there but I have not found anything that answers this or I am probably not seeing my mistake clearly.
Thanks for the help in advance. :)
for query with pointer U have to use query like that
let discoveryQuery = PFQuery(className: "DiscoveryDetails")
discoveryQuery.cachePolicy = .CacheElseNetwork
discoveryQuery.whereKey("discoveryID", equalTo: PFObject(withoutDataWithClassName: "Discovery", objectId: "\(varInDDT!.objectId!)"))
discoveryQuery.orderByDescending("createdAt")
return discoveryQuery
for downloading the detail you have to pass at least ID of the object you want to download from the first viewController to the second or you can pass the whole PFObject
DiscoveryTableView
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showDetail", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "showDetail"){ // define the segue Name
let controller = (segue.destinationViewController as! DiscoveryDetailTableViewController)
let row = sender!.row //we know that sender is an NSIndexPath here.
let selectedObj = discoveryObjects[row] // some var where you hold your data
controller.varInDDT = selectedObj
}
}
and define the var of PFObject in detailVC
DiscoveryDetailTableViewController
var varInDDT : PFObject?
import UIKit
class FeedTableViewController: UITableViewController {
var navBar:UINavigationBar=UINavigationBar()
let font = UIFont(name: "Baskerville", size: 15)
var feedData:NSMutableArray = NSMutableArray()
required init(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
}
#IBAction func likeButton(sender: AnyObject) {
if var votes:Int? = quote!.objectForKey("votes") as? Int {
votes!++
}
}
#IBAction func loadData(sender: AnyObject?) {
feedData.removeAllObjects()
var findFeedData:PFQuery = PFQuery(className: "userQuotes")
findFeedData.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]?, error:NSError?)->Void in
if error == nil{
if let objs = objects{
for object in objs{
let quote:PFObject = object as! PFObject
self.feedData.addObject(quote)
// let user:PFUser = (object as! NSArray).lastObject as! PFUser
}
//println(self.feedData)
let array:NSArray = self.feedData.reverseObjectEnumerator().allObjects
self.feedData = NSMutableArray(array: array)
NSOperationQueue.mainQueue().addOperationWithBlock({
self.tableView.reloadData()
})
}
}
}
}
override func viewDidAppear(animated: Bool) {
self.loadData( nil )
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Quotezilla"
// 3
//self.navigationItem.setRightBarButtonItem(rightSearchBarButtonItem, animated: true)
// 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 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return feedData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:QuoteTableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! QuoteTableViewCell
let quote:PFObject = self.feedData.objectAtIndex(indexPath.row) as! PFObject
cell.contentTextView!.font = font
cell.timeStampLabel!.font = font
cell.publisherLabel!.font = font
cell.contentTextView.alpha = 0
cell.timeStampLabel.alpha = 0
cell.publisherLabel.alpha = 0
cell.contentTextView.text = quote.objectForKey("content") as! String
//cell.publisherLabel.text = quote.objectForKey("publisher") as? String
/* func loadLikes(){
if var votes:Int? = quote.objectForKey("votes") as? Int {
votes!++
}
}*/
var dateFormatter:NSDateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "EEEE, MMM d, h:mm a"
cell.timeStampLabel.text = dateFormatter.stringFromDate(quote.createdAt!)
var votes:Int? = quote["votes"] as? Int
if votes == nil {
votes = 0
}
cell.likesLabel?.text = "\(votes!)"
var myObject = quote["publisher"] as? PFObject
myObject?.fetchIfNeeded()
if let foundUser = myObject as? PFUser{
cell.publisherLabel.text = foundUser.username
UIView.animateWithDuration(0.7, animations: {
cell.contentTextView.alpha = 1
cell.timeStampLabel.alpha = 1
cell.publisherLabel.alpha = 1
})
}
return cell
}
So what I am essentially attempting to do is create a likes or votes button. As you see in the code I have a likeButton action that is supposed to auto-increment the likes section in parse. I display the current likes that I have filled into the rows in Parse itself in the cellForRowAtIndexPath function. The problem is that I cannot call quote.objectForKey("votes"), because I initialize it later. I have been poring over this problem and cannot find a way to make the votes update in parse through the likeButton action.
You must live with life on the network. That means your table won't have certain data available when the App starts. Handle a missing object or missing key within a particular cell gracefully and just use some kind of placeholder value. When the parse callback executes, you are already correctly forcing a refresh.
OK So BIG EDIT
This class needed a lot of work. I'm not even going to spell out every change here, but it's basically a complete Parse.com tutorial at this point.
This code compiles cleanly but I can't be sure of everything in your context. In particular do you have a 'likesButton' on every table row as part of your custom table cell view? I'm assuming that.
class FeedTableViewController: UITableViewController {
var navBar = UINavigationBar()
let font = UIFont(name: "Baskerville", size: 15)
var feedData = [PFObject]()
static let cellID = "cell"
// NOTE! See how this tag is set below
#IBAction func likeButton(sender: UIButton) {
let quote = feedData[sender.tag]
if let votes = quote.objectForKey("votes") as? Int {
quote.setObject(votes + 1, forKey: "votes")
}
else {
// CHALLENGE FOR YOU: handle the case of no votes attribute
}
// UPDATE the local UI
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: sender.tag, inSection: 0)],
withRowAnimation: .None)
// CHALLENGE FOR YOU: UPDATE Parse...start a new question if necessary
}
#IBAction func loadData(sender: AnyObject?) {
feedData.removeAll()
PFQuery(className: "userQuotes").findObjectsInBackgroundWithBlock {
[unowned self]
(objects: [AnyObject]?, error: NSError?) -> Void in
if let objs = objects {
for object in objs {
self.feedData.append(object as! PFObject)
}
self.feedData = self.feedData.reverse()
}
NSOperationQueue.mainQueue().addOperationWithBlock { self.tableView.reloadData() }
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.loadData(nil)
self.title = "Quotezilla"
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return feedData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(FeedTableViewController.cellID, forIndexPath: indexPath) as! QuoteTableViewCell
cell.likesButton!.tag = indexPath.row // See how tag works with the above
cell.contentTextView!.font = font
cell.timeStampLabel!.font = font
cell.publisherLabel!.font = font
cell.contentTextView.alpha = 0.0
cell.timeStampLabel.alpha = 0.0
cell.publisherLabel.alpha = 0.0
let q = feedData[indexPath.row]
if let content = q.objectForKey("content") as? String {
cell.contentTextView.text = content
}
else {
cell.contentTextView.text = "Content not found!"
}
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "EEEE, MMM d, h:mm a"
cell.timeStampLabel.text = dateFormatter.stringFromDate(q.createdAt!)
let votes = (q.objectForKey("votes") as? Int) ?? 0
cell.likesLabel?.text = "\(votes)"
let myObject = q.objectForKey("publisher") as? PFObject
myObject?.fetchInBackgroundWithBlock {
[unowned self]
(object: PFObject?, error: NSError?) in
NSOperationQueue.mainQueue().addOperationWithBlock {
if let foundUser = object as? PFUser {
cell.publisherLabel.text = foundUser.username
UIView.animateWithDuration(0.7) {
cell.contentTextView.alpha = 1.0
cell.timeStampLabel.alpha = 1.0
cell.publisherLabel.alpha = 1.0
}
}
else {
cell.publisherLabel.text = "Publisher not found!"
}
}
}
return cell
}
}
I have tried to implement the UISearchController in IOS8 but failed.
The problem is when I have changed the text and the scope button, noting is presented to me.
And it seems that the updateSearchResultsForSearchController function is not even called when I update the search Bar or the scope button.
Here is my code:
class SearchTestController: UITableViewController, UISearchResultsUpdating {
struct Candy {
let category : String
let name : String
}
var searchcontroller = UISearchController(searchResultsController: nil)
func updateSearchResultsForSearchController(searchController: UISearchController) {
filteredcandy = candies.filter() { (candy:Candy) -> Bool in
let scopetest = ( self.category[self.searchcontroller.searchBar.selectedScopeButtonIndex] == "All" ) || ( candy.category == self.category[self.searchcontroller.searchBar.selectedScopeButtonIndex] )
//let texttest = candy.name.rangeOfString(self.searchcontroller.searchBar.text)
//let result = scopetest && (texttest != nil)
return scopetest
}
println(filteredcandy.count)
self.tableView.reloadData()
}
var candies = [Candy]()
var filteredcandy = [Candy]()
var category = ["Chocolate","Hard","Other","All"]
override func viewDidLoad() {
super.viewDidLoad()
// Sample Data for candyArray
self.candies = [Candy(category:"Chocolate", name:"chocolate Bar"),
Candy(category:"Chocolate", name:"chocolate Chip"),
Candy(category:"Chocolate", name:"dark chocolate"),
Candy(category:"Hard", name:"lollipop"),
Candy(category:"Hard", name:"candy cane"),
Candy(category:"Hard", name:"jaw breaker"),
Candy(category:"Other", name:"caramel"),
Candy(category:"Other", name:"sour chew"),
Candy(category:"Other", name:"gummi bear")]
// Reload the table
self.tableView.reloadData()
self.tableView.tableHeaderView = searchcontroller.searchBar
searchcontroller.searchBar.sizeToFit()
searchcontroller.searchBar.showsSearchResultsButton = true
self.definesPresentationContext = true
searchcontroller.searchBar.scopeButtonTitles = category
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchcontroller.active {
return self.candies.count
} else {
return self.candies.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//ask for a reusable cell from the tableview, the tableview will create a new one if it doesn't have any
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell
var candy : Candy
// Check to see whether the normal table or search results table is being displayed and set the Candy object from the appropriate array
if searchcontroller.active {
candy = filteredcandy[indexPath.row]
} else {
candy = candies[indexPath.row]
}
// Configure the cell
cell.textLabel!.text = candy.name
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
}
Add the following lines to viewDidLoad()
searchcontroller.searchResultsUpdater = self
searchcontroller.delegate = self
Update:
Add the following line in viewDidLoad()
searchcontroller.searchBar.delegate = self
Then update the search results in searchBar(_:selectedScopeButtonIndexDidChange:)