loadinBackground error in parse - swift

I have problems with loadinbackground. I am getting an error saying Cannot Invoke loadinBackground with no arguments.
The following is my code, I have looked in the internet and don't know why this is not working.
import UIKit
import Parse
import ParseUI
class DetailViewController: UIViewController, UINavigationControllerDelegate {
// Container to store the view table selected object
var currentObject : PFObject?
// Some text fields
#IBOutlet weak var topsLabel: UITextField!
#IBOutlet weak var topsImageView: PFImageView!
var updateObject : PFObject?
// The save button
#IBAction func saveButton(sender: AnyObject) {
// Use the sent country object or create a new country PFObject
if let updateObjectTest = currentObject as PFObject? {
updateObject = currentObject! as PFObject
} else {
updateObject = PFObject(className:"Tops")
}
// Update the object
if let updateObject = updateObject {
updateObject["topsLabel"] = topsLabel.text
// Create a string of text that is used by search capabilites
var searchText = (topsLabel.text).lowercaseString
updateObject["searchText"] = searchText
// Update the record ACL such that the new record is only visible to the current user
updateObject.ACL = PFACL(user: PFUser.currentUser()!)
// Save the data back to the server in a background task
updateObject.save()
}
// Return to table view
self.navigationController?.popViewControllerAnimated(true)
}
override func viewDidLoad() {
super.viewDidLoad()
// Unwrap the current object object
if let object = currentObject {
if let value = object["topsLabel"] as? String {
topsLabel.text = value
// Display standard question image
var initialThumbnail = UIImage(named: "question")
topsImageView.image = initialThumbnail
// Replace question image if an image exists on the parse platform
if let thumbnail = object["topsImageView"] as? PFFile {
topsImageView.file = thumbnail
topsImageView.loadInBackground()
}
}
}
}
/*
// 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.
}
*/
}
Tops View
import UIKit
import Parse
var tops = [PFObject]()
class TopsViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UISearchBarDelegate {
// Connection to the search bar
#IBOutlet weak var searchBar: UISearchBar!
// Connection to the collection view
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Wire up search bar delegate so that we can react to button selections
searchBar.delegate = self
// Resize size of collection view items in grid so that we achieve 3 boxes across
let cellWidth = ((UIScreen.mainScreen().bounds.width) - 32 - 30 ) / 3
let cellLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
cellLayout.itemSize = CGSize(width: cellWidth, height: cellWidth)
}
/*
==========================================================================================
Ensure data within the collection view is updated when ever it is displayed
==========================================================================================
*/
// Load data into the collectionView when the view appears
override func viewDidAppear(animated: Bool) {
loadCollectionViewData()
}
/*
==========================================================================================
Fetch data from the Parse platform
==========================================================================================
*/
func loadCollectionViewData() {
// Build a parse query object
var query = PFQuery(className:"Tops")
// Check to see if there is a search term
if searchBar.text != "" {
query.whereKey("uploader", containsString: searchBar.text.lowercaseString)
}
// Fetch data from the parse platform
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
// The find succeeded now rocess the found objects into the countries array
if error == nil {
// Clear existing country data
tops.removeAll(keepCapacity: true)
// Add country objects to our array
if let objects = objects as? [PFObject] {
tops = Array(objects.generate())
}
// reload our data into the collection view
self.collectionView.reloadData()
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
}
/*
==========================================================================================
UICollectionView protocol required methods
==========================================================================================
*/
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tops.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("mySingleCell", forIndexPath: indexPath) as! SingleRowCell
// Display the country name
if let value = tops[indexPath.row]["topsLabel"] as? String {
cell.topsLabel.text = value
}
// Display "initial" flag image
var initialThumbnail = UIImage(named: "question")
cell.topsImageView.image = initialThumbnail
// Fetch final flag image - if it exists
if let value = tops[indexPath.row]["tops"] as? PFFile {
let finalImage = tops[indexPath.row]["tops"] as? PFFile
finalImage!.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
cell.topsImageView.image = UIImage(data:imageData)
}
}
}
}
return cell
}
/*
==========================================================================================
Segue methods
==========================================================================================
*/
// Process collectionView cell selection
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let currentObject = tops[indexPath.row]
performSegueWithIdentifier("CollectionViewToDetailView", sender: currentObject)
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// If a cell has been selected within the colleciton view - set currentObjact to selected
var currentObject : PFObject?
if let country = sender as? PFObject{
currentObject = sender as? PFObject
} else {
// No cell selected in collectionView - must be a new country record being created
currentObject = PFObject(className:"Tops")
}
// Get a handle on the next story board controller and set the currentObject ready for the viewDidLoad method
var detailScene = segue.destinationViewController as! DetailViewController
detailScene.currentObject = (currentObject)
}
/*
==========================================================================================
Process Search Bar interaction
==========================================================================================
*/
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
// Dismiss the keyboard
searchBar.resignFirstResponder()
// Reload of table data
self.loadCollectionViewData()
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
// Dismiss the keyboard
searchBar.resignFirstResponder()
// Reload of table data
self.loadCollectionViewData()
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
// Clear any search criteria
searchBar.text = ""
// Dismiss the keyboard
searchBar.resignFirstResponder()
// Reload of table data
self.loadCollectionViewData()
}
/*
==========================================================================================
Process memory issues
To be completed
==========================================================================================
*/
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
UPLOADING Image
#IBAction func uploadButton(sender: AnyObject) {
var imageText = uploadMessage.text
if uploadPreviewImageView.image == nil {
//image is not included alert user
println("Image not uploaded")
}else {
var posts = PFObject(className: "Tops")
posts["imageText"] = imageText
posts["uploader"] = PFUser.currentUser()
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
var imageData = UIImagePNGRepresentation(self.uploadPreviewImageView.image)
var parseImageFile = PFFile(name: "uploaded_image.png", data: imageData)
posts["imageFile"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
println("finished")
self.performSegueWithIdentifier("goHomeFromUpload", sender: self)
}else {
println(error)
}
})
}else {
println(error)
}

