I want to pass the storage data contained in a TableView and pass it to another ViewController. My customCell has an UIImage and a String.
When the user press the cell I want to show a "detail view controller" with the UIImage and a label containing the info of the cell selected.
Here is my code:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var dataTableView: UITableView!
var myList = [dataList]()
var textToBeSent: String = ""
var selectedImage: UIImage?
var selectedLabel: String?
//Load Items To List
func loaditems(){
let item1 = dataList(photoList: UIImage.self(), itemDescription: "Descripcion Aqui")
let item2 = dataList(photoList: UIImage.self(), itemDescription: "Aqui tmb")
myList += [item1,item2]
}
//var list = ["Documento 1", "Documento 2", "Documento 3"]
override func viewDidLoad() {
super.viewDidLoad()
if let savedData = loadSavedItems(){
myList += savedData
} else {
loaditems()
}
//dataTableView.register(UITableViewCell.self, forCellReuseIdentifier: "reusablecell")
// Do any additional setup after loading the view, typically from a nib.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return myList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "prototype", for: indexPath) as! PrototypeCell
let itemsinCell = myList[indexPath.row]
cell.imageItem.image = itemsinCell.photoList
cell.itemDescription.text = String(itemsinCell.itemDescription)
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete{
myList.remove(at: indexPath.row)
dataTableView.reloadData()
}
saveToSavedData()
}
Here is the func where I want to pass the data of a certain cell.
The data is from a Swift file stored in a "DataList" using aDecoder NSCoder.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row \(indexPath.row) selected")
selectedImage! = myList[indexPath.row].photoList
selectedLabel! = myList[indexPath.row].itemdescription
performSegue(withIdentifier: "selectedRowSegue", sender: myList[indexPath.row])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "selectedRowSegue"){
let chosenRowViewController = segue.destination as! chosenRowViewController
chosenRowViewController.image3 = selectedImage?.photoList
chosenRowViewController.label3 = selectedLabel?.itemDescription
}
}
Unwind a segue in order to fill up the cells with data from previous
ViewController:
//Unwinde Segue
#IBAction func unWindlToList(sender: UIStoryboardSegue){
if let sourceViewController = sender.source as? ProcessViewController, let item = sourceViewController.item{
let newIndexPath = IndexPath(row: myList.count, section: 0)
myList.append(item)
dataTableView.insertRows(at: [newIndexPath], with: .automatic)
}
saveToSavedData()
}
//Archive Data
func saveToSavedData(){
NSKeyedArchiver.archiveRootObject(myList, toFile: (dataList.fileFolder?.path)!)
}
//Unarchive Data
func loadSavedItems() -> [dataList]?{
return NSKeyedUnarchiver.unarchiveObject(withFile: (dataList.fileFolder?.path)!) as? [dataList]
}
}
class PrototypeCell: UITableViewCell {
#IBOutlet weak var itemDescription: UILabel!
#IBOutlet weak var imageItem: UIImageView!
}
just replace prepare(for segue: UIStoryboardSegue, sender: Any?) function with below code
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "selectedRowSegue"), let list = sender as? dataList {
let chosenRowViewController = segue.destination as! chosenRowViewController
chosenRowViewController.image3 = list.photoList
chosenRowViewController.label3 = list.itemDescription
}
}
There are several things that stand out.
1- var myList = [dataList]() dataList is a Class, classes should be capitalized. It should be var myList = [DataList]()
2- You have this as a class property but it's not used anywhere in the code you posted so why did you add it and what is it's purpose? var textToBeSent: String = ""
3- You have these 2 class property variables
var selectedImage: UIImage?
var selectedLabel: String?
to hold the data from [myList] but you really don't need them because you can just access the data from [myList] using dot notation inside prepareForSegue (read the commented out code in prepareForSegue).
4- In prepareForSegue you have let chosenRowViewController = segue.destination as! chosenRowViewController. ChosenRowViewController is a class and it should be capitalized like so:
let chosenRowViewController = segue.destination as! ChosenRowViewController // it's capitalized after the as!
Here's the code a little cleaned up.
#IBOutlet weak var dataTableView: UITableView!
var myList = [DataList]()
func loaditems(){
let item1 = dataList(photoList: UIImage.self(), itemDescription: "Descripcion Aqui")
let item2 = dataList(photoList: UIImage.self(), itemDescription: "Aqui tmb")
myList.append(item1)
myList.append(item2)
}
override func viewDidLoad() {
super.viewDidLoad()
// everything you already have inside here...
}
// your tableView datasource methods...
5- Since your using prepareForSegue you don’t need didSelectRowAt indexPath
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "selectedRowSegue"){
// get the indexPath for the selectedRow
let indexPath = tableView.indexPathForSelectedRow
let chosenRowViewController = segue.destination as! ChosenRowViewController
chosenRowViewController.image3 = myList[indexPath!.row].photoList // use dot notation to access the photoList property
chosenRowViewController.label3 = myList[indexPath!.row].itemDescription // use dot notation to access the itemDescription property
}
}
You have made a mistake in your didSelectRowAt, while calling performSegue you have to pass the controller which is the sender, in your case it is your current UIVIewController, so you have to write self as sender controller. So your corrected methog will look like below code snippet:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row \(indexPath.row) selected")
selectedImage! = myList[indexPath.row].photoList
selectedLabel! = myList[indexPath.row]
performSegue(withIdentifier: "selectedRowSegue", sender: self)
}
Related
Essentially I have a view controller called FirstViewController, this view controller contains a table view within it called listTableView.
I would like to tap on one of the cells in the table view listTableView and present whatever text was in the cell as the navigation controller title.
The navigation controller that appears when the cell is tapped is called showDetailsViewController.
How can this be done?
The following is what I have written in the FirstViewController
import UIKit
import AudioToolbox
class FirstViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, FeedModelProtocol {
var feedItems: NSArray = NSArray()
var selectedStock : StockModel = StockModel()
let tableView = UITableView()
#IBOutlet weak var listTableView: UITableView!
#IBOutlet weak var refreshButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
//set delegates and initialize FeedModel
self.listTableView.delegate = self
self.listTableView.dataSource = self
let feedModel = FeedModel()
feedModel.delegate = self
feedModel.downloadItems()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
#IBAction func reloadData(_ sender: Any) {
print("reload pressed")
listTableView.reloadData()
viewDidLoad()
_ = AudioServicesPlaySystemSound(1519)
}
func itemsDownloaded(items: NSArray) {
feedItems = items
self.listTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of feed items
print("item feed loaded")
return feedItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Retrieve cell
let cellIdentifier: String = "stockCell"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
myCell.textLabel?.textAlignment = .center
myCell.textLabel?.font = .boldSystemFont(ofSize: 18)
// Get the stock to be shown
let item: StockModel = feedItems[indexPath.row] as! StockModel
// Configure our cell title made up of name and price
let titleStr = [item.customer].compactMap { $0 }.joined(separator: "-")
print(titleStr)
// Get references to labels of cell
myCell.textLabel!.text = titleStr
return myCell
}
}
UPDATE:
What is the issue with this code:
NOTE:
The restoration id of the tableview is scheduleTable
var homeworkIdentifierFromTableViewCell = ""
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
homeworkIdentifierFromTableViewCell = feedItems[indexPath.row].myCell
self.performSegue(withIdentifier: "scheduleTable", sender: self)
listTableView.deselectRow(at: indexPath, animated: true)
}
UPDATE 2
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item: StockModel = feedItems[indexPath.row] as! StockModel
let titleStr = [item.customer].compactMap { $0 }.joined(separator: "-")
print(titleStr)
}
You can use the didSelectRowAt to notice what cell was clicked and store what the text in the cell was (homeworkArray is the list of cells from a struct. Homeworkidentifier is a value in the struct).
var homeworkIdentifierFromTableViewCell = ""
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
homeworkIdentifierFromTableViewCell = homeworkArray[indexPath.row].homeworkIdentifier
self.performSegue(withIdentifier: "homeworktoExpandHomework", sender: self)
homeworkTableView.deselectRow(at: indexPath, animated: true)
}
Then, you could use a prepare for a segue function to pass the text of the table view cell to the next view controller. You do this by creating a variable in the other view controller (the one that you are going to pass data to) and later accessing it from the other view controller and changing its value.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "reportBug" {
let destinationViewController = segue.destination as! WebViewController
destinationViewController.reason = "reportBug"
}
else if segue.identifier == "provideFeedback" {
let destinationViewController = segue.destination as! WebViewController
destinationViewController.reason = "provideFeedback"
}
}
Here is more about passing data between viewcontrollers : Passing data between View Controllers in Swift (From TableView to DetailViewController)
Hope this helps
EDIT:
Here is the struct I am using :
struct homeworkTableViewCellData {
let homeworkName : String!
let className : String!
let dateName : String!
let colorImage : UIImage!
let homeworkIdentifier : String!
}
I have initialized my homeworkArray with this struct. When I am calling a value from the cell, I am picking one from in the struct.
To set the table view with a struct is more organized. This is a good video that teaches you how to set it up (if you are want to do that) : https://www.youtube.com/watch?v=zAWO9rldyUE&list=LL--UalPCi7F16WzDFhMEg7w&index=20&t=921s
I have two custom table views. I need to pass first and second cell datas of DestinationTableView to first cell of MyCartTableView. How can I make transition between this two table view cells with outside of tableView.
I did tableView.indexPathForSelectedRow but this time I need to make with UIButtonoutside of tableView.
Below triggered with tableView cell.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "cellForFoodSegue" {
if let destinationViewController = segue.destination as? DetailViewController
{
let indexPath = self.mainTableView.indexPathForSelectedRow!
var foodNameArray: String
var foodPriceArray: Double
foodNameArray = foodNames[indexPath.row]
foodPriceArray = foodPrices[indexPath.row].purchaseAmount
destinationViewController.detailFoodName = foodNameArray
destinationViewController.detailFoodPrice = foodPriceArray
}
}
}
I tried below code but I did not success passing data with button.
#IBAction func addBasket(_ sender: Any) {
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "addToCartSegue") {
if let addToCartVC = segue.destination as? MyCartViewController {
let selectedCell = sender as! UITableViewCell
let indexPath = self.detailTableView.indexPath(for: selectedCell)
var foodNameArray: String
var foodPriceArray: Double
foodNameArray = foodNames[indexPath.row]
foodPriceArray = prices[indexPath.row].purchaseAmount
addToCartVC.fromDetailFoodName = foodNameArray
addToCartVC.fromDetailFoodPrice = prices[(indexPath?.row)!].purchaseAmount
}
}
}
Belows my MyViewController codes. Which is my added objects when tapped to addBasket button
class MyCartViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var fromDetailFoodName: [String?] = []
var fromDetailFoodPrice = Double()
var nameLabel = MyCartTableViewCell()
#IBOutlet weak var myCartTableView: UITableView!
#IBOutlet weak var totalPriceLabel: UILabel!
let foodNames = [
"Hamburger big mac",
"Cemal",
"Emre",
"Memo"
]
//TODO-: Delete my cart
#IBAction func deleteMyCart(_ sender: Any) {
}
//TODO: - Approve my cart
#IBAction func approveCart(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return section == 0 ? 1 : foodNames.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCartCell", for: indexPath) as! MyCartTableViewCell
cell.myCartFoodNameLabel?.text = fromDetailFoodName.description
cell.myCartFoodPriceLabel?.text = "\(fromDetailFoodPrice)₺"
return cell
}
}
You should get the index path of the data you want to pass in func addBasket(_ sender: Any).
For example, you can save index path as a property that referenced in class.
class StartViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var selectedIndexPath: IndexPath?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedIndexPath = indexPath
}
#IBAction func addBasket(_ sender: Any) {
if let indexPath = selectedIndexPath {
let destinationVC = MyCartViewController()
destinationVC.detailFoodName = foodNames[indexPath.row]
destinationVC.detailFoodPrice = foodPrices[indexPath.row].purchaseAmount
}
}
}
In MyCartViewController which is destination VC.
class MyCartViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var fromDetailFoodNames: [String?] = []
var fromDetailFoodPrices: [Double?] = []
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 1 && indexPath.last! <= fromDetailFoodPrices.indices.last! {
let cell = myCartTableView.dequeueReusableCell(withIdentifier: "myCartCell", for: indexPath) as! MyCartTableViewCell
let name = fromDetailFoodNames[indexPath.row]?.description ?? ""
let price = fromDetailFoodPrices[indexPath.row]
cell.myCartFoodNameLabel?.text = name
cell.myCartFoodPriceLabel?.text = "\(price)₺"
return cell
}
}
}
BTW, for better coding, you can implement OOP concept in your code. detailFoodName and detailFoodPrice should be in ONE object. Besides, var foodNameArray: String naming could be confusing. Rename it as var foodName: String would be better.
I'm trying to pass just the image part of a struct (containing also two textFields, and another imageView I'd like to not pass).
Here is the tableViewController
import UIKit
class SentMemesTableViewController: UITableViewController {
var _tableView: UITableView!
var memeData: [Meme] = []
//calling memes from array in Delegate
let appDelegate = UIApplication.shared.delegate as! AppDelegate
var memes: [Meme] {
return appDelegate.memes
}
override func viewWillAppear(_ animated: Bool) {
tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.isScrollEnabled = true
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MemeDetailViewController" ,
let nextScene = segue.destination as? MemeDetailViewController ,
let indexPath = tableView.indexPathForSelectedRow {
let selectedMeme = memes[indexPath.row].memedImage
nextScene.sentMemeView.image = Meme.memedImage
}
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//navigationController!.pushViewController(MemeDetailViewController, animated: true)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return memes.count
}
// Here it is! -----
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "sentMemesTableView") as! MemeTableViewCell
let meme = memes[indexPath.row]
tableViewCell.tableViewImage.image = meme.memedImage
tableViewCell.tableViewLabel.text = "\(meme.topText)...\(meme.bottomText)"
return tableViewCell
}
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return false
}
func deleteMemesInTableViewCell(_ index: Int) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.memes.remove(at: index)
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
tableView.beginUpdates()
deleteMemesInTableViewCell(indexPath.row)
tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.left)
tableView.endUpdates()
}
}
}
Here is the Meme and SentMemeView structs.
import Foundation
import UIKit
struct Meme {
let topText: String
let bottomText: String
let originalImage: UIImage
let memedImage: UIImage
}
struct SentMemeImageView {
var memedImageDetailVC: UIImageView
}
I can't find a way to call it successfully.
Here is the MemeDetailViewController. I need just for the sentMemeView to display the SentMemeImageView.
class MemeDetailViewController: UIViewController {
var meme = SentMemeImageView?.self
#IBOutlet weak var sentMemesBtn: UIBarButtonItem!
#IBOutlet weak var editBtn: UIBarButtonItem!
#IBOutlet weak var sentMemeView: UIImageView!
func displayMeme(_ meme: SentMemeImageView) {
}
#IBAction func launchMemeEditorViewController(_ sender: Any) {
_ = navigationController?.popViewController(animated: true)
}
//unwinding to the view before (the collectionView, or the tableView)
#IBAction func unwindVC(for unwindSegue: UIStoryboardSegue, towardsViewController subsequentVC: UIViewController) {
self.dismiss(animated: true, completion: nil)
}
}
First of all, sad to say that, your code is quite messed up:
You have with three different kinds of data sources, some are ignored, some you work with, but not in a consistent way:
data from the app delegate (deletion of data)
memeData property (display of data)
memes property (ignored)
You should really focus on where the data is stored and how to access it.
Secondly, you won't send views from one view controller to the other, but data. So rather use UIImage than UIImageView. So you'll hand in a SentMemeImage to the details controller.
I tried to clean up the code a little, but just to answer your explicit question. Please refactor it!
struct Meme {
let topText: String
let bottomText: String
let originalImage: UIImage
let memedImage: UIImage
}
struct SentMemeImage {
var memedImage: UIImage
}
class SentMemesTableViewController: UITableViewController {
var memeData: [Meme] = []
// ----8<---- snipp ----8<----
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MemeDetailViewController" ,
let nextScene = segue.destination as? MemeDetailViewController ,
let indexPath = tableView.indexPathForSelectedRow {
let selectedMeme = memeData[indexPath.row]
let sentMemeImage = SentMemeImage(memedImage: selectedMeme.memedImage)
nextScene.meme = sentMemeImage
}
}
// ----8<---- snipp ----8<----
}
class MemeDetailViewController: UIViewController {
var meme:SentMemeImage?
#IBOutlet weak var sentMemesBtn: UIBarButtonItem!
#IBOutlet weak var editBtn: UIBarButtonItem!
#IBOutlet weak var sentMemeView: UIImageView!
func displayMeme() {
self.sentMemeView.image = self.meme?.memedImage
}
}
I am struggling with getting my care data to populate my second tableview controller. The data is populating the first tableview and I can select a row and the segue is used to go to the second table but the labels are not populated.
I've looked all over and have found older samples or obj-c but I cannot figure it out, so any help pointing this n00b in the right direction will be helpful.
Here is what I have, I think I am missing how to populate a variable to pass in prepareForSegue in the list tableview, but I could be wrong. I get a warning error in that function (Warning cannot assign value of type 'ListEntity' to type '[ListEntity]').
CoreData
Entity = ListEntity
Attributes = title, event & location (all as Strings)
listTableViewController
import UIKit
import CoreData
class ListTableViewController: UITableViewController {
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var lists = [ListEntity]()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "The List"
let addButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: self, action: #selector(ListTableViewController.addButtonMethod))
navigationItem.rightBarButtonItem = addButton
}
func addButtonMethod() {
print("Perform action")
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
reloadData()
tableView.reloadData()
}
func reloadData() {
let fetchRequest = NSFetchRequest(entityName: "ListEntity")
do {
if let results = try managedObjectContext.executeFetchRequest(fetchRequest) as? [ListEntity] {
lists = results
}
} catch {
fatalError("There was an error fetching the list!")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return lists.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("ListCell") as! ListTableViewCell
let list = lists[indexPath.row]
cell.configurationWithSetup(list)
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("DetailsSegue", sender: self)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DetailsSegue" {
let destinationVC = segue.destinationViewController as! DetailsTableViewController
let indexPath : NSIndexPath = self.tableView.indexPathForSelectedRow!
print(indexPath.row) // Print the Row selected to console
// Place the code to pass data here?
// destinationVC.lists = lists[indexPath.row]
// Warning cannot assign value of type 'ListEntity' to type '[ListEntity]'
}
}
}
listTableViewCell
import UIKit
class ListTableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
func configurationWithSetup(list: AnyObject) {
titleLabel.text = list.valueForKey("title") as! String?
}
}
detailsTableViewController
import UIKit
import CoreData
class DetailsTableViewController: UITableViewController {
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var lists = [ListEntity]()
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DataCell") as! DetailsTableViewCell
let list = lists[indexPath.row]
cell.configurationWithSetup(list)
return cell
}
}
detailsTableViewCell
import UIKit
import CoreData
class DetailsTableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var eventLabel: UILabel!
#IBOutlet weak var locationLabel: UILabel!
func configurationWithSetup(list: AnyObject) {
titleLabel.text = list.valueForKey("title") as! String?
eventLabel.text = list.valueForKey("event") as! String?
locationLabel.text = list.valueForKey("location") as! String?
}
}
The warning contains the answer - just change
var lists = [ListEntity]() to
var lists = ListEntity(), or var lists:ListEntity! and when you prepare for segue set that value.
Then you will need to change
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DataCell") as! DetailsTableViewCell
// as data source is not array you can just you the item you passed
// let list = lists[indexPath.row]
cell.configurationWithSetup(lists)
return cell
}
You should use a static table view if you just want one cell
More info per you current issue
class DetailsTableViewController: UITableViewController {
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var theDetailListEntity:ListEntity!
override func viewDidLoad() {
super.viewDidLoad()
print(theDetailListEntity) // check that you passed it across
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DataCell") as! DetailsTableViewCell
cell.configurationWithSetup(theDetailListEntity)
return cell
}
}
Don't forget to add prepare for segue in the listTableViewController otherwise theDetailListEntity won't be set... and then it will crash.
Depending on how you set up your segue, it may differ. But this is what you need
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("showMyDetailView", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showMyDetailView" {
guard let
vc = segue.destinationViewController as? DetailsTableViewController,
ip = sender as? NSIndexPath else { fatalError() }
let item = lists[ip.row]
vc.theDetailListEntity = item
// set the item in the next VC
tableView.deselectRowAtIndexPath(ip, animated: true)
}
}
I have one table view with many cell.Each cell have one image and one label.And what i need is when ever user press any cell it have to go to detail viewcontroller.And there i need to show the respective image and label name in my detail view controller.How to do that.
I have done all segue.But in my detail view controller i have one image and label.Now how can i show the image and label name - when i select the any cell from my table view ??
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var valueToPass:String!
var selectedIndexPath: NSIndexPath = NSIndexPath()
var tableData: [String] = ["Christ Redeemer", "Great Wall of China", "Machu Picchu","Petra","Pyramid at Chichén Itzá","Roman Colosseum","Taj Mahal"]
var arrImageName: [String] = ["ChristRedeemer", "GreatWallOfChina", "MachuPicchu","Petra","PyramidChichenItza","RomanColosseum","TajMahal"]
var tableRate: [String] = ["$120", "$100", "$222","$1000","$500","$900","$2000"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func numberOfSectionsInTableView(tableView: UITableView) ->Int
{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.tableData.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:CustomTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("CustomTableViewCell") as! CustomTableViewCell
cell.imageVW.image = UIImage(named:self.arrImageName[indexPath.row])
cell.lblName.text = self.tableData[indexPath.row]
cell.rateName.text = self.tableRate[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedIndexPath = indexPath
performSegueWithIdentifier("DetailView", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
let indexPath = self.selectedIndexPath
if (segue.identifier == "DetailView") {
var viewController = segue.destinationViewController as! DetailVC
viewController.data = UIImagePNGRepresentation(UIImage(named:self.arrImageName[indexPath.row])!)!
//viewController.name = self.tableData[[indexPath.row]]
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is my detailvc.swift
import UIKit
class DetailVC: UIViewController {
var data: NSData = NSData()
var name: String = String()
#IBOutlet weak var ImgView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.ImgView.image = UIImage(data: data)
//self.detailLabelNamee.text = name
}
}
change your did select with something like this
Declare one gloabal indexPath in ViewContrller like this
var selectedIndexPath: NSIndexPath = NSIndexPath()
Change your didselect like this
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedIndexPath = indexPath
self.performSegueWithIdentifier("DetailView", sender: self)
}
Now in prepareForSegue method add this
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
let indexPath = self.selectedIndexPath
if (segue.identifier == "DetailView") {
var viewController = segue.destinationViewController as! DetailVC
viewController.data = UIImagePNGRepresentation(UIImage(named:self.arrImageName[indexPath.row]))
viewController.name = self.tableData[indexPath.row]
}
}
Now add two global identifier in DetailVC like below
var data: NSData = NSData()
var name: String = String()
Now assign this data and string to imageview and label in viewdid load
change the viewdidload of detailVC like this
override func viewDidLoad() {
super.viewDidLoad()
self.ImgView.image = UIImage(data: data)
self.detailLabelNamee.text = name
}
Hop this will help.
In your didSelectRowAtIndexPath you can just perform the segue and in prepareForSegue you can get the indexPath with self.tableView.indexPathForSelectedRow. And of course it returns an optional and you have to check it first for safety. I think this is the easiest way.
In your didSelectRowAtIndexPath you can get the index path of the selected row and then you can performSegue and pass index path in sender.
In prepareForSeque , from the index path , you can get the image , tableData and tableRate . Which you can pass to detail view . Something like below
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("DetailView", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
let selectedIndexPath = sender as! NSIndexPath
if (segue.identifier == "DetailView") {
var viewController = segue.destinationViewController as! DetailVC
viewController . setValues(tableData:tableData[selectedIndexPath] , rate: tableRate[selectedIndexPath] , imageName:arrImageName[selectedIndexPath])
}
class DetailVC: UIViewController {
var imageName:String!
var tableData:String!
var tableRate:String!
func setValues(tableData:String , rate:String , imageName:String){
imageName = tableData
tableRate = rate
imageName = imageName
}
or
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
let selectedIndexPath = sender as! NSIndexPath
if (segue.identifier == "DetailView") {
var viewController = segue.destinationViewController as! DetailVC
viewController.imageName = self.arrImageName[selectedIndexPath.row]
viewController.tableData = self.tableData[selectedIndexPath.row]
viewController.tableRate = self.tableRate[selectedIndexPath.row]
}
You can declare a variable for store indexpath in that .
var selectedItemIndex = Int()
on click of cell write below lines in didselectowatndexaPath
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
selectedItemIndex = indexPath.row
self .performSegueWithIdentifier(“YourViewController”, sender: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let yourVC = segue.destinationViewController as! YourViewController
yourVC.text = tableData[selectedItemIndex]
yourVC.image = UIImage(named:arrImageName[selectedItemIndex])
}
You are almost there! The line:
performSegueWithIdentifier("DetailView", sender: self)
needs changing. 'self' is passing a reference of the current view controller to the prepareForSegue method. If you change 'self' to 'indexPath', then prepareForSegue will see the cell index path in the 'sender' object and you take what you want from that.
You could do something like:
if (segue.identifier == "yourSegueIdentifer") {
var viewController = segue.destinationViewController as! DetailVC
let indexPath = sender as! NSIndexPath
viewController.passedImageName = self.arrImageName[indexPath.row]
viewController.passedData = self.tableData[indexPath.row]
viewController.passedRate = self.tableRate[indexPath.row]
and in DetailVC:
class DetailVC: UIViewController {
var passedImageName:String!
var passedData:String!
var passedRate:String!