Swift how to get cell from prepare for segue in collectionView - ios

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
}
}

Related

Issue in Passing data from UicollectionView controller

I have seen couple of posts but not able to figure out the issue
I want to pass data from UICollectionView Controller to my UIViewController , Here are the details
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Selection2" {
if let indexPath = self.collectionView?.indexPath(for: sender as! UICollectionViewCell) {
let detailVC = segue.destination as! SelectionViewController
//
let item = items1[indexPath.row]
//passing the item name which is selected
detailVC.label1.text = item.name1
}
}
}
And here is the SelectionViewController code :
import UIKit
class SelctionViewController: UIViewController {
var label1 : UILabel!
#IBOutlet weak var Label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
Label.text = self.label1.text
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
But when i run this i am not able to pass values and getting the following error :
fatal error: unexpectedly found nil while unwrapping an Optional value
Please suggest how this can be corrected , Thanks
I will suggest you the following approach. write below code in didSelectItemAt method.
let detailVC = self.storyboard?.instantiateViewController(withIdentifier: "Selection2") as! SelectionViewController
let item = items1[indexPath.row]
//Create string property itemName and pass the value
detailVC.itemName = item.name1
self.navigationController?.pushViewController(detailVC, animated: true)
Assing itemName to laber in SelectionViewController like below.
self.Label.text = itemName
#lazyCoder , thanks for helping me out
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let detailVC = self.storyboard?.instantiateViewController(withIdentifier: "Selection2") as! SelctionViewController
detailVC.itemName = self.items1[indexPath.row].name1
self.navigationController?.pushViewController(detailVC, animated: true)
}
This code is working perfectly fine now ..Cheers
Instead of using UIlabel label1, declare string variable eg. title. and Change the following lines in your code.
class SelctionViewController: UIViewController {
var title = ""
#IBOutlet weak var Label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
Label.text = title
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
prepareForSegue method: instead of detailVC.label1.text, use detailVC.title
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Selection2" {
if let indexPath = self.collectionView?.indexPath(for: sender as! UICollectionViewCell) {
let detailVC = segue.destination as! SelectionViewController
let item = items1[indexPath.row]
detailVC.title = item.name1 // instead of detailVC.label1.text, use detailVC.title
}
}
}

Value is not passed after prepareforsegue. Swift

VC that fires perform segue.
It has a backgroundImage with a userImage and a collectionView with images in cells.
import UIKit
class EmojiCollectionVC: {
#IBOutlet weak var backgroundImage: UIImageView!
#IBOutlet weak var emojiCollection: UICollectionView!
var userImage: UIImage!
override func viewDidLoad() {
super.viewDidLoad()
backgroundImage.image = userImage
}
#IBAction func dismiss(_ sender: Any) {
dismiss(animated: false, completion: nil)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! EmojiCollectionCell
let chosenEmoji = cell.emojiView.image
performSegue(withIdentifier: "backToEmojiVC", sender: chosenEmoji)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "backToEmojiVC"{
if let destinationVC = segue.destination as? EmojiVC {
if let emoji = sender as? UIImage {
destinationVC.emojiImage = emoji
let data = UIImagePNGRepresentation(userImage)
print("Zhenya: 1 - \(data)")
destinationVC.imageData = data
print("Zhenya: 5 - \(destinationVC.imageData)")
}
}
}
}
}
userImage has an image in it that is displayed.
After pressing the cell, image from it (chosenEmoji) should be passed to EmojiVC, to its emojiImage.
Both prints "Zhenya: 1" and "Zhenya: 5" in prepare for segue print desired value.
The destination VC:
class EmojiVC: UIViewController {
#IBOutlet weak var mainImg: UIImageView!
#IBOutlet weak var emojiImageView: UIImageView!
var imageData: Data!
var imageItself: UIImage!
var emojiImage: UIImage!
override func viewDidLoad() {
super.viewDidLoad()
print("Zhenya:3 - \(imageData)")
print("Zhenya:4 - \(emojiImage)")
}
override func viewDidAppear(_ animated: Bool) {
print("Zhenya:3 - \(imageData)")
print("Zhenya:4 - \(emojiImage)")
if imageData != nil {
print("Zhenya:2 - \(imageData)")
let img = UIImage(data: imageData)
mainImg.image = img
} else if imageItself != nil {
mainImg.image = imageItself
}
if emojiImage != nil {
print("Zhenya: \(emojiImage)")
emojiImageView.image = emojiImage
}
}
#IBAction func addEmoji(_ sender: Any) {
let img = mainImg.image
performSegue(withIdentifier: "EmojiCollectionVC", sender: img)
}
}
Both prints Zhenya: 3 and Zhenya: 4 print nil. Data that was set in prepare for segue wasn't passed to them.
Segue backToEmojiVC is performed, but data isn't passed.
I did check - if there are any other segues with same identifiers.
I suspect, that value gets destroyed somewhere or somehow when destination VC appears. Or both imageData and emojiImage are re-initialized with nil values.
What might be the problem?
Went through the code step by step. Copy pasted names of segues instead of typing them. Shit started to work.