Related

realm selectedRowAtIndexPath using segue showing different results

it is my first time using segment control and realm. so currently I am using segue to perform segue to Add/EditVC for modification of data.
when segue performed and took data to Add/EditVC to variable selectedTransaction, I want as following data to to be filled accordingly
/* selectedTransaction print statement Results */
print("selectedTransaction = \(selectedTransaction!)")
selectedTransaction = Transaction {
categoryType = Category {
type = expense;
name = EXPENSE 3;
};
amount = 1000;
date = April 2;
}
amountTF.text = selectedTransaction.amount (done and correct)
categorySCoutlet.selectedSegmentIndex = selectedTransaction.categoryType.type (fail to show segmentindex at selectedTransaction.categoryType.type)
categoryTF.text = selectedTransaction.categoryType.name (name shown correctly, however will return nil if user did not RESELECT again)
I was expecting all data are shown as if it created.
However, I faced 2 issue in getting it done
SegmentControl selected index are always in 0 instead of selectedTransaction.categoryType.name (I want the segment control to be at the index which is as created)
categoryTF.text are showing correctly, but if I did not choose again and leave as it be. It will auto return back to nil in results when I pressed the saveButton. : I wish categoryTF.text will return as created and value will not change even if I did not touch it and clicked saveButton
In gif shown below, I chosen row2 as sample. and the result in Realm Browser showing as it is.
I only changed the amountTF.text information from 1200 to 2000, which in result realm browser will set the result of cateogoryType in segmentcontrol to "income" and category will return to nil
sample of the workflow
//Data Model
//MARK: - Transaction Category Section
enum CategoryType : String, CaseIterable {
case income = "income"
case expense = "expense"
init?(id : Int) {
if id < CategoryType.allCases.count {
self = CategoryType.allCases[id]
} else {
return nil
}
}
}
class Category : Object {
#objc dynamic var type : String = CategoryType.income.rawValue
#objc dynamic var name : String = ""
// let parentCategory = LinkingObjects(fromType: Transaction.self, property: "ofCategory")
convenience init(type:CategoryType, name: String) {
self.init()
self.type = type.rawValue
self.name = name
}
}
/* VC that should read and load all data to required place */
//edit
var selectedTransaction : Transaction!
#IBOutlet weak var amountTF: UITextField!
//PickerView for keyboard
lazy var pickerView : UIPickerView = UIPickerView()
//Segment Control
#IBOutlet weak var categorySCoutlet: UISegmentedControl!
#IBOutlet weak var categoryTF: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
amountTF.text! = selectedTransaction.amount
categoryTF.text! = selectedTransaction.categoryType!.name
setupPicker()
}
#IBAction func categoryTypeSC(_ sender: UISegmentedControl) {
guard let type = CategoryType(id: sender.selectedSegmentIndex) else {
fatalError("error")
}
currentCategories = categories.filter("type == %#", type.rawValue)
categoryTF.text = currentCategories.first?.name
pickerView.reloadAllComponents()
pickerView.selectRow(1, inComponent: 0, animated: true)
}
//MARK:- Add Transaction Btn
#IBAction func addTransButtonTapped(_ sender: UIButton) {
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
if touches.first?.view == view {
categoryTF.resignFirstResponder()
}
}
//MARK:- Picker Helper
func setupPicker() {
currentCategories = categories.filter("type == %#", CategoryType.income.rawValue)
categoryTF.inputView = pickerView
pickerView.delegate = self
pickerView.dataSource = self
categorySCoutlet.setTitle("Income", forSegmentAt: 0)
categorySCoutlet.setTitle("Expense", forSegmentAt: 1)
categorySCoutlet.addTarget(self, action: #selector(categoryTypeSC(_:)), for: .valueChanged)
}
You are calling tableView.deselectRow(at: indexPath, animated: false) in your tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) method.
This results in returning the incorrect indexPath in prepareForSegue.
You should either remove the deselectRow call from didSelectRowAtIndexPath method,
or you should create a property to hold the value of indexPath.
Something like this:
// somewhere in your class
var selectedIndexPath: IndexPath?
then
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedRowForTrans : Transaction = getTransactions[indexPath.row]
selectedIndexPath = indexPath // set the value of selectedIndexPath
tableView.deselectRow(at: indexPath, animated: false)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "editTrans") {
if let indexPath = selectedIndexPath { // check if there is a valid indexPath
let editTransVC = segue.destination as! AddTransactionTableViewController
let selectedRowForTrans : Transaction = getTransactions[indexPath.row]
editTransVC.selectedTransaction = selectedRowForTrans
}
}
}
Hope this helps

