Transfer TableviewCell to AnotherTableView in swift - swift

I have two tableView (FavouriteViewController and MainViewController) controllers in my project and the ViewController connected through segue with button. I have some data running in my MainViewController and the FavouriteViewController basically with no data in it.I am trying to transfer tableViewCell when the cell clicked from MainViewController to favouriteViewController using tableViewCell swipe action method or any another suggeste method.
my codes as below.
My MainViewController
var arrays = ["Alpha","Beta","Gamma","Phill","Below","Above","Clean",]
var sendSelectedData = NSString()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
title = "FavTV"
let titlebutton: UIButton = UIButton(frame: CGRectMake(0, 0, 100, 32))
titlebutton.setTitle("Quote", forState: UIControlState.Normal)
titlebutton.titleLabel?.font = UIFont(name: "PartyLetPlain", size: 35)
titlebutton.setTitleColor(UIColor.redColor(), forState: UIControlState.Normal)
titlebutton.addTarget(self, action: "titlePresed", forControlEvents: UIControlEvents.TouchUpInside)
self.navigationItem.titleView = titlebutton
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell1")
self.tableView.reloadData()
}
func titlePressed() {
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
self.performSegueWithIdentifier("ShowDetails", sender: nil)
segue.destinationViewController as! favTableViewController
}
self.performSegueWithIdentifier("ShowDetails", sender: nil)
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell!
sendSelectedData = (currentCell.textLabel?.text)! as String
//self.arrays.append(String(indexPath.row)
// performSegueWithIdentifier("ShowDetails", sender: self)
}
override func tableView(tableView: UITableView,commitEditingStyle editingStyle: UITableViewCellEditingStyle,forRowAtIndexPath indexPath: NSIndexPath) {
}
///////////////////////
override func tableView(tableView: UITableView,commitEditingStyle editingStyle: UITableViewCellEditingStyle,forRowAtIndexPath indexPath: NSIndexPath) {
switch editingStyle {
case .Delete:
// remove the deleted item from the model
self.arrays.removeAtIndex(indexPath.row)
performSegueWithIdentifier("ShowDetails", sender: self)
tableView.reloadData()
default:
return
}
}
/////////////////////
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "ShowDetails") {
// initialize new view controller and cast it as your view controller
let viewController = segue.destinationViewController as! favTableViewController
// your new view controller should have property that will store passed value
viewController.arrayx = [sendSelectedData as String]
///////////////////////
self.arrays.append(sendSelectedData as String)
/////////////////////
}
}
My FavouriteTableView:
var arrayx = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
title = "Fav"
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayx.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = arrayx[indexPath.row] as? String
return cell
}
}
Above code works in a simple way when i press the cell from MainViewController and then when the titlePressed() button pressed. it passing the pressed cell data to FavouriteTableView....
I need some suggetion how to transfer cell to my FavouriteTableView permanently.I am not sure about my logic is right. Please some one point me the right direction.
Thanks in Advance...

What shows up in a table is driven by :
var arrayx = [] // <-- CHANGE THE CONTENTS OF THIS ARRAY
Change the data in that array and then reload the table.
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
Here is your function that gets the data and puts it into the cells.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
// arrayx is the data that drives the table.
// changing the data in arrayx will cause the table to show different data.
// **********************************************
// ** The table will show whatever is in arrayx
// ** therefore, if you change arrayx then table
// ** will have that new data.
// **********************************************
cell.textLabel?.text = arrayx[indexPath.row] as? String
// **********************************************
return cell
}

Related

trying to pass cell.profilepic.image I get this error Thread 1: signal SIGABRT (Could not cast value of type 'UIButton' to 'UIImage')

import UIKit
trying to pass cell.profilepic.image from ViewController2 to ViewController3
in runtime when I click on the Botton (func bottone) [my Botton is
in the prototype cell of the tableView in viewController2]
I put the tableView func inside the botton's action cause I want that my pic3 (declared in ViewController3 as UIImage) is the pic I click in the TableView of my ViewController2
class ViewController2: UIViewController, UITableViewDataSource, UITableViewDelegate {
let images = ["image1", "image2", "image3"]
// here are my functions for the my TableViewCell2
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (images.count)
}
// the identifier of my prototype cell in the TableView is cell (and nome is just a label)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell2
cell.nome.text = images [indexPath.row]
cell.profilepic.image = UIImage(named: images[indexPath.row])
return (cell)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/* I put the tableView func inside the botton's action cause I want that my pic3 (declared in
ViewController3 as UIImage) is the pic I click in the TableView of my ViewController2 */
#IBAction func bottone(_ sender: Any) {
func tableView2(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell2
cell.nome.text = images [indexPath.row]
cell.profilepic.image = UIImage(named: images[indexPath.row])
performSegue(withIdentifier: "page3", sender: cell.profilepic.image)
return (cell)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "page3" {
let viewCont: ViewController3 = segue.destination as! ViewController3
viewCont.pic3 = sender as! UIImage
}
}
}

