Delete row in Parse Data browser. So my TableViewController gets updated with the correct amount of cells minus the deleted cell - ios

import UIKit
class FavouritesTableViewController: UITableViewController {
let factBook = FactBook()
var userQuoteData: NSMutableArray = NSMutableArray()
let colorWheel = ColorWheel()
override func viewDidAppear(animated: Bool) {
var refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: Selector("loadData"), forControlEvents: UIControlEvents.ValueChanged)
self.refreshControl = refreshControl
self.loadData()
//********** For resizbale cells UILABEL **************//
// tableView.estimatedRowHeight = 102 // Replace with your actual estimation
// // Automatic dimensions to tell the table view to use dynamic height
// tableView.rowHeight = UITableViewAutomaticDimension
//********** For resizbale cells UILABEL **************//
// if (PFUser.currentUser() == nil) {
// var loginAlert:UIAlertController = UIAlertController(title: "Sign Up / Login", message: "Please sign up or login", preferredStyle: UIAlertControllerStyle.Alert)
//
// loginAlert.addTextFieldWithConfigurationHandler({
// textfield in
// textfield.placeholder = "Your username"
// })
//
// loginAlert.addTextFieldWithConfigurationHandler({
// textfield in
// textfield.secureTextEntry = true
// textfield.placeholder = "Your password"
// })
//
// loginAlert.addAction(UIAlertAction(title: "Login", style: UIAlertActionStyle.Default, handler: {
// alertAction in
// let textField:NSArray = loginAlert.textFields as NSArray!
// let usernameTextField:UITextField = textField.objectAtIndex(0) as UITextField
// let passwoordTextField:UITextField = textField.objectAtIndex(1) as UITextField
//
// PFUser.logInWithUsernameInBackground(usernameTextField.text, password: passwoordTextField.text, block: { (user:PFUser!, error:NSError!) -> Void in
// if ((user) != nil) {
// println("Login Successful")
// }else {
// println("Login Failed")
// }
// })
// }))
//
// loginAlert.addAction(UIAlertAction(title: "Signup", style: UIAlertActionStyle.Default, handler: {
// alertAction in
// let textField:NSArray = loginAlert.textFields as NSArray!
// let usernameTextField:UITextField = textField.objectAtIndex(0) as UITextField
// let passwoordTextField:UITextField = textField.objectAtIndex(1) as UITextField
//
// var user:PFUser = PFUser()
// user.username = usernameTextField.text
// user.password = passwoordTextField.text
//
// user.signUpInBackgroundWithBlock({ (sucsess: Bool!, error:NSError!) -> Void in
// if error == nil {
// println("Sign Up sucessful")
// } else {
// let error = error.userInfo
// println(error)
// }
// })
//
// }))
//
// self.presentViewController(loginAlert, animated: true, completion: nil)
//
// }
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: Segue to Main View Controller
#IBAction func CancelButton(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
//MARK: logout the user
#IBAction func logoutUser(sender: AnyObject) {
let alertController = UIAlertController(title: "Logout", message: "Are you sure you want to logout?", preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
// ...
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "OK", style: .Default) { (action) in
PFUser.logOut()
self.performSegueWithIdentifier("selectedQuoteSegue", sender: nil)
var currentUser = PFUser.currentUser() // this will now be nil
println(currentUser)
}
alertController.addAction(OKAction)
self.presentViewController(alertController, animated: true) {
// ...
}
}
// MARK: Getting Quotes from Parse.com for a particular user
func loadData() {
userQuoteData.removeAllObjects()
var findUserQuoteData: PFQuery = PFQuery(className: "favouriteQuotes")
findUserQuoteData.whereKey("user", equalTo: PFUser.currentUser())
findUserQuoteData.findObjectsInBackgroundWithBlock{ (objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil{
for object in objects{
let user: PFObject = object as PFObject
self.userQuoteData.addObject(user)
}
let array:NSArray = self.userQuoteData.reverseObjectEnumerator().allObjects
self.userQuoteData = NSMutableArray(array: array)
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userQuoteData.count
}
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell {
let cell:FavouritesTableViewCell = tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath!) as FavouritesTableViewCell
let favouriteQuotes:PFObject = self.userQuoteData.objectAtIndex(indexPath!.row) as PFObject
cell.favouriteQuoteTextView.text = favouriteQuotes.objectForKey("content") as? String
cell.favouriteQuoteTextView.backgroundColor = colorWheel.randomColor()
//Label Animation
cell.favouriteQuoteTextView.alpha = 0
//Date Formatter
// var dateFormatter:NSDateFormatter = NSDateFormatter()
// dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
// cell.timestampLabel.text = dateFormatter.stringFromDate(sweet.createdAt)
//Find User
// var findSweeter:PFQuery = PFUser.query()
// findSweeter.whereKey("objectId", equalTo: sweet.objectForKey("sweeter").objectId)
//
// findSweeter.findObjectsInBackgroundWithBlock { (objects:[AnyObject]!, error:NSError!) -> Void in
// if error == nil {
// let user:PFUser = (objects as NSArray).lastObject as PFUser
// cell.usernameLabel.text = user.username
//Animation automation
UIView.animateWithDuration(0.5, animations: { () -> Void in
cell.favouriteQuoteTextView.alpha = 1
})
// }
//
// }
cell.favouriteQuoteTextView.scrollRangeToVisible(NSMakeRange(0, 0))
return cell
}
override func tableView(tableView: UITableView?, didSelectRowAtIndexPath indexPath: NSIndexPath?) {
let cell:FavouritesTableViewCell = tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath!) as FavouritesTableViewCell
var selectedQuoteFromFavourites: AnyObject = self.userQuoteData.objectAtIndex(indexPath!.row)
var selectedQuote: String = selectedQuoteFromFavourites.objectForKey("content") as String!
println(selectedQuote)
NSUserDefaults.standardUserDefaults().setObject(selectedQuote, forKey: "currentQuote") // we are saving a variable called myName and we are giving it the value of "Bob"
NSUserDefaults.standardUserDefaults().synchronize() // Added synchronize as suggested by LAMMERT WESTERHOFF
println(NSUserDefaults.standardUserDefaults().objectForKey("currentQuote")!) // Here we are accessing the variable.
// factBook.currentQuoteIndexArray()
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "segueHappened") // we are saving a variable called myName and we are giving it the value of "Bob"
NSUserDefaults.standardUserDefaults().synchronize() // Added synchronize as suggested by LAMMERT WESTERHOFF
// println(NSUserDefaults.standardUserDefaults().boolForKey("segueHappened")) // Here we are accessing the variable.
self.performSegueWithIdentifier("selectedQuoteSegue", sender: AnyObject?())
}
//MARK: Swipe to delete
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
//MARK: Deleting Object PFQuery
override func tableView(tableView: UITableView?, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath?) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
println("touch")
// var selectedQuoteFromFavourites: AnyObject = self.userQuoteData.objectAtIndex(indexPath!.row)
//
// var selectedQuote: String = selectedQuoteFromFavourites.objectForKey("content") as String!
//
// println(selectedQuote)
//Query objectId from parse and delete!
// self.tableView.reloadData()
}
}
I have this loadData() function that gets all the Quotes that a user has stored to my Parse backend. I think it puts the data received from parse into this NSMutable array "userQuoteData". This is what my tableview uses to populate the cells. I added a swipe to delete function at the bottom of this code. it looks like this:
override func tableView(tableView: UITableView?, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath?) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
within this swipe to delete function:
How do I tell parse to delete the corrent row with the content of the current cell that is selected(swiped). so I can then reloadData on that tableview with my amended list of quotes from parse. Do I need to find the objectId? Really lost. Thanks in advance.