Can't update a value with Core Data

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.

Parse: Retrieving Data by Row

Overview: How can I make it so that when the cell with the segue
identifier of 0 will load data in the row that has 0 as its ID, cell with segue identifier of 1 will load data in the row that has 1 as its ID, and so on and so forth. The data includes ID (responds to cell identifier), navTitle (title of the navigation bar), written (who the article was written by), date (date of the article), and article (the article itself).
I am trying to make it so that once a cell is tapped in my tableview it opens data unique to that cell. What would the best way to do that? I was thinking that maybe I should have it check the ID column I have on Parse and load data the data in that row, but I'm not sure how to do that. Is there a better way to do this? Any help is appreciated! Feel free to ask me for any additional information.
^ So here I have a tableview in which data is being taken from Parse and used for both labels.
^ This view controller is segued to the cell above with:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
self.performSegueWithIdentifier("0a", sender: nil)
self.tableview.deselectRowAtIndexPath(indexPath, animated: true)
}
}
Here is my EventsDetailViewController, the one that is called when a cell is tapped:
import UIKit
import Parse
import ParseUI
import Bolts
class EventDetailViewController: UIViewController {
#IBAction func eventDetail(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
}
#IBOutlet weak var articleTitle: UILabel!
#IBOutlet weak var writtenBy: UILabel!
#IBOutlet weak var date: UILabel!
#IBOutlet weak var article: UITextView!
#IBOutlet weak var navBar: UINavigationBar!
var dateDetail = [String]()
var articleDetail = [String]()
override func viewDidLoad() {
super.viewDidLoad()
loadEvents()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadEvents () -> Void {
var query = PFQuery(className: "eventsdetail")
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error : NSError?) -> Void in
if error == nil {
if let objects = objects as [PFObject]! {
for object in objects {
var output1 = object.objectForKey("navTitle") as! String
self.navBar.topItem?.title = output1
var output2 = object.objectForKey("articleTitle") as! String
self.articleTitle.text = output2
var output3 = object.objectForKey("written") as! String
self.writtenBy.text = output3
var output4 = object.objectForKey("date") as! String
self.date.text = output4
var output5 = object.objectForKey("article") as! String
self.article.text = output5
}
}
}
}
}
}
Here is my EventsViewController:
import UIKit
import Parse
import Bolts
import ParseUI
class EventsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var timer: NSTimer!
var isAnimating = false
var currentColorIndex = 0
var currentLabelIndex = 0
var customView: UIView!
var labelsArray: Array<UILabel> = []
var refreshControl: UIRefreshControl!
var testArray = [String]()
var subArray = [String]()
#IBOutlet weak var tableview: UITableView!
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
refreshControl = UIRefreshControl()
tableview.delegate = self
tableview.dataSource = self
refreshControl.addTarget(self, action: Selector("loadEvents"), forControlEvents: UIControlEvents.ValueChanged)
self.tableview.addSubview(refreshControl)
loadEvents()
loadCustomRefreshContents()
//refreshControl colors
refreshControl.backgroundColor = UIColor.clearColor() //color of background
refreshControl.tintColor = UIColor.clearColor() //color of indicator
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadEvents () -> Void {
testArray = [String]()
subArray = [String]()
let query = PFQuery(className: "events")
let runkey = query.orderByDescending("eventTitle")
runkey.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error:NSError?) -> Void in
if error == nil {
if let objects = objects as [PFObject]! {
for object in objects {
let load = object.objectForKey("eventTitle") as! String
self.testArray.append(load)
let subload = object.objectForKey("date") as! String
self.subArray.append(subload)
//reload TableView
self.tableview.reloadData()
print(self.testArray)
}
}
} else {
print("error:\(error!) \(error!.userInfo)")
}
}
refreshControl.endRefreshing()
}
func do_table_refresh() {
dispatch_async(dispatch_get_main_queue()) {
self.tableview.reloadData()
return
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
self.performSegueWithIdentifier("0a", sender: nil)
self.tableview.deselectRowAtIndexPath(indexPath, animated: true)
}
}
func tableView(tableView:UITableView!, numberOfRowsInSection section:Int) -> Int {
return testArray.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("eventcell", forIndexPath: indexPath) as! EventTableViewCell
cell.title.text = self.testArray[indexPath.row]
cell.subTitle.text = self.subArray[indexPath.row]
return cell
}
//refreshes tableview; starts refresh
func loadCustomRefreshContents() {
let refreshContents = NSBundle.mainBundle().loadNibNamed("RefreshControl", owner: self, options: nil)
customView = refreshContents[0] as! UIView
customView.frame = refreshControl.bounds
for var i=0; i<customView.subviews.count; ++i {
labelsArray.append(customView.viewWithTag(i + 1) as! UILabel)
}
refreshControl.addSubview(customView)
}
//stops refresh
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
do_table_refresh()
if refreshControl.refreshing {
if !isAnimating {
animateRefreshStep1()
}
}
}
//cycles through colors
func getNextColor() -> UIColor {
var colorsArray: Array<UIColor> = [UIColor.magentaColor(), UIColor.brownColor(), UIColor.yellowColor(), UIColor.redColor(), UIColor.greenColor(), UIColor.blueColor(), UIColor.orangeColor()]
if currentColorIndex == colorsArray.count {
currentColorIndex = 0
}
let returnColor = colorsArray[currentColorIndex]
++currentColorIndex
return returnColor
}
func doSomething() {
timer = NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: "endOfWork", userInfo: nil, repeats: true)
self.do_table_refresh()
}
func endOfWork() {
refreshControl.endRefreshing()
timer.invalidate()
timer = nil
}
//first part of animation
func animateRefreshStep1() {
isAnimating = true
UIView.animateWithDuration(0.1, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[self.currentLabelIndex].transform = CGAffineTransformMakeRotation(CGFloat(M_PI_4))
self.labelsArray[self.currentLabelIndex].textColor = self.getNextColor()
}, completion: { (finished) -> Void in
UIView.animateWithDuration(0.05, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[self.currentLabelIndex].transform = CGAffineTransformIdentity
self.labelsArray[self.currentLabelIndex].textColor = UIColor.blackColor()
}, completion: { (finished) -> Void in
++self.currentLabelIndex
if self.currentLabelIndex < self.labelsArray.count {
self.animateRefreshStep1()
}
else {
self.animateRefreshStep2()
}
})
})
}
//second part of animation
func animateRefreshStep2() {
UIView.animateWithDuration(0.35, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[0].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[1].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[2].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[3].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[4].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[5].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[6].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[7].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[8].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[9].transform = CGAffineTransformMakeScale(1.5, 1.5)
}, completion: { (finished) -> Void in
UIView.animateWithDuration(0.25, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[0].transform = CGAffineTransformIdentity
self.labelsArray[1].transform = CGAffineTransformIdentity
self.labelsArray[2].transform = CGAffineTransformIdentity
self.labelsArray[3].transform = CGAffineTransformIdentity
self.labelsArray[4].transform = CGAffineTransformIdentity
self.labelsArray[5].transform = CGAffineTransformIdentity
self.labelsArray[6].transform = CGAffineTransformIdentity
self.labelsArray[7].transform = CGAffineTransformIdentity
self.labelsArray[8].transform = CGAffineTransformIdentity
self.labelsArray[9].transform = CGAffineTransformIdentity
}, completion: { (finished) -> Void in
if self.refreshControl.refreshing {
self.currentLabelIndex = 0
self.animateRefreshStep1()
}
else {
self.isAnimating = false
self.currentLabelIndex = 0
for var i=0; i<self.labelsArray.count; ++i {
self.labelsArray[i].textColor = UIColor.blackColor()
self.labelsArray[i].transform = CGAffineTransformIdentity
}
}
})
})
}
}
Since you have the data on the tableView just make sure you create a segue in your storyboard connecting the prototype cell and the destination view controller and add an identifier to the segue.
Next, on the controller with the tableView make sure you call:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "segueIdentifier"){
let detailScene = segue.destinationViewController as! EventDetailViewController
if let indexPath = self.tableView.indexPathForSelectedRow {
let row = Int(indexPath.row)
//here you can pass all the data to the destination viewController. But you CANT POPULATE YOUR LABELS. make sure you pass the data to some auxiliar variable(s). Next line is an example
detailScene.selectedData = (self.myData[row] as! PFObject)
}
}
}
Update:
detailScene.selectedData = (self.myData[row] as! PFObject)
detailScene is an instance of the destination viewController. selectedData is, in this case an instance of PFObject that will be use to populate the labels in my destination viewController. self.myData is an array in my source viewController with the data that is shown in my tableView.
So if you want to send the data you show in your cells. (
self.testArray[indexPath.row]
self.subArray[indexPath.row]
) make sure you declare the variables that will receive this data on your EventsDetailViewController something like this:
var testString:String!
var subString:String!
Then in your prepareForSegue (EventsViewController) make sure to instantiate this variables with the proper data:
detailScene.test = self.testArray[row]
detailScene.sub = self.subArray[row]
Finally on EventsDetailViewController you can pass the data to the labels you want on viewDidLoad():
self.articleTitle.text = testString
Let me know in case of any concerns.
What you are asking is the archetypical basic app: show a list of items in a tableview and being able to tap on a row to see more details.
What seems unusual to me is how you have two different classes: events and eventdetails.
Compare it with a database of books. You would not have a Book class and a BookDetails class. You would only have a Book class that contains all details about a book. So when you want to show a list of books, you fetch all the Book objects. In the tableviewcontroller you display a subset of fields from the Book objects (like i.e. title and author). When the user then taps on a specific book, you open a viewcontroller and pass it the Book object for that row. This detail viewcontroller then just shows MORE info/fields from that same Book object.