Passing Data between TableView in Swift

I have two tableView running in my project.I am trying to pass(copy) my first tableViewcell data to second tableView.I using tableView row action method to pass data.My partial code below...
First VC:
var tableView: UITableView!
var DataArray = ["Bus","Helicopter","Truck","Boat","Bicycle","Motorcycle","Plane","Train","Car","S cooter","Caravan"]
var sendSelectedData = NSString()
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let copyAction = UITableViewRowAction(style: UITableViewRowActionStyle.normal, title: "Pass Data") { (UITableViewRowAction, NSIndexPath) -> Void in
print("Button Pressed") // Xcode Console prints **Button Pressed** when swipe action performed.
self.performSegue(withIdentifier: "send", sender: self)
}
return [copyAction]
}
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
self.performSegue(withIdentifier: "send", sender: self)
// segue.destination as! tableController
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRow(at: indexPath!)!
self.sendSelectedData = (currentCell.textLabel?.text)! as String as NSString
let viewController = segue.destination as! tableController
viewController.labelcell = ([self.sendSelectedData as String])
print(self.sendSelectedData) // no result
}
Second VC:
var labelcell = [String]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: textCellIdentifier, for: indexPath as IndexPath) as UITableViewCell
cell.textLabel?.text = labelcell[indexPath.row] as? String
tableView.reloadData()
return cell
}
Above code looks like passing data to my second VC(segue).But, I am only getting a empty tableview..
Okay after testing it, it turns out, that you're using an incorrect prepareForSegue function. You are not using "prepareForSegue", you are creating a function called prepareForSegue - since the syntax has changed in Swift 3. This one will get called and you can pass data.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "send" {
let selectedIndex = sender as! NSIndexPath
let currentCell = tableView.cellForRow(at: selectedIndex as IndexPath)! as! Cell
self.sendSelectedData = (currentCell.label?.text)! as String as NSString
print(self.sendSelectedData) // till here it worked for me - it is filled with my label.text
// I don't know what this is "viewController.labelcell", so you have to to know how to go on from here on
viewController.labelcell = ([self.sendSelectedData as String])
}
}
Also you need to pass the indexPath:
self.performSegue(withIdentifier: "send", sender: indexPath)
Exactly like this:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let copyAction = UITableViewRowAction(style: UITableViewRowActionStyle.normal, title: "Pass Data") { (UITableViewRowAction, NSIndexPath) -> Void in
print("editActionsForRowAt called") // Xcode Console prints **Button Pressed** when swipe action performed.
self.performSegue(withIdentifier: "send", sender: indexPath)
}
return [copyAction]
}
This worked in my testing project.
Also beware: Cell is a custom subclass of UITableViewCell I have created and label is an UIOutlet of a label element for my test project.

fatal error: unexpectedly found nil while unwrapping an Optional value: Swift, Core Data

