ViewController loading twice xcode iOS - ios

I know what causes it to load twice, but I do not know how to fix the problem. I have looked through many other questions at the same topic, but any of those are matching to my problem.
So here's the code
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let selectedCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
super.performSegueWithIdentifier("TVtoVCSegue", sender: selectedCell)
print("kolm")
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "TVtoVCSegue" {
let otherViewController = segue.destinationViewController as! TTDetailCntr
if let cell = sender as? UITableViewCell, text = cell.textLabel?.text {
otherViewController.CurrentClass = text
}
}
}
As I understand, in tableview function
super.performSegueWithIdentifier("TVtoVCSegue", sender: selectedCell)
Calls out the view to load and the function below itself calls out the view to load,
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
both will load the view so I tried to integrate those methods and I tried to do sth like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let indexPath = tableView.indexPathForSelectedRow! as NSIndexPath
let selectedCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
super.performSegueWithIdentifier("TVtoVCSegue", sender: selectedCell)
if segue.identifier == "TVtoVCSegue" {
let otherViewController = segue.destinationViewController as! TTDetailCntr
if let cell = sender as? UITableViewCell, text = cell.textLabel?.text {
otherViewController.CurrentClass = text
}
}
}
But It says an error if I try to access the view that loaded twice before:
The error comes from the line:
super.performSegueWithIdentifier("TVtoVCSegue", sender: selectedCell)
And the error is:
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
(lldb)
The idea of the code is to get the indexPath value and then pass it to another ViewController

The segue that you've created is most probably from a tableViewCell rather than the UIViewController
Delete the segue and create one from the UIViewController instead.
Ctrl + drag from the circle highlighted in the image to your destination VC.
This will solve this problem.

Here is the SecondviewController that receives the passed data:
class TTDetailCntr: UIViewController {
#IBOutlet var ClassIDLbl: UILabel!
#IBOutlet var TeacherIDlbl: UILabel!
var CurrentClass = ""
override func viewDidLoad() {
super.viewDidLoad()
ClassIDLbl.text = CurrentClass
}

write
self.performSegueWithIdentifier
and check instead of
super.performSegueWithIdentifier
Its working fine with this
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let selectedCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
self.performSegueWithIdentifier("TVtoVCSegue", sender: selectedCell)
print("kolm")
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "TVtoVCSegue" {
let otherViewController = segue.destinationViewController as! SecondViewController
if let cell = sender as? UITableViewCell {
otherViewController.CurrentClass = cell.textLabel?.text
}
}
}
SecondControllerClass.swift
class SecondViewController: UIViewController {
var CurrentClass:String!
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.
}

Related

Swift how to get cell from prepare for segue in collectionView

Im using autolayout and for the life of me cannot set the proceeding view controller image view with the previous view controller collection view cell's image. Im using
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
performSegue(withIdentifier: "openDetailView", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "openDetailView" {
let cell = sender as? ImageCollectionViewCell
let detailVC = segue.destination as! DetailedImageViewController
detailVC.imageToPresent = cell?.imageView.image
}
}
This is the class that I have already set up to receive the image
class DetailedImageViewController : UIViewController{
var imageToPresent: UIImage!
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = imageToPresent
}
}
The segue performs as expected but the image DOES NOT show in detailedImageViewController. Thanks in advance.
You need to set the imageToPresent into a UIImageview in order to show the image.
class DetailedImageViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var imageToPresent : UIImage!
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = imageToPresent
}
...
It's not a best practice to avoid optional unwrapping in this case. Try to use this code and check the errors if they happen.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "openDetailView" {
guard let cell = sender as? ImageCollectionViewCell else {
assertionFailure("Failed to unwrap sender. Try to set a breakpoint here and check what sender is")
return
}
let detailVC = segue.destination as! DetailedImageViewController
guard let cellImage = cell.imageView.image else {
assertionFailure("The cell has no image in image view")
return
}
detailVC.imageToPresent = cellImage
}
}

how to pass the value from table view cell to view controller

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!

Passing data between segue with Swift 2.0

