didSelectRowAtIndexPath and performSegueWithIdentifier - swift2

I have a tableView that display a list of cells. I need to catch the selected cell, and pass my object data based on indexPath.row to display it on my Second View Controller. My didSelectRowAtIndexPath is working fine, but probably I'm not familiar with the syntax for performSegueWithIdentifier, where it fails to call the method.
Sorry I'm new to Swift programming, would appreciate if you could explain more details.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
selectedCell = indexPath.row
performSegueWithIdentifier("DetailScreen", sender: self)
}
override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) {
detailedView.personName = personList[selectedCell].GetPersonName()
}

Solution 1
First, make sure you have segue between your first and second view controllers (From the table view controller one to the Detail view screen). Make sure that the segue has a name
Now in your first view controller's didSelectRowAtIndexPath event, Invoke the segue like this.
performSegueWithIdentifier("DetailScreen", sender: nil)
Now in the prepareForSegue method of the first view controller, you can customize it to send more details.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if(segue.identifier=="DetailScreen")
{
let ctrl = segue.destinationViewController as! YourDetailsViewController
ctrl.personName = "Set some person name here"
}
}
Assuming Your Detail screen's class is called YourDetailsViewController and it has a property called personName of String type. You may update the code to use your real view controller.
Solution 2
If you do not want to create the segue, you can programmatically navigate( actually pushing the second view controller to the front) to the second view. In your first view controllers, didSelectIndexPathAtRow method,
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let ctrl = self.storyboard?.instantiateViewControllerWithIdentifier("DetailsCtrl")
as? YourDetailsViewController
ctrl?.personName="Set some name here"
self.navigationController?.pushViewController(ctrl!, animated: true)
}
For the above code to work, you need to make sure that you have StoryBoardID set to "DetailsCtrl" on the second view controller(Details view)

You have set the storyboard segue as given below:
Click on the segue and add the identifier
You can achieve the above requirement using the following code and this worked for me:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let storyboard1 = UIStoryboard(name: "Main", bundle: nil)
let detail = storyboard1.instantiateViewControllerWithIdentifier("DetailScreen") as! SecondViewController
detail.personName = personList[selectedCell].GetPersonName()
self.navigationController?.pushViewController(detail, animated: true)
}
The storyboard segue from your first view controller to second view controller should be "Push".
Hope this might be helpful.

Related