How would I make a like button?

I am working on making a social media app clone using tutorials for practice in Swift, but I want to add a like button with Parse but not sure how. Does anyone know a tutorial or do you know how you would go about doing this? I attempted to make one like this but I'm pretty sure it is not correct...
I put this in the cell view controller
#IBAction func likeButton(sender: AnyObject) {
a++
var post = PFObject(className: "Post")
post["likes"] = a
}
}
This went into the feed view controller...
var messages = [String]()
var usernames = [String]()
var imageFiles = [PFFile]()
var users = [String: String]()
var likesArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
var query = PFUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
self.messages.removeAll(keepCapacity: true)
self.users.removeAll(keepCapacity: true)
self.imageFiles.removeAll(keepCapacity: true)
self.usernames.removeAll(keepCapacity: true)
self.likesArray.removeAll(keepCapacity: true)
for object in users {
if let user = object as? PFUser {
self.users[user.objectId!] = user.username!
}
}
}
})
var getFollowedUsersQuery = PFQuery(className: "followers")
getFollowedUsersQuery.whereKey("follower", equalTo: PFUser.currentUser()!.objectId!)
getFollowedUsersQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
for object in objects {
var followedUser = object["following"] as! String
var query = PFQuery(className: "Post")
query.whereKey("userId", equalTo: followedUser)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
self.messages.append(object["message"] as! String)
self.imageFiles.append(object["imageFile"] as! PFFile)
self.usernames.append(self.users[object["userId"] as! String]!)
self.likesArray.append(object["likes"] as? String)
self.tableView.reloadData()
}
}
})
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
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 usernames.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell
imageFiles[indexPath.row].getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
myCell.postedImage.image = downloadedImage
}
}
myCell.username.text = usernames[indexPath.row]
myCell.message.text = messages[indexPath.row]
myCell.likeLabel.text = likesArray[indexPath.row]
myCell.selectionStyle = .None
return myCell
}
}
This is the view controller when you post the picture and message...
var likes = 0
var picSelected = false
#IBOutlet var feed: UIButton!
func displayAlert(title: String, message: String) {
var alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
}))
presentViewController(alert, animated: true, completion: nil)
}
var activityIndicator = UIActivityIndicatorView()
#IBOutlet var imageToPost: UIImageView!
#IBAction func chooseImage(sender: AnyObject) {
var image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
image.allowsEditing = false
presentViewController(image, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
dismissViewControllerAnimated(true, completion: nil)
imageToPost.image = image
picSelected = true
}
#IBOutlet var message: UITextField!
#IBAction func postImage(sender: AnyObject) {
if message.text != "" && picSelected != false {
picSelected = false
activityIndicator = UIActivityIndicatorView(frame: view.frame)
activityIndicator.backgroundColor = UIColor(white: 1.0, alpha: 0.5)
activityIndicator.center = self.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.sharedApplication().beginIgnoringInteractionEvents()
var post = PFObject(className: "Post")
post["message"] = message.text
post["userId"] = PFUser.currentUser()?.objectId!
let imageData = UIImagePNGRepresentation(imageToPost.image)
let imageFile = PFFile(name: "image.png", data: imageData)
post["imageFile"] = imageFile
post["likes"] = a
post.saveInBackgroundWithBlock { (success, error) -> Void in
self.activityIndicator.stopAnimating()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
if error == nil {
self.displayAlert("Image Posted!", message: "Your image has been posted successfully.")
self.imageToPost.image = UIImage(named: "Blank-Person1.png")
self.message.text = ""
}
}
} else {
displayAlert("Could Not Post Image!", message: "Please enter a message and/or select a picture.")
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
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.
}
*/
}
I'm about to make Like button like this:
Create Names column in parse ( Array column) to hold names who click on like button
Create Likes column in parse (integer column) to hold count number of Names column
and when someone click on like button add his name to Names Array in parse, If he click it again remove his name
And you need to take all names in NamesArray column and count them in swift then update likes column
i'm not sure but that's in my mind right now, but if you think of it you'll get better way.