I am getting error on the line:
let indexPath = self.menuTable.indexPathForSelectedRow()!.
Seems that I am not getting a value from indexPathForSelectedRow. I am parsing from a CSV file into Core Data. Not sure if it matters. I am new to coding, so not sure if I am missing something obvious.
import UIKit
import CoreData
class MenuTableViewController: UITableViewController {
#IBOutlet var menuTable: UITableView!
private var menuItems:[MenuItem] = []
var fetchResultController:NSFetchedResultsController!
override func viewDidLoad() {
super.viewDidLoad()
// Load menu items from database
if let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext {
let fetchRequest = NSFetchRequest(entityName: "MenuItem")
var e: NSError?
menuItems = managedObjectContext.executeFetchRequest(fetchRequest, error: &e) as! [MenuItem]
if e != nil {
println("Failed to retrieve record: \(e!.localizedDescription)")
}
}
// Make the cell self size
self.tableView.estimatedRowHeight = 66.0
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.layoutIfNeeded()
}
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 the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return menuItems.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = menuTable.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! MenuTableViewCell
// Configure the cell...
cell.nameLabel.text = menuItems[indexPath.row].name
cell.detailLabel.text = menuItems[indexPath.row].detail
// cell.priceLabel.text = "$\(menuItems[indexPath.row].price as! Double)"
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
self.performSegueWithIdentifier("showFront", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "showFront")
{
var upcoming: CardFrontViewController = segue.destinationViewController as! CardFrontViewController
let indexPath = self.menuTable.indexPathForSelectedRow()!
let titleString = menuItems[indexPath.row].name
upcoming.titleStringViaSegue = titleString
self.menuTable.deselectRowAtIndexPath(indexPath, animated: true)
}
}
}
Since you have an implementation of tableView:didSelectRowAtIndexPath: and the cell is connected to the segue in the storyboard, the segue is happening twice. The second time the segue is performed there would be no selection because you deselect it during the first segue. You can fix this issue by deleting your implementation of tableView:didSelectRowAtIndexPath: or by creating the segue in the storyboard with the view controller itself as the source instead of the cell and leaving your manual invocation of the segue.
I don't know if this is the problem but why are u using self as sender if u need the indexPath?
Try:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
self.performSegueWithIdentifier("showFront", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "showFront")
{
var upcoming: CardFrontViewController = segue.destinationViewController as! CardFrontViewController
let titleString = menuItems[indexPath.row].name
upcoming.titleStringViaSegue = titleString
self.menuTable.deselectRowAtIndexPath(indexPath, animated: true)
}
}
I see you are using a UITableViewController. In a UITableViewController a UITableView is automatically created for you with the needed outlets. You can access it in code via self.tableView. My guess is that you do not connected the IBOutlet for your UITableView called menuTable. So the optional which is nil while unwrapping is not the indexPath but the UITableView.
Fix:
Delete your IBOutlet and everywhere you use the menuTable variable and use self.tableView instead.

PrepareForSegue from a UIButton in a custom prototype cell

As the title say I have a tableView with prototype cell; cell is a custom cell (so I made a class called CustomCell.swift in witch I created the IBOutlet for image, label, button etc); here my class
import UIKit
class CustomCell: UITableViewCell
{
#IBOutlet var imageSquadra: UIImageView!
#IBOutlet var button: UIButton!
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
}
}
then I made the UITableViewController:
import UIKit
class SquadreController: UITableViewController
{
var index: NSIndexPath?
var isScrolling = Bool()
override func viewDidLoad()
{
super.viewDidLoad()
DataManager.sharedInstance.createCori()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return DataManager.sharedInstance.arrayCori.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
let squadra = DataManager.sharedInstance.arrayCori[indexPath.row]
cell.backgroundColor = UIColor.clearColor()
if (indexPath.row % 2 == 0)
{
cell.backgroundColor = UIColor.greenColor()
}
else
{
cell.backgroundColor = UIColor.blueColor()
}
//Here I added target to the button in the cell, and below in the class I implemented the fun makeSegue()
cell.button.addTarget(self, action: "makeSegue", forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
//Following 4 method are used to detect UIScollView scrolling and to change cell height.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
tableView.deselectRowAtIndexPath(indexPath, animated: true)
index = indexPath
tableView.beginUpdates()
tableView.endUpdates()
}
override func scrollViewWillBeginDragging(scrollView: UIScrollView)
{
isScrolling = true
tableView.beginUpdates()
tableView.endUpdates()
}
override func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool)
{
isScrolling = false
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
if isScrolling
{
return 100
}
if index == indexPath
{
return 200
}
else
{
return 100
}
}
//Here I implemented the makeSegue() func, the action I had made as target of the button.
func makeSegue() {
self.performSegueWithIdentifier("toCoriViewController", sender: self)
}
}
Ok ok now comes the hard part: to make the prepareForSegue; I do not have any ideas how to solve this problem, I tried
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "toCoriViewController"
{
if let indexPath = ?????????????
{
let controller = segue.destinationViewController as! CoriViewController
controller.coriSquadra = DataManager.sharedInstance.arrayCori[indexPath.row]
}
}
}
but I don't know how to set the constant indexPath.
Oh, first of all I made a segue by control-right from the button to the second controller: maybe I must make that segue from the tableView cell???
Hope someone could help me!
You could get the index path of the cell like so
let indexPath : NSIndexPath
if let button = sender as? UIButton {
let cell = button.superview?.superview as! UITableViewCell
indexPath = self.tableView.indexPathForCell(cell)
}
You'll also need to change your makeSegue like this:
func makeSegue(button:UIButton) {
self.performSegueWithIdentifier("toCoriViewController", sender: button)
}
and in your cellForRowAtIndexPath just change the line where you set the action to cell.button.addTarget(self, action: "makeSegue:", forControlEvents: UIControlEvents.TouchUpInside).
Alternatively, you could create a squadra property inside your custom cell class to hold the arrayCori value of that cell, so you'd have some code that looks like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
let squadra = DataManager.sharedInstance.arrayCori[indexPath.row]
cell.squadra = squadra #add this line
cell.backgroundColor = UIColor.clearColor()
if (indexPath.row % 2 == 0)
{
cell.backgroundColor = UIColor.greenColor()
}
else
{
cell.backgroundColor = UIColor.blueColor()
}
//Here I added target to the button in the cell, and below in the class I implemented the fun makeSegue()
cell.button.addTarget(self, action: "makeSegue", forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "toCoriViewController"
{
let controller = segue.destinationViewController as! CoriViewController
if let button = sender as? UIButton {
let cell = button.superview?.superview as! CustomCell
controller.coriSquadra = cell.squadra
}
}
}
Storyboard + prepareForSegue
It can be done with just about no code by adding a separate UIStoryboardSegue with its own identifier for the button in the Storyboard.
prepareForSegue becomes:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if "fromButtonToViewController" == segue.identifier {
if let button = sender as? UIButton {
// ... The UIButton is the sender
}
}
}
This handles both tap on cell and tap on button either jointly or separately, passes the proper sender to prepare:segue:sender, thus allowing customization of the cell, the button, the transition, and ultimately the target view. The demonstration of this statement can be found in the compact project below.
► Find this solution on GitHub and additional details on Swift Recipes.
For those who are looking for a generic approach.
/* Generic function to get uitableviewcell from any UIKit controllers which stored in deep level of views or stackviews */
func getCell<T>(_ view: T) -> UITableViewCell? {
guard let view = view as? UIView else {
return nil
}
return view as? UITableViewCell ?? getCell(view.superview)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "toCoriViewController"
{
if let button = sender as? UIButton,
let cell = getCell(button),
let indexPath = tableView.indexPath(for: cell)
{
let controller = segue.destinationViewController as! CoriViewController
controller.coriSquadra = DataManager.sharedInstance.arrayCori[indexPath.row]
}
}
}