How to transfer/display an image from CollectionView to another ViewController

I have looked up many examples and tried to incorporate but have been unsuccessful. In my CollectionView (That has been placed in a ViewController), I'd like to select a cell and push the cell image to another ViewController. The images have been placed in an Array of Dictionaries. I'm not sure, how i should edit both my prepareForSegue or my func collectionView...didSelectItemAtIndexPath. Also, any detailed explanation to go along with your code will be helpful as I'm still learning swift and its syntax.
Below is what i think all the information you need but please let me know if you need more:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "ShowToStory") {
var story = sender as! UICollectionViewCell, indexPath = collectionView.indexPathForCell(story)
}
}
private func initStoryImages() {
var storyArchives = [StoryImages]()
let inputFile = NSBundle.mainBundle().pathForResource("StoryArchive", ofType: "plist")
let inputDataArray = NSArray(contentsOfFile: inputFile!)
for inputItem in inputDataArray as! [Dictionary<String, String>] {
let storyImage = StoryImages(dataDictionary: inputItem)
storyArchives.append(storyImage)
}
storyImages = storyArchives
}
ADDITIONAL CLASS: CollectionViewCell class
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var cellImage: UIImageView!
func setStoryImage(item:StoryImages){
cellImage.image = UIImage(named:item.itemImage)
}
}
ADDITIONAL CLASS: UIViewController
class StoryView: UIViewController{
#IBOutlet weak var ImageToStory: UIImageView!
var story: StoryImages?
override func viewDidLoad() {
super.viewDidLoad()
ImageToStory.image = UIImage(named: (story?.itemImage)!)
}
}
ADDITIONAL CLASS: StoryImages
class StoryImages{
var itemImage: String
init(dataDictionary:Dictionary <String,String>) {
itemImage = dataDictionary["ItemImage"]!
}
class func newStoryImage(dataDictionary:Dictionary<String,String>) -> StoryImages {
return StoryImages(dataDictionary: dataDictionary)
}
}
}
First pass the indexPath of selectedItem in didSelectItemAtIndexPath
Now pass the image in prepareForSegue method like this
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "ShowToStory") {
let cell = sender as! UICollectionViewCell //Change UICollectionViewCell with CustomCell name if you are using CustomCell
let indexPath = self.collectionView?.indexPathForCell(cell)
let story = storyImages[indexPath.row]
let destVC = segue.destinationViewController as! StoryView
destVC.selectedStory = story
}
}
Now declare one StoryImages types of object in your StoryView where you want to pass image and use that object in viewDidLoad to assign image
var selectedStory: StoryImages?
override func viewDidLoad() {
super.viewDidLoad()
ImageToStory.image = selectedStory.itemImage // or use NSData if it contain url string
}

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.

ViewController loading twice xcode 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.
}

Resources