Segue to another imageview for fullsize Image

I have a photoview controller that displays images in a table view. I am looking for help to segue to a fullsizeimageview imageview controller. I can't figure out how to do that.
import UIKit
import Parse
import ParseUI
class PhotosViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let arrSubCatData: NSMutableArray = [];
#IBOutlet weak var tblPhotos: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationItem.title = "Photos"
var tabBar : TabBarController = self.tabBarController as! TabBarController
println(tabBar.parkInfo)
self.tblPhotos.tableFooterView = UIView()
var query = PFQuery(className: "MultiImages")
query.whereKey("placeId", equalTo:tabBar.parkInfo?.valueForKey("objectId") as! String)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
self.arrSubCatData.addObjectsFromArray(objects!)
self.tblPhotos?.reloadData();
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("tableViewCell") as! UITableViewCell
if let file:PFFile = (self.arrSubCatData.objectAtIndex(indexPath.row).valueForKey("image") as? PFFile) {
file.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
var imgView : UIImageView = cell.contentView.viewWithTag(100) as! UIImageView
imgView.image = UIImage(data:imageData)
}
}
}
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("segueToInfo", sender: indexPath.row)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrSubCatData.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
/*override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showfullsizeimage" {
if let indexPath = self.tableView.indexPathForSelectedRow() {
let detailViewController = segue.destinationViewController as! PhotoFullSizeController
detailViewController.detailItem = objects[indexPath.row]
}
}
}
*/
/*
// 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.
}
*/
}
My newly created fullsize image controller is like this with segue identifier "fullsizeimageview"
import UIKit
class PhotoFullSizeController: UIViewController {
#IBOutlet weak var fullImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
First of all, You should add TapGesture to the imgView.
Your cellForRowIndexPath will be now as follow :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("tableViewCell") as! UITableViewCell
if let file:PFFile = (self.arrSubCatData.objectAtIndex(indexPath.row).valueForKey("image") as? PFFile) {
file.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
var imgView : UIImageView = cell.contentView.viewWithTag(100) as! UIImageView
//Add Tap Gesture to the imgView
imgView.userInteractionEnabled = true;
let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("imageTapped"))
imgView.addGestureRecognizer(tapRecognizer)
imgView.image = UIImage(data:imageData)
}
}
}
}
return cell
}
Now write a handler for imageTapped
//When image is tapped
func imageTapped()
{
println("image tapped")
self.performSegueWithIdentifier("fullsizeimageview", sender: self)
}
And prepareForSegue will look as follow :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "fullsizeimageview")
{
let destVC = (segue.destinationViewController as? PhotoFullSizeController)!
let indexPath = self.tblPhotos.indexPathForSelectedRow() //IndexPath for selected table row
if let file:PFFile = (self.arrSubCatData.objectAtIndex(indexPath!.row).valueForKey("image") as? PFFile) {
destVC.imageFile = file
}
}
}
In your PhotoFullSizeController controller
class PhotoFullSizeController: UIViewController {
#IBOutlet weak var fullImageView: UIImageView!
var imageFile: PFFile!
override func viewDidLoad() {
super.viewDidLoad()
// Load image
self.imageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
//Set image in imageview
fullImageView.image = UIImage(data:imageData)
}
}
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Let me know if any issue is there. Hope this will help!