Swift Sending Label Text on Button Click as Parse Object Value - ios

I have a custom tableview cell that displays a Parse users profile image, username label and a button to add them as a "following" object within my Followers class. My relation setup is set as the "follower" within my "Followers" class as the username of the current user and the "following" as the username of the tableview cell that the "add friend" button was clicked. The way I am currently trying to achieve this is add a tag to the button that is set to indexPath.row and then adding a target and IBAction. From there I set the label view with a tag value of 1 and then try to set that label as a usernameLabel variable which I can use to set to the "following" column. Unfortunately my current solution, following["following"] = usernameLabel.text as PFObject gives me 'UIView? is not convertible to 'PFObject'. Is this the best way to achieve what I'm looking to do and any idea why this error is happening?
Here is my tableview cell:
import UIKit
class SearchUsersRegistrationTableViewCell: UITableViewCell {
#IBOutlet var userImage: UIImageView!
#IBOutlet var usernameLabel: UILabel!
#IBOutlet weak var addUserButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
userImage.layer.borderWidth = 1
userImage.layer.masksToBounds = false
userImage.layer.borderColor = UIColor.whiteColor().CGColor
userImage.layer.cornerRadius = userImage.frame.width/2
userImage.clipsToBounds = true
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Here is my tableview functionality. (Note that this is a view controller with a tableview element):
import UIKit
class SearchUsersRegistrationViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var userArray : NSMutableArray = []
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
loadParseData()
var user = PFUser.currentUser()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadParseData() {
var query : PFQuery = PFUser.query()
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
if let objects = objects {
println("\(objects.count) users are listed")
for object in objects {
self.userArray.addObject(object)
}
self.tableView.reloadData()
}
} else {
println("There is an error")
}
}
}
let textCellIdentifier = "Cell"
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.userArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! SearchUsersRegistrationTableViewCell
let row = indexPath.row
var individualUser = userArray[row] as! PFUser
var username = individualUser.username as String
var profileImage = individualUser["profileImage"] as! PFFile
profileImage.getDataInBackgroundWithBlock({
(result, error) in
cell.userImage.image = UIImage(data: result)
})
cell.usernameLabel.text = username
cell.addUserButton.tag = row
cell.addUserButton.addTarget(self, action: "addUser:", forControlEvents: .TouchUpInside)
return cell
}
#IBAction func addUser(sender: UIButton){
let usernameLabel = sender.superview?.viewWithTag(1)
var following = PFObject(className: "Followers")
following["following"] = usernameLabel.text as PFObject
following["follower"] = PFUser.currentUser().username //Currently logged in user
following.saveInBackground()
/* if let surtv = tableView.objectAtIndex(sender.tag) as? SearchUsersRegistrationTableViewCell {
surtv.usernameLabel = sender.tag as! String
var following = PFObject(className: "Followers")
following["following"] = usernameLabel.text
following["follower"] = PFUser.currentUser().username //Currently logged in user
following.saveInBackground()
}*/
}
#IBAction func finishAddingUsers(sender: AnyObject) {
self.performSegueWithIdentifier("finishAddingUsers", sender: self)
}
}

You shouldn't really be using tags to try to navigate around like this. I know it's tempting, but it's cheating and leads to this kind of problem. It's also encouraging you to use your view as data storage which is also wrong.
You already have your custom cell class SearchUsersRegistrationTableViewCell, so you should leverage that. Give it a property to hold the individualUser. Now at least you can get the user back from the cell when the button is tapped.
Better is to have the cell update the user when the button is tapped, so you don't need to call back to the controller at all.
Better still is to create a custom class which holds the individualUser and the logic to apply the new follower and give that to the custom cell, then the cell asks that object for the individualUser info and tells that object when to add the follower. This is a better separation of knowledge and logic.

Related

Make a tableView that shows previous user inputs (in other views)