You've set self.userQuoteData to contain the full PFObjects so simply delete the object; and you'll need to remove the selected object from the self.userQuoteData array before reloading since it informs your table data.
Also, your Parse table doesn't inform your cellForRowAtIndexPath: directly at all -- the self.userQuoteData array does -- so the Parse table doesn't technically need to be updated in order for your table to reflect the changes. So like I've done in the code below, you can delete your object from Parse in the background even as your table reloads.
override func tableView(tableView: UITableView?, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath?) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
var selectedQuoteFromFavourites:PFObject = self.userQuoteData.objectAtIndex(indexPath!.row) as PFObject
selectedQuoteFromFavourites.deleteInBackground()
self.userQuoteData.removeObjectAtIndex(indexPath!.row)
self.tableView.reloadData()
}
}

Related

Database.database() Error cannor find in scope>

I am trying to delete a table view cell in swift and when I delete the cell I also need to delete the data in firebase. So I use Database.database().child("tweet") this is where the error is it says cannot find Database in scope.
import UIKit
import Firebase
import Firestore
class TableViewController: UITableViewController {
var db:Firestore!
var tweetArray = [tweet]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsMultipleSelectionDuringEditing = true
db = Firestore.firestore()
loadData()
checkForUpdates()
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
Database.database().child("tweet") "Error cannot find Database in scope"
}
func loadData() {
db.collection("tweet").getDocuments() {
querySnapshot, error in
if let error = error {
print("\(error.localizedDescription)")
}else{
self.tweetArray = querySnapshot!.documents.compactMap({tweet(dictionary: $0.data())})
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
func checkForUpdates() {
db.collection("tweet").whereField("timeStamp", isGreaterThan: Date())
.addSnapshotListener {
querySnapshot, error in
guard let snapshots = querySnapshot else {return}
snapshots.documentChanges.forEach {
diff in
if diff.type == .added {
self.tweetArray.append(tweet(dictionary: diff.document.data())!)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
#IBAction func composeSweet(_ sender: Any) {
let composeAlert = UIAlertController(title: "Add Employee", message: "Add Employee", preferredStyle: .alert)
composeAlert.addTextField { (textField:UITextField) in
textField.placeholder = "Name"
}
composeAlert.addTextField { (textField:UITextField) in
textField.placeholder = "Adress"
}
composeAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
composeAlert.addAction(UIAlertAction(title: "Add Employee", style: .default, handler: { (action:UIAlertAction) in
if let name = composeAlert.textFields?.first?.text,
let content = composeAlert.textFields?.last?.text {
let newTweet = tweet(name: name, content: content,timeStamp: Date())
var ref:DocumentReference? = nil
ref = self.db.collection("tweet").addDocument(data: newTweet.dictionary) {
error in
if let error = error {
print("Error adding document: \(error.localizedDescription)")
}else{
print("Document added with ID: \(ref!.documentID)")
}
}
}
}))
self.present(composeAlert, animated: true, completion: nil)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tweetArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let tweet1 = tweetArray[indexPath.row]
cell.textLabel?.text = "\(tweet1.name) \(tweet1.content)"
cell .detailTextLabel?.text = "\(tweet1.timeStamp) "
return cell
}
}
I tried importing different firebase imports and that didn't work i'm not sure if it has something to do with my cocoa pods. these are the cocapods I have downloaded: pod 'Firebase/Core
pod 'Firebase/Auth' pod 'Firestore'
Your code is reading data with:
db.collection("tweet").whereField("timeStamp", isGreaterThan: Date())
This is the API for Cloud Firestore, a NoSQL document database that is part of Firebase.
You then try to also access data with:
Database.database().child("tweet")
This is using the API for the Realtime Database, which is also a part of Firebase but it is a completely separate product with its own API.
To prevent more problems, use only the API for the database you're actually using, which seems to be Firestore. Have a look at the documentation on deleting data from Firestore

Swift background mode for BLE iOS9

I want to improve the MPCRevisited project which is Chat app that using multi peer method. I'm using BLE to connect one device to another device (iPad and iPod) and send and receive the data. However, when I press home button to make background mode on one device, after 5 seconds, I can't send or receive the data.
image description here
I've already check all the thing in background modes, but still its not working at all.
import UIKit
import MultipeerConnectivity
class ParkBenchTimer {
let startTime:CFAbsoluteTime
var endTime:CFAbsoluteTime?
init() {
startTime = CFAbsoluteTimeGetCurrent()
}
func stop() -> CFAbsoluteTime {
endTime = CFAbsoluteTimeGetCurrent()
return duration!
}
var duration:CFAbsoluteTime? {
if let endTime = endTime {
return endTime - startTime
} else {
return nil
}
}
}
class ChatViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var chatTextField: UITextField!
#IBOutlet weak var chatTableView: UITableView!
var messagesArray: [[String : String]] = []
let mpcManager = MPCManager.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.chatTableView.delegate = self
self.chatTableView.dataSource = self
self.chatTableView.estimatedRowHeight = 60.0
self.chatTableView.rowHeight = UITableViewAutomaticDimension
self.chatTextField.delegate = self
self.mpcManager.messageRecievedDelegate = self
}
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.
}
*/
// MARK: IBAction method implementation
#IBAction func endChat(sender: AnyObject) {
let messageDictionary: [String: String] = ["message": "_end_chat_"]
if self.mpcManager.sendData(dictionaryWithData: messageDictionary, toPeer: self.mpcManager.session.connectedPeers[0] as MCPeerID){
self.dismissViewControllerAnimated(true, completion: { () -> Void in
self.mpcManager.session.disconnect()
})
}
}
// MARK: UITableView related method implementation
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.messagesArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCellWithIdentifier("idCell") else {
assert(true)
return UITableViewCell()
}
guard let currentMessage = self.messagesArray[safe: indexPath.row] else {
print(" ")
assert(true)
return UITableViewCell()
}
if let sender = currentMessage["sender"] {
var senderLabelText: String
var senderColor: UIColor
if sender == "self" {
senderLabelText = "I said:"
senderColor = UIColor.purpleColor()
} else {
senderLabelText = sender + " said:"
senderColor = UIColor.orangeColor()
}
cell.detailTextLabel?.text = senderLabelText
cell.detailTextLabel?.textColor = senderColor
}
if let message = currentMessage["message"] {
cell.textLabel?.text = message
}
return cell
}
// MARK: UITextFieldDelegate method implementation
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
guard let textFieldText = textField.text else {
assert(true)
return false
}
let messageDictionary: [String: String] = ["message": textFieldText]
guard let connectedPeer = self.mpcManager.session.connectedPeers[safe: 0] else {
print(" ")
assert(true)
return false
}
if self.mpcManager.sendData(dictionaryWithData: messageDictionary, toPeer: connectedPeer) {
let dictionary = ["sender": "self", "message": textFieldText]
self.messagesArray.append(dictionary)
self.updateTableview()
} else {
print("Could not send data")
}
textField.text = ""
return true
}
// MARK: Custom method implementation
func updateTableview(){
chatTableView.reloadData()
if self.chatTableView.contentSize.height > self.chatTableView.frame.size.height {
let indexPathToScrollTo = NSIndexPath(forRow: messagesArray.count - 1, inSection: 0)
self.chatTableView.scrollToRowAtIndexPath(indexPathToScrollTo, atScrollPosition: .Bottom, animated: true)
}
}
}
extension ChatViewController : MPCManagerRecievedMessageDelegate {
func managerRecievedData(data:NSData ,fromPeer:MCPeerID) {
// Convert the data (NSData) into a Dictionary object.
let dataDictionary = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! [String : String]
// Check if there's an entry with the "message" key.
if let message = dataDictionary["message"] {
// Make sure that the message is other than "_end_chat_".
if message != "_end_chat_"{
// Create a new dictionary and set the sender and the received message to it.
let messageDictionary: [String: String] = ["sender": fromPeer.displayName, "message": message]
// Add this dictionary to the messagesArray array.
messagesArray.append(messageDictionary)
// Reload the tableview data and scroll to the bottom using the main thread.
self.updateTableview()
} else {
}
}
}
func managerDidRecievedMessage(message: String, fromPeer: MCPeerID) {
// Create a new dictionary and set the sender and the received message to it.
//let messageDictionary: [String: String] = ["sender": fromPeer.displayName, "message": message]
// Add this dictionary to the messagesArray array.
//messagesArray.append(messageDictionary)
// Reload the tableview data and scroll to the bottom using the main thread.
//self.updateTableview()
}
func managerDidEndChat(fromPeer:MCPeerID) {
// In this case an "_end_chat_" message was received.
// Show an alert view to the user.
let alert = UIAlertController(title: "", message: "\(fromPeer.displayName) ended this chat.", preferredStyle: UIAlertControllerStyle.Alert)
let doneAction: UIAlertAction = UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default) { (alertAction) -> Void in
self.mpcManager.session.disconnect()
self.dismissViewControllerAnimated(true, completion: nil)
}
alert.addAction(doneAction)
self.presentViewController(alert, animated: true, completion: nil)
}
}
This is my code.
Please help me if someone knows this problem. What I want to do is one device to keep sending the message and other device to become background and foreground back and forth.
Thank you.
Looking at some other StackOverflow posts (here and here), it seems like the Multipeer Connectivity Framework is not built to function in the background and your functionality will disappear after a couple minutes.
Bluetooth will function in the background, with the capabilities that you checked, but you will have to create your own messaging platform; even though Multipeer relies partially on Bluetooth, the capabilities are separate entities.

