I would like to implement an IBAction in a tableViewCell.
The tableView dysplay a list of users, and for each user, i have a follow button.
The follow method needs to specify the user to follow witch is the cell's user.
How could i do this ?
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: AddFirendsTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)as AddFirendsTableViewCell
let users:PFObject = self.userList.objectAtIndex(indexPath.row) as PFObject
return cell
}
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let users:PFObject = self.userList.objectAtIndex(indexPath.row) as PFObject
}
#IBAction func followUnfollow(sender: AnyObject) {
//what should i put here ?
}
func follow (user :PFUser) {
var relation : PFRelation = PFUser.currentUser().relationForKey("KfriendsRelation")
relation.addObject(user)
PFUser.currentUser().saveInBackgroundWithBlock { (succeed:Bool, error: NSError!) -> Void in
if error != nil {
println(error)
}
}
}
I'm a little confused on how you are going about it, though I will just run with it for a moment. In order to get a reference to a cell, you could use the following line:
let indexPath = tableView.indexPathForRowAtPoint(buttonPosition)
You could then use the index path to get a reference to the cell, and therefore do what you like with it:
let cell = tableView.cellForRowAtIndexPath(indexPath)
However, i would personally move the IBAction into the cells subclass of AddFirendsTableViewCell where you already have access to all of the cells variables and values. This then means that every cell will work the same and you won't have to do some weird work-around to try and find out which button got pressed. But, that is just my opinion. Hopefully this will have helped.
Related
I am creating a UITableView that enables the user to add a variable amount of data. Table looks like this initially:
When the user clicks on the "+" button, i would like to add a new cell with a UITextField for entering data. This new cell is a Custom UITableViewCell called "RecordValueCell". Here's what is looks like:
//Custom UITableViewCell
class RecordValueCell : UITableViewCell {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var deleteButton: UIButton!
var onButtonTapped : ((_ sender : UIButton)->Void)?
#IBAction func deleteButtonTouched(_ sender: Any) {
guard let senderButton = sender as? UIButton else {
return
}
onButtonTapped?(senderButton)
}
}
However when i try to add another cell, using the tableView.dequeueReusableCell(withIdentifier: ) function, it seems to return the same cell. And here is what my UI looks like:
Empty space at the top of the section where my new cell should be. Here is the code to add the cell:
func addNewValueCell() {
guard let reusableValueCell = self.tableView.dequeueReusableCell(withIdentifier: "valueCell") as? RecordValueCell else {
fatalError("failed to get reusable cell valueCell")
}
var cell = Cell() //some custom cell Object
//add the gray horizontal line you see in the pictures
reusableValueCell.textField.addBorder(toSide: .Bottom, withColor: UIColor.gray.cgColor, andThickness: 0.5)
reusableValueCell.onButtonTapped = { (sender) in
self.removeValue(sender: sender)
}
cell.cell = reusableValueCell
self.sections[self.sections.count - 1].cells.insert(cell, at: 0)
//When i put a break point at this spot, i find that reusableValueCell is the same object as the cell that is already being used.
tableView.reloadData()
reusableValueCell.prepareForReuse()
}
When i debug it, i find that dequeueReusableCell(withIdentifier: ) returns the exact same RecordValueCell multiple times.
Here is my cellForRowAt:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = self.sections[indexPath.section].cells[indexPath.row].cell else {
fatalError("error getting cell")
}
return cell
}
numberOfRowsInSection
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.sections[section].cells.count
}
First of all, you will need to set the View Controller Class that this table is contained in as the table's UITableViewDataSource
tableView.dataSource = self // view controller that contains the tableView
Create an array of strings as member of your View Controller class which contains the data for each cell:
var strings = [String]()
Then you will need to implement the following method for the UITableViewDataSource protocol:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return strings.count
}
You should also be dequeueing the cells in your cellForRowAt method like so:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: yourIdentifier) as! YourCellClass
cell.textLabel = strings[indexPath.row]
return cell
}
Then whenever the user enters into the textField, their input will be appended to this array:
let input = textField.text
strings.append(input)
tableView.reloadData()
Once the data is reloaded, the cell will be added to the table automatically since the number of rows are defined by the String array's length and the label is set in the cellForRowAt method.
This feature is very easy to implement if you will do in a good way.
First, you have to create two TableCell. First to give the option to add a record with plus button and second for entering a value with textfield. Now always return first cell (AddRecordTableCell) in the last row in tableView, and return the number of rows according to entered values like
return totalValues.count + 1
I have a UITableViewController with UITableViewCell dynamically generated there. Each cell contains an imageView that I'm filling with images fetched from my server. I'm using alamofire_images to do so. My code looks as follows:
func tableView(testDetailsPanel: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = testDetailsPanel.dequeueReusableCellWithIdentifier("cell") as! TestDetailsCell
let test:SingleTest = self.items[indexPath.row] as! SingleTest
if(test.photo != "") {
cell.myPhoto.af_setImageWithURL(NSURL(string: test.photo)!)
} else {
cell.myPhoto.image = UIImage(named: "clusterLarge")
}
return cell
}
I thought that since I'm downloading images while displaying the table, there is no need to download it again on the other screen (which is accessible through clicking each cell).
So my idea was to pass the image from specific cell to the other screen through segue. But the problem is that from the method prepareForSegue I don't have access to the specific cell that user clicks. So my other choice was to use protocols. I created a very simple one:
protocol HandlePhoto: class {
func setUpBackgroundPhoto(miniature: UIImage)
}
and then in my native class I wanted to use it in didSelectRowAtIndexPath method:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let test:SingleTest = self.items[indexPath.row] as! SingleTest
let cell = testDetailsPanel.dequeueReusableCellWithIdentifier("cell") as! TestDetailsCell
if(test.photo != "") {
handlePhoto.setUpBackgroundPhoto(cell.testPhoto.image!)
self.performSegueWithIdentifier("testPhotoDetailsSegue", sender: test)
}
} else {
self.performSegueWithIdentifier("testTextDetailsSegue", sender: test)
}
}
But this line:
handlePhoto.setUpBackgroundPhoto(cell.testPhoto.image!)
throws error:
fatal error: unexpectedly found nil while unwrapping an Optional value
So my final question is: how can I access photo from the specific cell that user chooses and pass it to other view (without downloading it there for the 2nd time)?
Your didSelectRowAtIndexPath implementation is wrong, with dequeueReusableCellWithIdentifier you are obtaining a new cell, not the selected cell.
Try this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let selectedCell = tableView.cellForRow(at: indexPath) as! TestDetailsCell
//this will return downloaded image or "clusterLarge"
let image = selectedCell.myPhoto.image
//
//Make your check on image and extra setup
//
self.performSegueWithIdentifier("testPhotoDetailsSegue", sender: test)
}
Why are you using dequeueReusableCellWithIdentifier in your didSelectRowAtIndexPath?; instead, you should get the cell directly using:
let cell = yourTableView.cellForRowAtIndexPath(indexPath) as! TestDetailsCell
if let image = cell.testPhoto.image {
print(image)//this is what you want.
}
I am looking to captured image tap event on the first record of UITableView, when user taps I cell.imageAvtar I just want to capture that event.
This is the code I am using
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("details", forIndexPath: indexPath) as! AccountCell
if (indexPath.row == 0) {
(cell.contentView.viewWithTag(101) as! UIImageView).image = UIImage(named: "no_image_available.jpg")
}
return cell
}
But (cell.contentView.viewWithTag(101) is returning as nil.I have tried (cell.contentView.viewWithTag(100) tried (cell. imageAvtar.viewWithTag(101) as well.
check your imageView's tag in interface builder or storyboard if it is 0 make it 101 and retry..
you can also check
for subView in cell.contentView.subView {
print("subView tag --> \(subView.tag)!")
}
try this in your cellForRowAtIndexPath
Try,
cell.viewWithTag(101) or self.view.viewWithTag(101) if tag is unique(i.e. if you are not using this tag at other place).
Second thing you have to add gesture recognizer to capture event on it. How you come to know that it's returning nil ? It may not return nil. You are making another mistake. Make sure that no_image_available.jpg is properly available in project!
Another thing is make sure that you have set tag properly.
I have used IBOutlets as vadian and jrturton advised.
This is the working code
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("details", forIndexPath: indexPath) as! AccountCell
if (indexPath.row == 0) { let tapGestureRecognizer = UITapGestureRecognizer(target:self, action:Selector("imageTapped:"))
cell.imageAvtar.userInteractionEnabled = true
cell.imageAvtar.addGestureRecognizer(tapGestureRecognizer)
}
}
func imageTapped(img: AnyObject)
{
print("event captured")
//your logic comes here
}
I know that I can query for, lets say, users that have emailVerified equal to true and present them into a tableView, but I was having trouble getting a single Parse object of type array into a tableView. I couldn't find anything online about this specific problem, but after putting a few answers together, I got it to work my answer is below for those also having trouble with this.
Here is what I found based on my question. I have an object in Parse called "my_classes" that is of type array. I want to get the items from the array into a tableView.
1) Create a variable: var myClassesResults : NSMutableArray = []
2) Create the function or place the code where necessary:
func getUserData() {
if PFUser.currentUser()!.objectForKey("my_classes") != nil {
let classes = PFUser.currentUser()!.objectForKey("my_classes")!
myClassesResults = classes as! NSMutableArray
self.noClasses = false
self.tableView.reloadData()
} else {
self.noClasses = true
self.tableView.reloadData()
}
}
3) tableView functions:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.myClassesResults.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel!.text = myClassesResults[indexPath.row] as? String
return cell
}
I have a custom cell class that has a function called setCell.
This takes a word and an image and sets a label and an imageview to them settings.
That works fine and is called during the cell setup.
The problem is when I try to get the currently selected cell text, it just returns nil.
Below is current 'didSelectRow' function:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = myTableView.indexPathForSelectedRow();
let currentCell = myTableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
println(currentCell.textLabel!.text) //This returns nil
}
Bellow is my custom cell setup functions:
func setCell(text: String, imagetext: String) {
if var image = self.myImage {
image.image = UIImage(named: imagetext)
}
if var label = self.myLabel {
label.text = text
println(label.text) //Prints out the items that are in the cells, which is what I want it to do.
}
}
Does anyone know why my code is returning nil?
EDIT: Thank you to the suggestions so far, but I just found out that if I print out cell.labelText.text after calling the setCell function on it, it just prints out nils.
cell.setCell(category, imagetext: theimage)
println(cell.textLabel!.text) //I have 7 items in the list so it just print out nil 7 times.
Why is it not being set after calling the function on it?
The indexPath and tableView are passed in as parameters and should be used to do what you're trying to do:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var currentCell = tableView.cellForRowAtIndexPath(indexPath!) as CustomTableViewCellClass!;
println(currentCell.textLabel!.text) //This returns nil
}