0

I am trying to pass an image from my Collection View (PortfolioView.swift) to another View Controller (PortfolioDetail.swift). My code for PortfolioView.swift reads:

import UIKit

class Portfolio View: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
    var array = [String] = []
    var name : AnyObject? {
        get {
            return NSUserDefaults.standardUserDefaults().objectForKey("name")
    }
        set {
            NSUserDefaults.standardUserDefaults.setObject(newValue!, forKey: "name")
            NSUserDefaults.standardUserDefaults().synchronize()
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        array = ["PortImage1","PortImage2","PortImage3","PortImage4","PortImage5","PortImage6","PortImage7",
    "PortImage1","PortImage2","PortImage3","PortImage4","PortImage5","PortImage6","PortImage7",
    "PortImage1","PortImage2","PortImage3","PortImage4","PortImage5","PortImage6","PortImage7"]
        self.view.backgroundColor = UIColor(patternImage: UIImage(named: "BackgroundImage.png")!)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func collectionView(collectionView: UICollectionView,numberOfItemsInSection section: Int) -> Int {
        return array.count
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CollectionViewCell
        cell.ImageView.image = UIImage(named: array[indexPath.row])
        cell.ImageView.layer.cornerRadius = cell.ImageView.frame.size.width / 2
        cell.ImageView.clipsToBounds = true
        cell.ImageView.layer.borderWidth = 2.0
        cell.ImageView.layer.borderColor = UIColor.whiteColor().CGColor
        return cell
    }
    func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
        name = UIImage(named: array[indexPath.row])
    }
}

My PortfolioDetail.swift code reads:

import UIKit

class PortfolioDetail: UIViewController {
    @IBOutlet var DetailImageView: UIImage!
    @IBOutlet var DetailLabel: UILabel!

    var name: AnyObject? {
        get {
            return NSUserDefaults.standardUserDefaults().objectForKey("name")
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor(patternImage: UIImage(named: "BackgroundImage.png")!)
        DetailImageView.image = UIImage(named: name as! String)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

When I run this app I am able to get a display of my array of images but when I click on one of the images it doesn't display the image in my other VC. I think my issue is with the following line:

DetailImageView.image = UIImage(named: name as! String)
Michaël Azevedo
  • 3,874
  • 7
  • 31
  • 45
Chosen
  • 1
  • 6
  • 1
    This is a misuse of `NSUserDefaults`. – rmaddy Dec 07 '15 at 16:03
  • @rmaddy how am I misusing NSUserDefaults? I followed a tutorial on this and he got it to work. – Chosen Dec 07 '15 at 16:08
  • @kholl what do you mean by file system? I am new to this. – Chosen Dec 07 '15 at 16:08
  • 2
    Just because you found a tutorial doing this doesn't make it right. There is a lot of terrible sample code on the Internet. 1) Using `NSUserDefaults` just to pass data between view controllers is a bad idea. 2) Storing large blobs of image data in `NSUserDefaults` is a really bad idea. Just pass the data directly from one controller to another. – rmaddy Dec 07 '15 at 16:11
  • @rmaddy Okay true. I am new to this. What is the easiest way to pass data from one controller to the next? Do you have any links that you can provide? – Chosen Dec 07 '15 at 16:14
  • Add a public variable in your second view controller, and set its value from the first one when the push occurs. – Michaël Azevedo Dec 07 '15 at 16:16
  • @MichaëlAzevedo where in the code do I put this? Is this called segue? – Chosen Dec 07 '15 at 16:18
  • 1
    You should review this: http://stackoverflow.com/questions/5210535/passing-data-between-view-controllers?s=7|2.3903 – rmaddy Dec 07 '15 at 16:21

1 Answers1

0

You are saving an UIImage in NSUserDefaults and then trying to use it as a String - this will not work, as these two types are not compatible. The easiest way to make things work, is to change
name = UIImage(named: array[indexPath.row])
to
name = array[indexPath.row]

This way, you will save the name of the image in NSUserDefaults and will be able to load the image based on it later.


Now, as it has been said in the comments - passing data between view controllers this way isn't really a good design choice. The best way would be to pass the name directly - there are two ways to do this, depending on how you move to PortfolioDetail view controller - by segue or "directly" (i.e. instantianting it yourself in code and calling presentViewController).

If you do this with segue you should add (if you don't have it) this method :

override func prepareForSegue(_ segue: UIStoryboardSegue, sender sender: AnyObject?) {

    if (segue.identifier == "YourSegueIdentifier") {
        let portfolioDetail = segue.destinationViewController as! PortofolioDetail
        portfolioDetail.name = self.name
    }

}

If you instantiate it directly it should look something like this :

let portfolioDetailVC = PortfolioDetail()
portoflioDetailVC.name = self.name
self.presentViewController(portfolioDetailVC, animated: true, completion: nil)

You'd also need to remove the custom getters and seterrs of the name variables in both view controllers.

Losiowaty
  • 7,911
  • 2
  • 32
  • 47
  • this was extremely helpful. You broke it down in a way that I could understand it all and I appreciate your help. When I use your segue identifier method I get the error "type PortfolioDetail has no member 'name' " for the following code: PortfolioDetail.name = self.name – Chosen Dec 07 '15 at 16:33
  • You can try changing it to be a`public` variable like this `public var name:AnyObject?` in `PortfolioDetail`, but it should work regardless (as long as both classes are in the same module, but I assume so) - I do hope you didn't remove it altogether after my remark about `get`ters and `set`ters, did you? I only meant that you wouldn't need the `get` and `set` parts of the variable declaration. – Losiowaty Dec 07 '15 at 16:41
  • Yes I removed get { return NSUserDefaults.standardUserDefaults().objectForKey("name") } set { NSUserDefaults.standardUserDefaults.setObject(newValue!, forKey: "name") NSUserDefaults.standardUserDefaults().synchronize() } for both view controllers. is this correct? – Chosen Dec 07 '15 at 17:00
  • You told me to change 'name = UIImage(named: array[indexPath.row])' to 'name = array[indexPath.row]' but I get an error that says " cannot subscript a value of type [string]" – Chosen Dec 07 '15 at 17:01
  • Yes, thats what I meant about getters and setters. About the subscript error, I cannot see a reason for it, especially that it worked just before. Have you tried cleaning and rebuilding your code? Is `array` optional? You can try this `array?[indexPath.row]` – Losiowaty Dec 07 '15 at 18:50
  • Thanks !! @Losiowaty . I just kept my original code and changed name = UIImage(named: array[indexPath.row]) to name = array[indexPath.row] it worked! – Chosen Dec 07 '15 at 19:21