Update Table View in iOS (Swift)

I am making a cocktail iOS application.
I am adding strings to a tableview (an ingredient to the "cabinet"). The user enters an ingredient and then presses the button ADD. It successfully adds it to the Core Data but it does not appear right away. What am I doing wrong?
Below is my code, thanks!
ViewController:
import UIKit
import CoreData
class CabinetViewController: UIViewController, UITextFieldDelegate, UITableViewDataSource, UITableViewDelegate {
var ingredientArray = [String]()
var display = [String]()
var dbIngredients = [String]()
let ingredientFetch = NSFetchRequest(entityName: "Cabinet")
var fetchedIngredient = [Cabinet]()
#IBOutlet weak var TextUI: UITextField!
#IBOutlet weak var Button: UIButton!
#IBOutlet weak var TableView: UITableView!
let moc = DataController().managedObjectContext
override func viewDidLoad() {
super.viewDidLoad()
TextUI.delegate = self
TextUI.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
TableView.delegate = self
TableView.dataSource = self
TableView.registerClass(UITableViewCell.self,
forCellReuseIdentifier: "Cell")
// fetch Core Data
do{
fetchedIngredient = try moc.executeFetchRequest(ingredientFetch) as! [Cabinet]
} catch {
fatalError()
}
let postEndpoint: String = "http://www.thecocktaildb.com/api/json/v1/1/list.php?i=list"
guard let url = NSURL(string: postEndpoint) else {
print("Error: cannot create URL")
return
}
let urlRequest = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
}
guard error == nil else {
print("error calling GET on www.thecocktaildb.com")
print(error)
return
}
let post: NSDictionary
do {
post = try NSJSONSerialization.JSONObjectWithData(responseData,
options: []) as! NSDictionary
} catch {
print("error trying to convert data to JSON")
return
}
var count = 1
if let drinks = post["drinks"] as? [NSDictionary] {
for drink in drinks {
if let strIngredient = drink["strIngredient1"] as? String {
print(String(count) + ". " + strIngredient)
self.dbIngredients.append(strIngredient)
count++
}
}
}
})
task.resume()
TableView.reloadData()
}
func textFieldDidChange(textField: UITextField) {
search(self.TextUI.text!)
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
Button.addTarget(self, action: "buttonPressed:", forControlEvents: .TouchUpInside)
return true
}
func buttonPressed(sender: UIButton!) {
//ingredientArray.append(TextUI.text!)
let entity = NSEntityDescription.insertNewObjectForEntityForName("Cabinet", inManagedObjectContext: moc) as! Cabinet
entity.setValue(TextUI.text!, forKey: "ingredient")
do{
try moc.save()
}catch {
fatalError("failure to save context: \(error)")
}
showAlertButtonTapped(Button)
// dispatch_async(dispatch_get_main_queue(), { () -> Void in
// self.TableView.reloadData()
// })
}
#IBAction func showAlertButtonTapped(sender: UIButton) {
// create the alert
let alert = UIAlertController(title: "Added!", message: "You've added " + TextUI.text! + " to your cabinet", preferredStyle: UIAlertControllerStyle.Alert)
// add an action (button)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
// show the alert
self.presentViewController(alert, animated: true, completion: nil)
}
func search(str:String) {
display.removeAll(keepCapacity: false)
for s in dbIngredients{
if s.hasPrefix(str){
display.append(s)
print(s)
}
}
}
func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return fetchedIngredient.capacity
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
do{
let fetchedIngredient = try moc.executeFetchRequest(ingredientFetch) as! [Cabinet]
cell.textLabel?.text = fetchedIngredient[indexPath.row].ingredient
} catch {
fatalError("bad things happened: \(error)")
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let alert = UIAlertController(title: "Remove " + fetchedIngredient[indexPath.row].ingredient!,
message: "No more " + fetchedIngredient[indexPath.row].ingredient! + " in your cabinet?",
preferredStyle: .Alert)
let deleteAction = UIAlertAction(title: "Remove",
style: .Default,
handler: { (action:UIAlertAction) -> Void in
self.fetchedIngredient.removeAtIndex(indexPath.row)
do{
let fetchedResults = try self.moc.executeFetchRequest(self.ingredientFetch)
if let result = fetchedResults[indexPath.row] as? NSManagedObject {
self.moc.deleteObject(result)
try self.moc.save()
}
}catch{
fatalError()
}
})
let cancelAction = UIAlertAction(title: "Cancel",
style: .Default) { (action: UIAlertAction) -> Void in
}
alert.addAction(cancelAction)
alert.addAction(deleteAction)
presentViewController(alert,
animated: true,
completion: nil)
TableView.reloadData()
}
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.
}
*/
}
Since your problem isn't Core Data you need to use Table View beginUpdates and EndUpdates to insert the row. At the end of your buttonPressed function put this:
do{
fetchedIngredient = try moc.executeFetchRequest(ingredientFetch) as! [Cabinet]
self.tableView.beginUpdates()
let totalIngredients = fetchedIngredient.count
let newItemIndexPath = NSIndexPath(forRow: totalIngredients-1, inSection: 0)
self.tableView.insertRowsAtIndexPaths([newItemIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
self.tableView.endUpdates()
} catch {
fatalError()
}
On your number of rows in section:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedIngredient.count
}
And on the cell for row at index path
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
cell.textLabel?.text = fetchedIngredient[indexPath.row].ingredient
return cell
}
There are a couple of problems with your code. Firstly, since you're fetching records into an array, calling reloadData will not have any impact unless you update the array. There is no automatic connection between adding a new core data record and your fetchedIngredient array.
There are a few ways to solve this, although the most common is probably to just refetch the records into the same array whenever core data is updated. Alternatively you can change your code to us NSFetchedResultsController instead of an array, which will automatically update the tableView when core data is updated (based on the predicate you provide it). This class provides the automatic connection to core data for you.
Another problem is that you are refetching the records in cellForRowAtIndexPath and didSelectRowAtIndexPath. This should not be done. Instead you should just be referring to the class-level fetchedIngredient array (or the NSFetchedResultsController if you choose to use that).
Furthermore, the call to dataTaskWithRequest runs in the background. It's not clear from the code how you're using it, but the fact that you have reloadData afterwards suggests it should impact the tableView. However because the task runs in the background, the completion handler will run after the table is reloaded. Therefore you should be calling reloadData inside the completion handler. And since it would then be running on another thread, you would have to dispatch it to the main queue, using:
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}