I seem to be following tutorials to the tee yet I can't get my data to pass to my second view controller without being nil.
I am new to Swift so I'm probably also not using optionals correctly. Here is how I have my code set up.
import UIKit
class DetailsViewController: UIViewController {
var book : PLBook?
override func viewDidLoad() {
super.viewDidLoad()
//View Did Load
print(self.book)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
}
Then this is how I am presenting the second view controller and preparing for segue.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("toDetailVC", sender:self)
}
//MARK: Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "toDetailVC"){
//prepare for segue to the details view controller
if let detailsVC = sender?.destinationViewController as? DetailsViewController {
let indexPath = self.tableView.indexPathForSelectedRow
detailsVC.book = self.books[indexPath!.row]
}
}
}
In the second view controller, the book var is always nil. Any ideas how I can get the data to pass?
Try This:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "toDetailVC") {
//prepare for segue to the details view controller
let detailsVC = segue.destinationViewController as! DetailsViewController
let indexPath = self.tableView.indexPathForSelectedRow
detailsVC.book = self.books[indexPath!.row]
}
You should be using segue.destinationViewController, not sender?.destinationViewController.

On passing prepareForSegue , how do I pass my model object to my VC?

My prepareForSegue code looks like this :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowVerse" {
let pageDetailViewController = segue.destinationViewController as! PageViewController
// Get the cell that generated this segue.
if let selectedPageCell = sender as? PageTableViewCell {
let indexPath = tableView.indexPathForCell(selectedPageCell)!
let selectedPage = pages[indexPath.row]
pageDetailViewController.page = selectedPage
}
}
}
However, this line :
let selectedPageCell = sender as? PageTableViewCell
returns nil, and thus so, no information is passed to the ViewController.
How can I determine why this returns nil? And ultimately, how can I successfully assign selectedPageCell to my sender as PageTableViewCell.
My TableViewCell.swift :
import UIKit
class PageTableViewCell: UITableViewCell {
// MARK: Properties
#IBOutlet weak var chapter: UILabel!
#IBOutlet weak var verse: 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
}
}
I'm basing my app off of this Apple Tutorial
all you really need here is the index of the selected row - so you could have that as a class-level variable, and assign it in didSelectRowAtIndexPath
Here's an outline of the code - with all sorts of assumptions about your class names
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
{
var selectedIndexPathRow = -1
... more code ...
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
selectedIndexPathRow = indexPath.row
}
... more code ...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "ShowVerse"
{
if selectedIndexPathRow != -1 // default value to show that something has been selected
{
pageDetailViewController.page = pages[selectedIndexPathRow]
}
}
}
... more code ...
}
Hope this will help you .Replace your code with below code .
you need to replace (sender: AnyObject?) to (sender: AnyObject!) and (sender as? PageTableViewCell) to (sender as PageTableViewCell)
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "ShowVerse" {
let pageDetailViewController = segue.destinationViewController as? PageViewController
// Get the cell that generated this segue.
if let selectedPageCell = sender as? PageTableViewCell {
let indexPath = tableView.indexPathForCell(selectedPageCell)!
let selectedPage = pages[indexPath.row]
pageDetailViewController.page = selectedPage
}
}}
Happy coding .Provide your feedback.

Getting object for tapped UITableViewCell in new UIView?

What is the right way to segue from a cell in a UITableViewCell to a new view, passing parameter data?
I have specified a segue from my prototype cell in my UITableViewCell, that links it to a new UIVIew and has it set to show (aka push). The new UIView displays, but I am not sure how to make tell the UIView the section/row that was selected or tell it about the object associated with that selection.
An abridged version of my code is shown below:
class MyTableViewController : UITableViewController {
// other code omitted
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let files = filesByDate[filesByDateKeys![indexPath.section]]
self.selectedFile = files![indexPath.row]
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "SegueToFileDetails") {
let destinationViewController = segue.destinationViewController as! FileDetailsViewController
destinationViewController.file = self.selectedFile
}
}
}
class FileDetailsViewController : UIViewController {
var file: NSURL
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
print("File: ", file)
}
}
What I find happening is the tableView() function is called after the prepareForSegue() functon, causing the file attribute to be nil when viewWillAppear() is called.
A little more search turned up this other post, which indicated the right approach. The tableView() function in my question is not needed. Instead (in Swift 2):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "SegueToFileDetails") {
let destinationViewController = segue.destinationViewController as! FileDetailsViewController
let path = self.tableView.indexPathForSelectedRow
let files = filesByDate[filesByDateKeys![path!.section]]
destinationViewController.file = files![path!.row]
}
}
And if you want to simply do behaviour based on the specific destination class, based on another suggestion:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destinationViewController = segue.destinationViewController as? FileDetailsViewController {
let path = self.tableView.indexPathForSelectedRow
let files = filesByDate[filesByDateKeys![path!.section]]
destinationViewController.file = files![path!.row]
}
}

Resources