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.
Related
I am making an app which has a news feed of images (HomeViewController). The user can tap on each image which segues to the SiteViewController which has a table view of empty data and a button that when clicked segues to ContextSheetViewController where the user can upload data of the image that they clicked on in the news feed. The user then presses upload and this data (siteCodeTextView, areaCodeTextView, trenchTextView) is saved to firebase and it dismisses back to the SiteViewController. I then want to retrieve the data value of siteCodeTextView that has just been uploaded of the image in the table view of the SiteViewController. But when I press upload in the ContextSheetViewController the error: Unexpectedly found nil while unwrapping an Optional value occurs. And my sheetId is printing nil in SiteViewController so I am not sure how to retrieve it correctly? Any help?
Here is my storyboard of relevant view controllers:
Code for SiteViewController:
class SiteViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var sheets = [Sheet]()
var users = [User]()
var sheetId: String!
var postId: String!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
loadSheets()
print(postId)
print(sheetId)
}
func loadSheets() {
Api.Sheet.REF_SHEETS.child(self.postId!).observe(.childAdded, with: {
snapshot in
Api.Sheet.observeSheets(withSheetId: snapshot.key, completion: {
sheet in
// self.fetchUser(uid: sheet.uid!, completed: {
print("sheet id: \(sheet.id)")
print("sheet uid: \(sheet.uid)")
self.sheets.append(sheet)
self.tableView.reloadData()
// })
})
})
}
func fetchUser(uid: String, completed: #escaping () -> Void ) {
Api.User.observeUser(withId: uid, completion: {
user in
self.users.append(user)
completed()
})
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SheetSegue" {
let sheetVC = segue.destination as! SheetViewController
let sheetId = sender as! String
sheetVC.sheetId = sheetId
}
}
}
extension SiteViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sheets.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SheetCell", for: indexPath) as! SiteTableViewCell
let sheet = sheets[indexPath.row]
print("sheet id: \(sheet.id)")
print("sheet uid: \(sheet.uid)")
// let user = users[indexPath.row]
// cell.user = user
cell.sheet = sheet
cell.delegate = self
return cell
}
}
extension SiteViewController: SiteTableViewCellDelegate {
func goToSheetVC(sheetId: String) {
performSegue(withIdentifier: "SheetSegue", sender: sheetId)
}
}
Code for ContextSheetViewController:
class ContextSheetViewController: UIViewController {
#IBOutlet weak var siteCodeTextView: UITextField!
#IBOutlet weak var areaCodeTextView: UITextField!
#IBOutlet weak var trenchTextView: UITextField!
#IBOutlet weak var uploadArtefactImage: UIImageView!
#IBOutlet weak var artefactImageView: UIImageView!
var selectedImage: UIImage?
var postId: String!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.handleSelectPhoto))
uploadArtefactImage.addGestureRecognizer(tapGesture)
uploadArtefactImage.isUserInteractionEnabled = true
}
#objc func handleSelectPhoto() {
let pickerController = UIImagePickerController()
pickerController.delegate = self
present(pickerController, animated: true, completion: nil)
}
#IBAction func uploadButton_TouchUpInside(_sender: Any) {
if let profileImg = self.artefactImageView.image, let imageData = UIImageJPEGRepresentation(profileImg, 0.1) {
let photoIdString = NSUUID().uuidString
print(photoIdString)
let storageRef = Storage.storage().reference(forURL: Config.STORAGE_ROOF_REF).child("sheets").child(photoIdString)
storageRef.putData(imageData, metadata: nil, completion: { (metadata, error) in
if error != nil {
ProgressHUD.showError(error!.localizedDescription)
return
}
let photoUrl = metadata?.downloadURL()?.absoluteString
self.sendDataToDatabase(photoUrl: photoUrl!)
})
} else {
ProgressHUD.showError("Sheet Image can not be empty!")
}
}
func sendDataToDatabase(photoUrl: String) {
// let ref = Database.database().reference()
let sheetsReference = Api.Sheet.REF_SHEETS
// let sheetsReference = ref.child("sheets")
let newSheetId = sheetsReference.childByAutoId().key
let newSheetReference = sheetsReference.child(newSheetId)
guard let currentUser = Auth.auth().currentUser else {
return
}
let currentUserId = currentUser.uid
newSheetReference.setValue(["uid": currentUserId, "photoUrl": photoUrl, "siteCodeTextView": siteCodeTextView.text!, "areaCodeTextView": areaCodeTextView.text!, "trenchTextView": trenchTextView.text!], withCompletionBlock: {
(error, ref) in
if error != nil {
ProgressHUD.showError(error!.localizedDescription)
return
}
let postSheetRef = Api.Sheet.REF_SHEETS.child(self.postId!).child(newSheetId)
// let postSheetRef = Api.Sheet.REF_SHEETS.child("post-sheets").child(self.postId).child(newSheetId)
postSheetRef.setValue(true, withCompletionBlock: { (error, ref) in
if error != nil {
ProgressHUD.showError(error!.localizedDescription)
return
}
})
ProgressHUD.showSuccess("Success")
self.clean()
self.navigationController?.popViewController(animated: true)
})
}
func clean() {
self.siteCodeTextView.text = ""
self.uploadArtefactImage.image = UIImage(named: "upload")
self.artefactImageView.image = UIImage(named: "image")
}
}
extension ContextSheetViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
print("did Finish Picking Media")
if let image = info["UIImagePickerControllerOriginalImage"] as? UIImage{
artefactImageView.image = image
// selectedImage = image
// uploadArtefactImage.image = image
}
dismiss(animated: true, completion: nil)
}
}
Code for SiteTableViewCell:
protocol SiteTableViewCellDelegate {
func goToSheetVC(sheetId: String)
}
class SiteTableViewCell: UITableViewCell {
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var siteSheetLabel: UILabel!
#IBOutlet weak var nameLabel: UILabel!
var delegate: SiteTableViewCellDelegate?
var sheet: Sheet? {
didSet {
updateView()
}
}
var user: User? {
didSet {
setupUserInfo()
}
}
func updateView() {
siteSheetLabel.text = sheet?.siteCodeTextView
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func setupUserInfo() {
nameLabel.text = user?.username
if let photoUrlString = user?.profileImageUrl {
let photoUrl = URL(string: photoUrlString)
profileImageView.sd_setImage(with: photoUrl, placeholderImage: UIImage(named: "placeholderImg"))
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.siteSheetLabel_TouchUpInside))
siteSheetLabel.addGestureRecognizer(tapGesture)
siteSheetLabel.isUserInteractionEnabled = true
}
#objc func siteSheetLabel_TouchUpInside() {
print(sheet?.id)
if let id = sheet?.id{
delegate?.goToSheetVC(sheetId: id)
}
}
override func prepareForReuse() {
super.prepareForReuse()
profileImageView.image = UIImage(named: "placeholderImg")
}
}
From what you have shown the culprit is the postId, you are using it to fetch data from Firebase and yet you haven't shown anywhere what its value is. When the user taps on an image, the postId is not transfered to the SiteViewController.
In the SiteViewController remove the ! and replace it with ?, put an initializer that will take the postID as a parameter.
var postId:String?
func initPost(forImage postId: String) {
self.postId=postId
}
In the previous news feed VC inside the segue or didSelectForRow(i don't know what you use for transition, initialize the SiteViewController, so when it is presented it knows which ID to retrieve data for.
Another thing that needs mentioning is that you are using observe but you are not removing the observers.
EDIT: this answer was based on me not knowing what your HomeVC looked like.
if segue.identifier == "SiteSegue" {
let siteVC = segue.destination as! SiteViewController
let postId = sender as! String
siteVC.postId = postId
}
So, I'm still working on with my poem mobile project.. I'm working on this login module. What's happening here is that it jumps from one ViewController to another ViewController.. maybe it's because of the task? Is there any way to finish all the tasks in the first ViewController before jumping to the second ViewController (TimelineViewController)? Like something to stop it from going to the TimelineViewController if the task in the first ViewController is not yet finish?
I hope someone can help me solve this.. :( Thank you in advance!
This is my ViewController code
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var txtusername: UITextField!
#IBOutlet weak var txtpassword: UITextField!
#IBOutlet weak var lblResult: UILabel!
var returnVal:String? = nil
#IBOutlet weak var btnLogin: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnLogin_Tapped(sender: UIButton) {
let url:NSURL = NSURL(string: "http://192.168.1.6/Test/login.php")!
let request:NSMutableURLRequest = NSMutableURLRequest(url:url as URL)
let bodyData = "username=\(txtusername.text!)&password=\(txtpassword.text!)"
request.httpMethod = "GET"
request.httpBody = bodyData.data(using: String.Encoding.utf8);
// NSURLConnection.sendAsynchronousRequest(request as URLRequest, queue: OperationQueue.main){(response, data, error) in
//print(response)
// }
let task = URLSession.shared.dataTask(with: request as URLRequest)
{
data, response, error in
guard let data = data, error == nil else {
print ("Error = \(error?.localizedDescription ?? "Unknown error")")
return
}
if let response = response {
print ("Response = \(response)")
}
if let responseString = String(data: data, encoding: .utf8) {
print ("Response data = \(responseString)")
}
//Converting response to NSDictionary
guard let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments),
let responseObject = json as? String,
let returnValidation = responseObject as? String else {
print("did not validate")
return
}
DispatchQueue.main.async()
{
self.returnVal = returnValidation
print("RETURN VALUE: \(self.returnVal!)")
self.performSegue(withIdentifier: "signinSegue", sender: self)
}
}
task.resume()
}
func AlertMessage(titleA: String, messageA: String)
{
let alert = UIAlertController(title: titleA, message: messageA, preferredStyle: UIAlertControllerStyle.alert)
let alertAction = UIAlertAction(title: "Ok", style:UIAlertActionStyle.default){(UIAlertAction)-> Void in }
alert.addAction(alertAction)
present(alert, animated: true){() -> Void in}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "signinSegue")
{
if(self.returnVal != nil)
{
if(self.returnVal! == "true")
{
let viewController = segue.destination as! TimelineViewController
viewController.passedValue = self.returnVal!
viewController.viewDidLoad()
}
else if (self.returnVal! == "false")
{
print("Incorrect Password!")
}
}
else
{
print("Empty")
}
}
}
}
This is my TimelineViewController code
import UIKit
import Foundation
struct Poem {
let poemTitle: String
let poemBody: String
init?(dictionary: [String: Any]) {
guard let poemTitle = dictionary["Title"] as? String,
let poemBody = dictionary["Body"] as? String else {
print("Did not find fullName/Bio")
return nil
}
self.poemTitle = poemTitle
self.poemBody = poemBody
}
}
class TimelineViewController: UIViewController {
#IBOutlet weak var contentTableView: UITableView!
#IBOutlet weak var poemBodyText: UITextView!
#IBOutlet weak var poemTitleText: UILabel!
var poems = [Poem]()
var passedValue:String? = nil
#IBOutlet weak var oPostBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
if(passedValue != nil)
{
getPoems()
}
else {
print("Empty")
}
}
func getPoems()
{
let url = URL(string: "http://192.168.1.6/Test/feed1.php")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request as URLRequest)
{
data, response, error in
guard let data = data, error == nil else {
print("Error = \(error?.localizedDescription ?? "Unknown error")")
return
}
if let response = response {
print("Response = \(response)")
}
if let responseString = String(data: data, encoding: .utf8){
print ("Response data = \(responseString)")
}
//Converting response to NSDictionary
guard let json = try? JSONSerialization.jsonObject(with: data),
let responseObject = json as? [String:Any],
let returnPoems = responseObject["returnPoems"] as? [[String:Any]] else {
print ("Did not find return Poems")
return
}
print (returnPoems)
DispatchQueue.main.async {
self.poems = returnPoems.flatMap { Poem(dictionary: $0) }
self.contentTableView.reloadData() }
}
task.resume()
}
/* override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}*/
func AlertMessage(titleA: String, messageA: String)
{
let alert = UIAlertController(title: titleA, message: messageA, preferredStyle: UIAlertControllerStyle.alert)
let alertAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default){(UIAlertAction)-> Void in }
alert.addAction(alertAction)
present(alert, animated: true){() -> Void in}
}
#IBAction func aPostBtn(_ sender: Any) {
var count = 0
while(count < 2)
{
//print("RESPONSE!!! : \(poemTitle[count])")
count = count + 1;
}
}
}
extension TimelineViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = contentTableView.dequeueReusableCell(withIdentifier: "PoemTableViewCell", for: indexPath) as? PoemTableViewCell else
{
fatalError("The dequeued cell is not an instance of PoemTableViewCell")
}
let poem = poems[indexPath.row]
cell.poemTitleText?.text = poem.poemTitle
cell.poemBodyText?.text = poem.poemBody
// cell.textLabel?.text = poem.poemTitle
// cell.detailTextLabel?.text = poem.poemBody
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return poems.count
}
func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
let poem = poems[indexPath.row]
print(poem)
}
}
In btnLogin_Tapped remove DispatchQueue.main.async(). I don't see why you would need this. It creates a new queue and execute the code inside it asynchronously.
Also remove viewController.viewDidLoad(). You should never call viewDidLoad yourself, it is called automatically when the new view controller appears.
Another thing that might be causing a problem is if you've created a segue in your Storyboard (Ctrl + drag) from the login button to your TimelineViewController. You should remove it as you perform the segue at the end of btnLogin_Tapped.
when I select UIButoon(selectMaghsad or selectMabda) go AircraftSearch to SelectedCity without difficulty and problem I choose one cell in selecteCity(tableviewController) go back to AircraftSearch and show data in label (labelcity) The problem is that Without that I want again go to tableViewController(selecteCity)
and alert :
A
Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSUnderlyingError=0x7f867b5a4920 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}}
why ??
Where do you think the problem is?
can you help me ??
AircraftSearch
class AircraftSearch: UIViewController ,SendbackDelegate{
#IBOutlet weak var Mabda: UIButton!
#IBOutlet weak var maghsad: UIButton!
#IBOutlet weak var labelcity: UILabel!
#IBOutlet weak var cityTectfield: UITextField!
var Airurl = NSURL()
var ScrOrDstArray = [MabdaAndMaghsad]()
var origin = [String]() // save mabda
var purpose = [String]() // save maghsad
var sendDataToTableview = [String]()
var tit = String()
override func viewDidLoad() {
super.viewDidLoad()
labelcity.text = tit
GetPassCity()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func selectMabda(sender: AnyObject) {
sendDataToTableview = origin
performSegueWithIdentifier("SelectedCellSegue", sender: sender)
}
#IBAction func selectMaghsad(sender: AnyObject) {
sendDataToTableview = purpose
print(sendDataToTableview)
performSegueWithIdentifier("SelectedCellSegue", sender: sender)
}
func originAndpurpose() {
let dataCity = ScrOrDstArray
for i in dataCity{
if i.SrcOrDst == true{
origin.append(i.Name)
}else{
purpose.append(i.Name)
}
}
}
func GetPassCity(){
let actInd : UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRectMake(0,0, 50, 50)) as UIActivityIndicatorView
actInd.center = self.view.center
actInd.hidesWhenStopped = true
actInd.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
view.addSubview(actInd)
actInd.startAnimating()
NSURLSession.sharedSession().dataTaskWithURL(Airurl){ ( data ,response ,error) in
if error != nil{
print("A")
print(error!)
}else{
do{
//readin data from Server
let posts = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! [[String:AnyObject]]
//save data
for post in posts{
var postCity:MabdaAndMaghsad?
if let Id = post["Id"] as? Int ,
let nameCity = post["Name"] as? String ,
let SrcOrDst = post["SrcOrDst"] as? Bool
{
postCity = MabdaAndMaghsad(ID: Id, Name: nameCity, SrcOrDst: SrcOrDst)
}
self.ScrOrDstArray.append(postCity!)
}
//===============
dispatch_async(dispatch_get_main_queue()){
actInd.stopAnimating()
self.originAndpurpose()
print(self.origin)
print("=======")
// print(self.purpose)
}
}catch let error as NSError{
print("B")
print(error)
}
}
}.resume()
}
func sendNameToPreviousVC(SelectCity: String) {
tit = SelectCity
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SelectedCellSegue" {
if let VC = segue.destinationViewController as? SelectedCity {
VC.toTake = sendDataToTableview
VC.delegate = self
}
}
}
}
SelectedCity view
import UIKit
protocol SendbackDelegate:class {
func sendNameToPreviousVC(City:String)
}
class SelectedCity: UITableViewController {
var toTake = [String]()
var selecteCity = String()
weak var delegate: SendbackDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(false, animated: true)
}
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 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 toTake.count ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("stcell", forIndexPath: indexPath) as? mAndMCell
let nameCity = toTake[indexPath.row]
print(nameCity)
cell!.nameCityLabel.text = nameCity
return cell!
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as! mAndMCell!
selecteCity = currentCell.nameCityLabel!.text as String!
sendBackIdCity(selecteCity)
navigationController?.popViewControllerAnimated(true)
}
func sendBackIdCity(name: String){
self.delegate?.sendNameToPreviousVC(name)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "backCitySegue"{
var VCOne = segue.destinationViewController as? AircraftSearch
self.delegate = VCOne
}
}
}
pic
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.
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)
}