I'm stack doing my first app, I searched a lot of tutorials about tableviews, arrays and segues but I can't even figure it out how to resolve my problem, here I go:
I need that the app store a value in an array (class) so I can access it latter (not in the next segue), I did a different app more simple than the last one, just with a UITextfield input and a button to add it to the class. When I move from the user input part to the tableView, the tableView is empty. I will put the code here:
TABLE VIEWCONTROLLER
import UIKit
class NameTableViewController: UITableViewController {
var names = [Name]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in 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 names.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "NameTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath) as? NameTableViewCell else {
fatalError("The dequeueReusable cell is not an instance of NameTableViewCell")
}
let name = names[indexPath.row]
cell.nameLabel.text = name.name
return cell
}
USER INTERFACE VIEWCONTROLLER:
import UIKit
class ViewController: UIViewController {
var name = [Name]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBOutlet weak var nameTextField: UITextField!
#IBAction func addingButton(_ sender: UIButton) {
let writtenName = nameTextField.text ?? "No name written"
let name1 = Name(name: writtenName)
name.append(name1)
}
}
<!-- end snippet -->
VIEWCELL:
class NameTableViewCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
<!-- end snippet -->
NAME CLASS METHOD:
class Name {
var name: String
init(name: String) {
self.name = name
}
}
!-- end snippet -->
TableView
User Input
Sorry if this is a dumb question, as you may have notice I'm new programming and swift is the first language that I'm learning.
You can use nsuserdefaults https://developer.apple.com/documentation/foundation/nsuserdefaults and store a key decodable struct and later on call it everywhere.
// Save Data
struct People: Codable {
let name: String?
}
var peopleArray = [People]()
let mike = People(name: "mike")
peopleArray.append(mike)
UserDefaults.standard.set(peopleArray, forKey: "people")
// Request Stored Data
func getPeople() -> [People]?{
let myPeople = UserDefaults.standard.data(forKey: "people")
if myPeople == nil {
return nil
}
let peopleArray = try! JSONDecoder().decode([People].self, from: myPeople!)
return peopleArray
}
let people = getPeople()
if(people != nil){
for person in people {
print(person.name)
}
}

Detect Taps in Different areas of a tableViewCell