pass UIimage from UITableViewCell to next ViewController [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 3 years ago.
There are many other topics of passing data to another ViewController - i know - but i could not find the solution for passing data from UITableViewCell to UIViewController. The question differs from others that here i have to access an ImageView in another class of UITableViewCell. Segues, prepare for segues an other topics are discussed in other posts sufficiently but not this special constellation.
I have a class UITableViewCell:
class PostCell: UITableViewCell {
...
// networkService is downloading an image
networkService.downloadImage({ (imageData) in
let image = UIImage(data: imageData as Data)
...
// image is set to UIImageView
self.postImageView.image = image
In my ViewController i do this to go to the DetailViewController:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
aktIndex = indexPath.section
performSegue(withIdentifier: "segueDetail", sender: self)
}
I tried this:
let MainStory:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let desVC = MainStory.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
desVC.getImage = ???
self.navigationController?.pushViewController(desVC, animated: true)
DetailViewController:
class DetailViewController: UIViewController {
var getImage = UIImage()
...
I have made a segue in xcode (segueDetail):
At the moment i store the imagedata in UserDefaults and read them again in the DetailViewController. Very weird, i know.
Where do i have to pass the data from? In my PostCell or in the ViewController? The problem is to get access to image-data from PostCell in my ViewController.
In tableView(_:didSelectRowAt:) when you call performSegue(withIdentifier: sender:), you can pass any data or references in it. This is now available in prepare(forSegue:sender:) and your last shot at preparing the data to be passed to the segued viewController.
Example (Using Segue):
If segueDetail is properly hooked up via storyboard and your user taps on a row, you could send the indexPath to the segue like:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "segueDetail", sender: indexPath)true)
}
Then in prepare(forSegue:sender:), depending on your solution, you can prepare access to the required data that you need to pass to the next viewController like:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? DetailViewController {
let indexPath = sender as! IndexPath
let cell = tableView.cellForRow(at: indexPath) as! PostCell
vc.getImage = cell.postImageView.image
}
}
Example (Manually without segue):
If you are not using a segue and the user taps on a row, you could manually push a viewController with data like:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let sb = UIStoryboard(name: "Main", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
let cell = tableView.cellForRow(at: indexPath) as! PostCell
vc.getImage = cell.postImageView.image
self.navigationController?.pushViewController(desVC, animated: true)
}
And your DetailViewController should be:
class DetailViewController: UIViewController {
var getImage: UIImage?
//...
NOTE: This answer is the best I could fit to work with the given content.
It should just about work but please don't just copy-paste as it's not optimized (for example, your user taps on a cell before it's image is downloaded).
This was just to show the basics, so please improvise and apply proper case handling.

How to Pass Collection View Data to a New View Controller

I am going try be as specific as possible.
What I am trying to achieve is to have one view controller which has a collection view in it and when the user clicks on of the collection view cells, it then sends the user to another view controller which has another collection view however the items displayed in the second collection view will change depending on which collection view cell the user previously tapped. I am also using CoreData to do this. With CoreData, the task is an entity and has attributes like name etc. Will I have to change this or have a relationship between the 2 collection views?
The reason for me wanting to do this is because I am creating a productivity app for iOS and the first view controller with a collection view will be where the user can create projects, within these projects which will be displayed in a collection view, the user can then tap on one of the cells and go to the next view controller and begin to create tasks specific to that project.
How can I keep the tasks stored in a specific collection view cell and have the user create different tasks in other projects. It is sort of like Wunderlist. If anybody is confused at what I am trying to do, I can ellaborate more.
This is one of my view controllers where the data from the 'create item view controller' gets sent to via CoreData and displays it in a collection view, hope it helps:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var myCollView: UICollectionView!
#IBAction func addCore(_ sender: UIButton) {
}
var tasks : [Task] = []
override func viewDidLoad() {
super.viewDidLoad()
self.myCollView.delegate = self
self.myCollView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
getData()
myCollView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tasks.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "connectCell", for: indexPath) as! MyCollectionViewCell
let task = tasks[indexPath.row]
cell.labelTe?.text = task.name!
self.myCollView.backgroundColor = UIColor.clear
cell.layer.cornerRadius = 25
return cell
}
func getData() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do {
tasks = try context.fetch(Task.fetchRequest())
}
catch {
print("Ahhhhhhhh")
}
}
If I am guessing right, and upon clicking a cell on the first collection view, you want to segue to another collection view, where you will display display data according to the selected cell.
In order to achieve this, simply add collectionView(_ collectionView:, didSelectItemAt indexPath:) and prepare(for segue:, sender:) functions in your first view controller.
In the collectionView(_ collectionView:, didSelectItemAt indexPath:) function get the id of the task selected by determine which cell was selected, then pass this id to the second view controller in prepare(for segue:, sender:) function.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! MyCollectionViewCell
id = cell.labelTe?.text
}
or
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
id = tasks[indexPath.row].id
}
Then pass this value in your prepare(for segue:, sender:) function to the second viewController.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "YourIdentifier"{
let destinationViewController = segue.destination as! SecondViewController
destinationViewController.id = id
}
}
Make sure to add a var id in both your viewControllers. In the second viewController, use this id to fetch the data of the selected task that you want to display.
Hope this helps.
EDIT
Simply declare a new variable id of your particular type in both the viewControllers. In your first viewController :
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var id = ""
and in the second viewController
class secondViewController: UIViewController {
var id = ""
Just make sure that both the variable are of same type.

Is it possible to create one tableViewCell that can be used in multiple Table Controllers?

I have about 3 or 4 table controllers that will all use the same tableview cell. I keep going back on fourth of the possible logic. Can I use the same tableViewCell in multiple tableView Controllers assuming the information is between the two is the same? Or will I have to create a new cell for each controller?
Yes you can.
I am assuming that you are using Swift.
Goto File -> New and select cocoaTouch class as follows.
Now name Your class for custom cell and make it subClass of UITableViewCell. also check the box which says "Also create Xib file"
Now design your cell in this Xib and create outlets in its .Swift file. Lets say you have a custom tableView cell which looks something like this
Which contains a label or ImageView or anyThing that you have in your cell. Now in your swift file of custom cell you can write a method like so
class func cellForTableView(tableView: UITableView, atIndexPath indexPath: NSIndexPath) -> YourCustomTableViewCell {
let kYourCustomTableViewCellIdentifier = "kYourCustomTableViewCellIdentifier"
tableView.registerNib(UINib(nibName: "YourCustomTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: kYourCustomTableViewCellIdentifier)
let cell = tableView.dequeueReusableCellWithIdentifier(kYourCustomTableViewCellIdentifier, forIndexPath: indexPath) as! YourCustomTableViewCell
return cell
}
Now you can use this cell in any tableView in your application just like below
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = YourCustomTableViewCell.cellForTableView(tableView, atIndexPath: indexPath)
cell.backgroundColor = UIColor.clearColor()
// do something with your cell
}
I hope it helps.
Update for Swift 3 and Swift 4:
class func cellForTableView(tableView: UITableView, atIndexPath indexPath: IndexPath) -> YourCustomTableViewCell {
let kYourCustomTableViewCellIdentifier = "kYourCustomTableViewCellIdentifier"
tableView.register(UINib(nibName: "YourCustomTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: kYourCustomTableViewCellIdentifier)
let cell = tableView.dequeueReusableCell(withIdentifier: kYourCustomTableViewCellIdentifier, for: indexPath) as! YourCustomTableViewCell
return cell
}
Yes you can use the table view cell in multiple tableView Controllers .

How to use two tableview in one view?

I have two table view in one view container. I insert each of them to the container.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
self.storyboard?.instantiateViewController(withIdentifier: "ChildTableView") as! ChildTableViewController
childTV.updateTable(id: indexPath.row)
}
I need to update second tableview when first tableview cell clicked.
How i can do this?
Okay, I think I see the problem. The way you've done this is with two UITableViewControllers and their table views. So now you have a problem communicating between the two table view controllers. But consider this: if you've truly created child view controllers, the table view controllers are children of the same parent. So the first table view controller can get its parent view controller, then get the parent's child view controllers, then get the second child view controller, and that must be the second table view controller.
In other words, if your view controller hierarchy is:
ParentViewController
TableViewController1
TableViewController2
... then TableViewController1 can say:
let tvc2 = self.parent!.childViewControllers[1] as! TableViewController2
... and now you have established a line of communication between them. So now table view controller 1 can talk to table view controller 2 and tell it to update its table. You will need to have a method in table view controller 2 that table view controller 1 can call, in order to hand it any needed data and tell it what to do.
in Second TableView:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ChildTableViewController.updateTable(sender:)), name: NSNotification.Name(rawValue: "updateChild"), object: nil)
}
func updateTable(sender:NSNotification){
tableView.reloadData()
}
in First TableView:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
selectedItem["id"]=indexPath.row
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateChild"),object:selectedItem)
}