Getting an Array From Parse into a Table View (Swift 2)

I am trying to pull an array of strings in the from "my_classes" in the "User" class in Parse. I want each individual string within the array to become a separate cell in a tableview when I tap on the search button. This is my array in "my_classes" : ["Physics","Economics","Pre Calculus"]. I want "Physics" as it's own cell, "Economics" as its own cell, etc.
import UIKit
import Parse
class CardSetClassTableViewController: UITableViewController, UISearchBarDelegate {
// MARK: Outlets
#IBOutlet var searchBar: UISearchBar!
#IBOutlet var resultsTableView: UITableView!
// MARK: Variables
var searchResults = [String]()
// MARK: Actions
#IBAction func newClassBarButtonItemPressed(sender: AnyObject) {
self.performSegueWithIdentifier("newClassSegue", sender: self)
}
// MARK: Functions
override func viewDidLoad() {
super.viewDidLoad()
self.searchBar.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func displayAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle:UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
func searchBarSearchButtonClicked(searchBar: UISearchBar)
{
if reachabilityStatus == kNOTREACHABLE {
self.displayAlert("No Internet Connection", message: "Please connect to the internet before continuing.")
} else {
searchBar.resignFirstResponder()
print("Search word = \(searchBar.text!)")
let classNameQuery = PFQuery(className:"_User")
classNameQuery.whereKey("my_classes".lowercaseString, equalTo: searchBar.text!.lowercaseString)
let query = PFQuery.orQueryWithSubqueries([classNameQuery])
query.findObjectsInBackgroundWithBlock {
(results: [PFObject]?, error: NSError?) -> Void in
if error != nil {
self.displayAlert("Error", message: error!.localizedDescription)
return
}
if let objects = results {
self.searchResults.removeAll(keepCapacity: false)
for object in objects {
let className = object.valueForKey("my_classes") as! String
self.searchResults.append(className)
}
dispatch_async(dispatch_get_main_queue()) {
self.resultsTableView.reloadData()
self.searchBar.resignFirstResponder()
}
}
}
}
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResults.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel!.text = searchResults[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let classIndexPath = tableView.indexPathForSelectedRow!
let selectedCell = tableView.cellForRowAtIndexPath(classIndexPath)! as UITableViewCell
let spinningActivity = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
spinningActivity.labelText = "Loading"
if reachabilityStatus == kNOTREACHABLE {
spinningActivity.hide(true)
self.displayAlert("No Internet Connection", message: "Please connect to the internet before continuing.")
} else {
// let className : String = String(selectedCell.textLabel!.text!)
self.performSegueWithIdentifier("addCardSet", sender: self)
}
searchBar.resignFirstResponder()
}
}
Thanks!
Try the following...
Edit
var songsArray = [String]()
func fetchUsers() {
let userQuery: PFQuery = PFUser.query()!
//search users by the sepcified username, returns a users! object
//make an array to put the values from the users! array object into
//then append those from your "middle-man" array into your destination array,
//in this example songArray is destination array and songsFromParse is "middle-man" array
userQuery.whereKey("username", equalTo: (username)!)
userQuery.findObjectsInBackgroundWithBlock({
(users, error) -> Void in
var songsFromParse = users!
if error == nil {
if songsFromParse.count != 0 {
self.songsArray = (songsFromParse[i].valueForKey("CurrentSongURLArray") as! Array)
}
self.tableView.reloadData()
} else {
print(error)
}
})
}
You then take your new array that contains the objects that you retrieved, in this example songsArray and use it to populate your tableView. In cellForRowAtIndexPath ...
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell ID")
cell?.textLabel?.text = songsArray[indexPath]
return cell!
}