this one has me pretty well stumped so hoping someone can help. I have a tableview that has a custom cell with 3 labels and 2 buttons. If a user taps the label, i use didSelectRowAtIndexPath to set a variable from an array (i.e. variable = array[indexPath.row]) and then perform a segue, passing the info from the variable to a new VC with prepareForSegueWithIdentifier - this works fine and all is well in the world.
I'd like to implement the same functionality for the button within the same cell, however I'm having trouble detecting which row was tapped. I've tried an IBAction from the button where i code "func didSelectRowAtIndexPath" a second time, and it kind of works but the row is inaccurate (for example, it'll pass info for a cell a few below the one I actually tapped) -- I also tried a global variable that would get the row from the original didSelectRowAtIndexPath function but that had similar results.
What is the best practices for doing this? Is there another way to get the row i tapped from a second place within the tableView? Should i have used another label instead of a button?
Any help/ideas is greatly appreciated. Happy to post my code as well if need. Thank you!!
import UIKit
import Parse
var rowNumber:Int = 0
class FeedTableViewController: UITableViewController {
var postToWeb:String = ""
var usernames = [String]()
var linkArr = [String]()
var titleArray = [String]()
var users = [String: String]()
var createdAt = [String]()
var userList: [User] = []
var sortedArticles: [User] = []
var commentUrl:String = ""
var commentTitle: String = ""
var commentUser:String = ""
struct User {
var date:NSDate
var username:String
var url:String
var title:String
}
let cellSpacingHeight: CGFloat = 10
class commentButtonClass: UIButton {
var section:Int = 0
}
#IBAction func commentButtonPressed(sender: AnyObject) {
commentTitle = self.userList[rowNumber].title
commentUrl = userList[rowNumber].url
commentUser = (PFUser.currentUser()?.username)!
performSegueWithIdentifier("commentView", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
var query = PFUser.query()
query?.orderBySortDescriptor(NSSortDescriptor(key: "createdAt", ascending: false))
query?.findObjectsInBackgroundWithBlock({ (objects, error) in
if let users = objects {
self.usernames.removeAll(keepCapacity: true)
self.linkArr.removeAll(keepCapacity: true)
self.titleArray.removeAll(keepCapacity: true)
self.createdAt.removeAll(keepCapacity: true)
for object in users {
if let user = object as? PFUser {
self.users[user.objectId!] = user.username!
}
}
}
let getFollowedUsersQuery = PFQuery(className: "followers")
getFollowedUsersQuery.whereKey("follower", equalTo: PFUser.currentUser()!.objectId!)
getFollowedUsersQuery.orderBySortDescriptor(NSSortDescriptor(key: "createdAt", ascending: false))
getFollowedUsersQuery.findObjectsInBackgroundWithBlock { (objects, error) in
if let objects = objects {
for object in objects {
let followedUser = object["following"] as! String
let query = PFQuery(className: "posts")
query.whereKey("userId", equalTo: followedUser)
query.orderBySortDescriptor(NSSortDescriptor(key: "createdAt", ascending: false))
query.findObjectsInBackgroundWithBlock({ (objects, error) in
//create a struct with createdAt as struct name since will be unique majority of time if include time and date.
if let objects = objects {
for object in objects {
let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = NSDateFormatterStyle.MediumStyle
dateFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
let dateString = dateFormatter.stringFromDate(object.createdAt!)
self.userList.append(User(date: object.createdAt!, username:self.users[object["userId"] as! String]!, url: object["linkURL"] as! String, title: object["title"] as! String))
self.userList.sortInPlace{ $0.date.compare($1.date) == NSComparisonResult.OrderedDescending }
self.tableView.reloadData()
}
}
})
}
}
}
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Set the spacing between sections
override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return cellSpacingHeight
}
// Make the background color show through
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = UIColor.clearColor()
return headerView
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return userList.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell
let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = NSDateFormatterStyle.MediumStyle
dateFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
let dateString = dateFormatter.stringFromDate(self.userList[indexPath.section].date)
myCell.titleLabel.text = self.userList[indexPath.section].title
myCell.userLabel.text = self.userList[indexPath.section].username
myCell.createdDateLabel.text = dateString
myCell.rowNumberLabel.tag = indexPath.section
// add border and color
myCell.backgroundColor = UIColor.whiteColor()
myCell.layer.borderColor = UIColor.clearColor().CGColor
myCell.layer.borderWidth = 2
myCell.layer.cornerRadius = 0
myCell.clipsToBounds = true
return myCell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell!;
rowNumber = indexPath.section
postToWeb = userList[indexPath.section].url
print(postToWeb)
performSegueWithIdentifier("webView", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "webView") {
// initialize new view controller and cast it as your view controller
let vc = segue.destinationViewController as! WebViewController
// your new view controller should have property that will store passed value
vc.passedValue = postToWeb
}
if (segue.identifier == "commentView") {
let commentVc = segue.destinationViewController as! commentsViewController
commentVc.passedCommentTitle = commentTitle
commentVc.passedCommentUrl = commentUrl
commentVc.passedCommentUsername = commentUser
}
}
in the above, the segue to "webView" works perfectly and the data is passed. In the commentView - data is passed, but it's incorrect.
To get the UITableViewCell that was tapped (as an Action of the Button), you have different options:
1) Use Target-Action method, something like:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell
//...More Code
myCell.myBtn.addTarget(self, action: "myActionMethod:", forControlEvents: .TouchUpInside)
//... More Code
return myCell
}
And then define your action method (note, yourTbl is an instance of UITableView):
func myActionMethod(sender:UIButton){
//base on the hierarchy of the UI
//Suppose in this case:
//(UITableView)->(UITableViewCell)->(ContentView)->UIButton then:
if let tableViewCell = sender.superview?.superview as? UITableViewCell, indexPath = yourTbl.indexPathForCell(tableViewCell){
//Here you have the IndexPath
}
}
2) The same Idea, but basically your going to set the Tag property of the UIButton (to your row cell), and using Target-Action on the sender (parameter) you get the tag of the button.
Update Sample:
https://github.com/Abreu0101/SampleTargetActionMethod
What is the best practices for doing this?
You need you delegate pattern. See below example.
The CustomTableViewCell class:
protocol CustomTableViewCellDelegate {
func customTableViewCell(cell: CustomTableViewCell, didTextInLabelChanged text: String)
}
class CustomTableViewCell: UITableViewCell {
var delegate: CustomTableViewCellDelegate?
func handeLabelTextChanged(text: String) {
delegate?.customTableViewCell!(self, didTextInLabelChanged: text)
}
// ... some other code
}
The CustomViewController class:
class CustomViewController {
// some code
}
class CustomViewController: UITableViewDataSource {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = // dequeue the right cell
cell.delegate = self
return cell
}
}
class CustomViewController: CustomTableViewCellDelegate {
func customTableViewCell(cell: CustomTableViewCell, didTextInLabelChanged text: String) {
// do tableView update with changed text
}
}
As you see all "changed" (or "tapped", or whatever) logic is going on in you cell. To notify controller about this changes you simply create a protocol with all methods what you need (in this case i notify my controller about text in label changed), then you need to create a var delegate: YourDelegate? and call it where you need. Next step you need implement "handle" function in your controller. It's very simple. You just need implement the customTableViewCell() function from CustomTableViewCellDelegate and also set the delegate variable to self for CustomTableViewCell.
UPDATE
When a user taps a button within the cell, i need the specific info from that cell, based on the indexPath.row
Very easy. Remember that in your controller you implement the CustomTableViewCellDelegate? So, to get specific info from cell you can do this:
class CustomViewController: CustomTableViewCellDelegate {
func customTableViewCell(cell: CustomTableViewCell, didTextInLabelChanged text: String) {
// here you get `someVariable` from your cell.
// where `someVariable` you set in the `cellForRowAtIndexPath` controller's
// method
let info = cell.someVariable
// or, if for some reason you not save in your cell some data,
// but you need the `indexPath.row` to get this data you
// can find this `indexPath` like this:
if let indexPath = tableView.indexPathForCell(cell) {
let number = youArrayOfNumbers[indexPath.row]
}
}
}