Passing an image when taped on uicollectionview to a detail view controller in swift

Ive been at this for a while but cant seem to crack it in swift
I want a user to be able to select an image in uicollectionView and for that image to appear in a detailed view controller, i can do this quite easily with a peice of text,
and i can do this when there is a static array of images preloaded. but i cant seem to get anywhere with a collectionview which is loaded with images from a camera.
I understand i need to use
override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) {
}
and this function to isolated selected cell.
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
}
I do have these outlets
#IBOutlet weak var collectionView: UICollectionView!
var images = [UIImage]()
image picker stores all images to this array by
images.insert(newImage, atIndex: 0)
when the array would be passed to the detailviewcontroller, i understand that would have to be copied into another local array and then how would i get the current image that was highlighted to be shown first, perhaps using indexPath.Row
Regards
I'm not using segues, and actually I don't quite understand what your problem is, but I'll try to show you how it could be achieved.
First of all, you have an array with images, so I believe your image should be accessed as images[indexPath.row]
let's suppose that you already have UIViewController class with UIImageView in it.
if so, you can write something like that:
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let myVC = MyViewController()
myVC.imageView.image = images[indexPath.row]
self.presentViewController(myVC, animated: true, completion: nil)
}
for modal or
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let myVC = MyViewController()
myVC.imageView.image = images[indexPath.row]
self.navigationController?.pushViewController(myVC, animated: true)
}
if you want to show it as navigational.
I believe that with segues it's basically the same but I think you have to use func prepareForSegue for, you know, preparing the segue (func performSegueWithIdentifier will just perform it). In prepareForSegue you should check identifier of your segue
if segue.identifier == "myIdentifier" {
//your code here
}
and if this identifier is right, put your commands to your myVC there.

Resources