Note code in Swift

I have seen a similar request but did not respond to my problem.
I am building a simple app notes but when I make the login, the data saved on Parse appear for a few seconds on the TableView and then disappear. What am I doing wrong?
thank you all
import UIKit
class MasterTableViewController: UITableViewController, PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate {
var noteObjects: NSMutableArray! = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
// 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 viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.loginSetup()
}
// Parse - Login
func logInViewController(logInController: PFLogInViewController, shouldBeginLogInWithUsername username: String, password: String) -> Bool {
if (!username.isEmpty || !password.isEmpty) {
return true
} else {
return false
}
}
func logInViewController(logInController: PFLogInViewController, didLogInUser user: PFUser) {
self.dismissViewControllerAnimated( true, completion: nil )
}
func logInViewController(logInController: PFLogInViewController, didFailToLogInWithError: NSError?)
{
println("Faild to log in..")
}
// Parse - sign up
func signUpViewController(signUpController: PFSignUpViewController, shouldBeginSignUp info: [NSObject : AnyObject]) -> Bool {
if let password = info["password"] as? String {
return count(password.utf16) >= 8
} else {
return false
}
}
func signUpViewController(signUpController: PFSignUpViewController, didSignUpUser user: PFUser) {
self.dismissViewControllerAnimated(true, completion: nil)
}
func signUpViewController(signUpController: PFSignUpViewController, didFailToSignUpWithError error: NSError?) {
println("Faild to sign up")
}
func signUpViewControllerDidCancelSignUp(signUpController: PFSignUpViewController) {
println("User dismissed sign up")
}
// Parse - logout
#IBAction func logoutAction(sender: AnyObject) {
PFUser.logOut()
self.loginSetup()
}
func loginSetup() {
if (PFUser.currentUser() == nil) {
var logInViewController = PFLogInViewController()
logInViewController.delegate = self
var signUpViewController = PFSignUpViewController()
signUpViewController.delegate = self
logInViewController.signUpController = signUpViewController
self.presentViewController(logInViewController, animated: true, completion: nil)
}else {
self.fetchAllObjectsFromLocalDatastore()
self.fetchAllObjects()
}
}
/*
func fetchAllObjectsFromLocalDatastore() {
var query: PFQuery = PFQuery(className: "Note")
//query.cachePolicy = .CacheElseNetwork
query.fromLocalDatastore()
query.whereKey("username", equalTo: PFUser.currentUser()!.username!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if (error == nil) {
if let objects = objects as? [PFObject] {
for object in objects {
println(object.objectId)
}
}
//var temp: PFObject = PFObject()
//self.noteObjects = temp.mutableCopy() as! NSMutableArray
//println(self.noteObjects)
self.tableView.reloadData()
}else {
println(error!.userInfo)
}
}
}
func fetchAllObjects() {
PFObject.unpinAllObjectsInBackgroundWithBlock(nil)
var query: PFQuery = PFQuery(className: "Note")
//query.cachePolicy = .CacheElseNetwork
query.whereKey("username", equalTo: PFUser.currentUser()!.username!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if (error == nil) {
PFObject.pinAllInBackground(objects, block: nil)
self.fetchAllObjectsFromLocalDatastore()
}else {
println(error!.userInfo)
}
}
}
*/
func fetchAllObjectsFromLocalDatastore() {
var query: PFQuery = PFQuery(className: "Note")
query.fromLocalDatastore()
query.whereKey("username", equalTo: PFUser.currentUser()!.username!)
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if (error == nil) {
//var temp: NSArray = objects as! [NSArray]
var temp: NSArray = objects! as NSArray
self.noteObjects = temp.mutableCopy() as! NSMutableArray
self.tableView.reloadData()
}else {
println(error!.userInfo)
}
}
}
func fetchAllObjects() {
PFObject.unpinAllObjectsInBackgroundWithBlock(nil)
var query: PFQuery = PFQuery(className: "Note")
query.whereKey("username", equalTo: PFUser.currentUser()!.username!)
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if (error == nil) {
PFObject.pinAllInBackground(objects, block: nil)
self.fetchAllObjectsFromLocalDatastore()
}else {
println(error!.userInfo)
}
}
}
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 noteObjects!.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MasterTableViewCell
var object: PFObject = self.noteObjects.objectAtIndex(indexPath.row) as! PFObject
cell.masterTitleLabel?.text = object["title"] as? String
cell.masterTextLabel?.text = object["text"] as? String
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("editNote", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var upcoming: AddNoteTableViewController = segue.destinationViewController as! AddNoteTableViewController
if (segue.identifier == "editNote") {
let indexPath = self.tableView.indexPathForSelectedRow()!
var object: PFObject = self.noteObjects.objectAtIndex(indexPath.row) as! PFObject
upcoming.object = object;
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
/*
// 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.
}
*/
}

Resources