How to make a segue by a tableViewDelegate

I'd like to create a segue from a tableViewDelegate cell to an other view. This is my code:
import UIKit
class CoriViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
{
#IBOutlet var tableView: UITableView!
var elencoCori : SquadraModel! //This var contains label and array
override func viewDidLoad()
{
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
InterfaceManager.sharedInstance.putBlurBackgroundToTableView(self.view, tableView: self.tableView)
self.tableView.tableFooterView = UIView(frame:CGRectZero)
self.tableView.backgroundColor = UIColor.clearColor()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.elencoCori.cori.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell : UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
let coro = elencoCori.cori[indexPath.row]
cell.textLabel?.text = coro.marker
cell.backgroundColor = UIColor.clearColor()
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)
{
self.performSegueWithIdentifier("toDettaglioController", sender: self)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
Now the problem: how I could set a prepareForSegue that send to the secondView? In other circumstances I would have solved the problem like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "toDettaglioController"
{
if let indexPath = tableView.indexPathForSelectedRow()
{
let controller = segue.destinationViewController as! Dettaglio controller
controller.coro = elencoCori.cori[indexPath.row]
}
}
}
but I know the this doesn't work and I have to use a delegate method. So can everyone help me with a step-by-step guide?
On your didSelectRowAtIndexPath method call performSegueWithIdentifier and pass the indexPath as your sender.
Then in prepareForSegue you can do if let indexPath = sender as NSIndexPath and setup your controller.
Suppose you have One UITableViewController-T and Two UIViewControllers-A and B.
Now suppose you want to go from T to A when cell 0 is clicked, and go from T to B when cell 1 is clicked.
Step 1 : Connect segue from T to A and name that segue "segueToA"
Step 2 : Connect segue from T to B and name that segue "segueToB"
Step 3 : Got to didSelectRowAtIndexPath in T and put if-else
if(indexPath.row == 0){
self.performSegueWithIdentifier("segueToA", sender: nil)
}else{
self. performSegueWithIdentifier("segueToB", sender: nil)
}
That's it.
Update: Here is a Sample Project.