SWIFT: Difficultly displaying data in tableView

I am attempting to display data from Parse onto the following tableView controller. For some reason, the data is not displaying on the tableView (i.e. the rows are blank). I do not think that the data queried from Parse is being appended to the arrays. I am wondering what I'm doing wrong here.
Here's the current output:
I am using a custom prototype cell with identifier "CellTrack" class "TrackTableViewCell" and as shown below:
Here is my code in the TableViewController file:
import UIKit
import Parse
class MusicPlaylistTableViewController: UITableViewController {
var usernames = [String]()
var songs = [String]()
var dates = [String]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
var query = PFQuery(className:"PlaylistData")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects! as? [PFObject] {
self.usernames.removeAll()
self.songs.removeAll()
self.dates.removeAll()
for object in objects {
let username = object["username"] as? String
self.usernames.append(username!)
print("added username")
let track = object["song"] as? String
self.songs.append(track!)
let date = object["createdAt"] as? String
self.dates.append(date!)
self.tableView.reloadData()
}
}
} else {
print(error)
}
}
}
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 usernames.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CellTrack", forIndexPath: indexPath) as! TrackTableViewCell
cell.username.text = usernames[indexPath.row]
cell.songTitle.text = songs[indexPath.row]
cell.CreatedOn.text = dates[indexPath.row]
return cell
}
}
And here is my code in the "TrackTableViewCell.swift" class:
import UIKit
class TrackTableViewCell: UITableViewCell {
#IBOutlet weak var songTitle: UILabel!
#IBOutlet weak var username: UILabel!
#IBOutlet weak var CreatedOn: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Execute your tableView.reloadData() in main thread.
dispatch_async(dispatch_get_main_queue(), {
self.tableViewCell.reloadData()
})
Try doing a guard let to see if those values are actually coming back as string or not. My guess would be that the value for created at never came back. Try it out and let me know.
guard let username = object["username"] as? String else {
print ("could not get username")
}
self.usernames.append(username)
print("added username")
guard let track = object["song"] as? String else {
print ("could not get song")
return
}
self.songs.append(track)
guard let date = object["createdAt"] as? String else {
print ("could not get createdAt")
return}
self.dates.append(date!)
func dequeueReusableCellWithIdentifier(_ identifier: String) -> UITableViewCell?
Return Value
A UITableViewCell object with the associated identifier or nil if no such object exists in the reusable-cell queue.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CellTrack", forIndexPath: indexPath) as! TrackTableViewCell
if cell == nil {
// create a new cell here
cell = TrackTableViewCell(...)
}
cell.username.text = usernames[indexPath.row]
cell.songTitle.text = songs[indexPath.row]
cell.CreatedOn.text = dates[indexPath.row]
return cell
}

Swift Use of Unresolved Identifier 'IndexPath' TableView Cell Button

I am attempting to get the text of my UILabel and set it to my Parse object, but I am running into an issue setting the object to the index path of the cell. I am getting an Use of unresolved identifier 'indexPath' error at that line.
follow["following"] = self.userArray.objectAtIndex(IndexPath.row)
Here is my tableview controller:
import UIKit
class SearchUsersRegistrationTableViewController: UITableViewController {
var userArray : NSMutableArray = []
override func viewDidLoad() {
super.viewDidLoad()
var user = PFUser.currentUser()
loadParseData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: SearchUsersRegistrationTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! SearchUsersRegistrationTableViewCell
let row = indexPath.row
var individualUser = userArray[row] as! PFUser
var username = individualUser.username as String
var profileImage = individualUser["profileImage"] as? PFFile
if profileImage != nil {
profileImage!.getDataInBackgroundWithBlock({
(result, error) in
cell.userImage.image = UIImage(data: result)
})
} else {
cell.userImage.image = UIImage(named: "profileImagePlaceHolder")
}
cell.usernameLabel.text = username
cell.addUserButton.tag = row
cell.addUserButton.addTarget(self, action: "addUser:", forControlEvents: .TouchUpInside)
return cell
}
func loadParseData() {
var query : PFQuery = PFUser.query()
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
if let objects = objects {
println("\(objects.count) users are listed")
for object in objects {
self.userArray.addObject(object)
}
self.tableView.reloadData()
}
} else {
println("There is an error")
}
}
}
#IBAction func addUser(sender: UIButton) {
println("Button Triggered")
let addUserButton : UIButton = sender
let user : PFObject = self.userArray.objectAtIndex(addUserButton.tag) as! PFObject
var follow = PFObject(className: "Follow")
follow["following"] = self.userArray.objectAtIndex(IndexPath.row)
follow["follower"] = PFUser.currentUser().username
follow.saveInBackground()
}
}
Here is my tableview cell:
import UIKit
class SearchUsersRegistrationTableViewCell: UITableViewCell {
#IBOutlet weak var userImage: UIImageView!
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var addUserButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
userImage.layer.borderWidth = 1
userImage.layer.masksToBounds = false
userImage.layer.borderColor = UIColor.whiteColor().CGColor
userImage.layer.cornerRadius = userImage.frame.width/2
userImage.clipsToBounds = true
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Try this
follow["following"] = self.userArray.objectAtIndex(sender.tag)
You are setting the row as tag for your button. Just use it.
you should not work with tags in that case.
to get the indexpath in your addUser function add the following:
let indexPath = tableView.indexPathForRowAtPoint(addUserButton.convertPoint(CGPointZero, toView: tableView))
then you can use that line:
follow["following"] = self.userArray.objectAtIndex(indexPath.row)
indexPath, not IndexPath

Swift Adding Button Action to TableView Cell

I'm trying to create a button within my custom tableview cell that has the action of creating a Parse class if it isn't already created and applying the text of the label of the row that the button clicked occurred as the value for the "following" column and set the "follower" column value as the username of the current loggedin user. Currently I have an error at the let usernameLabel in the addUser IBAction that my Class does not have a member named objectAtIndex. What is the best way to achieve what I'm looking for?
I have created the outlets in SearchUsersRegistrationTableViewCell.swift
import UIKit
class SearchUsersRegistrationTableViewCell: UITableViewCell {
#IBOutlet var userImage: UIImageView!
#IBOutlet var usernameLabel: UILabel!
#IBOutlet weak var addUserButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
userImage.layer.borderWidth = 1
userImage.layer.masksToBounds = false
userImage.layer.borderColor = UIColor.whiteColor().CGColor
userImage.layer.cornerRadius = userImage.frame.width/2
userImage.clipsToBounds = true
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Here is my table functionality and the action that I tried to apply to my addUserButton:
import UIKit
class SearchUsersRegistrationViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var userArray : NSMutableArray = []
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
loadParseData()
var user = PFUser.currentUser()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadParseData() {
var query : PFQuery = PFUser.query()
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
if let objects = objects {
println("\(objects.count) users are listed")
for object in objects {
self.userArray.addObject(object)
}
self.tableView.reloadData()
}
} else {
println("There is an error")
}
}
}
let textCellIdentifier = "Cell"
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.userArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! SearchUsersRegistrationTableViewCell
let row = indexPath.row
var individualUser = userArray[row] as! PFUser
var username = individualUser.username as String
var profileImage = individualUser["profileImage"] as! PFFile
profileImage.getDataInBackgroundWithBlock({
(result, error) in
cell.userImage.image = UIImage(data: result)
})
cell.usernameLabel.text = username
cell.addUserButton.tag = row
cell.addUserButton.addTarget(self, action: "addUser:", forControlEvents: .TouchUpInside)
return cell
}
#IBAction func addUser(sender: UIButton){
let usernameLabel = self.objectAtIndex(sender.tag) as! String
var following = PFObject(className: "Followers")
following["following"] = usernameLabel.text
following["follower"] = PFUser.currentUser().username //Currently logged in user
following.saveInBackground()
}
#IBAction func finishAddingUsers(sender: AnyObject) {
self.performSegueWithIdentifier("finishAddingUsers", sender: self)
}
}
I'm assuming the usernameLabel is on the same contentView as the UIButton sender. If that's the case you can add a tag to the usernameLabel and do this
let usernameLabel = sender.superview.viewWithTag(/*Put tag of label here*/)
I'm on a mobile so I don't know if viewWithTag is the right name of the method, but it's something similar.
hope this helps.
You are getting the error because you are using self instead of tableView
let usernameLabel = self.objectAtIndex(sender.tag) as! String
let usernameLabel = tableView.objectAtIndex(sender.tag) as! String
However, this will still give you an error because UITableViewCell cannot be cast as a String.
This is a better option:
if let surtvc = tableView.objectAtIndex(sender.tag) as? SearchUsersRegistrationTableViewCell {
// surtvc.usernameLabel...
// the rest of your code goes here
}

Resources