Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Build a Playlist Browser with Swift Building the Master and Detail Views Displaying Playlist Information

Magnus Larsen
PLUS
Magnus Larsen
Courses Plus Student 2,025 Points

Playlist optional returning nil

Hello! During this course I've had some issues with stuff not showing up the way I wanted it to. I've done a lot of searching and a lot of testing and I think that the problem is that my playlist optional is returning nil, and therefore the stuff inside the if clause is not happening.

Here is code from Playlist.swift:

import Foundation
import UIKit

struct Playlist {

    var title: String?
    var description: String?
    var icon: UIImage?
    var largeIcon: UIImage?
    var artists: [String] = []
    var backgroundColor: UIColor = UIColor.clearColor()

    init(index: Int) {
        let musicLibrary = MusicLibrary().library
        let playlistDictionary = musicLibrary[index]

        title = playlistDictionary["title"] as String!
        description = playlistDictionary["description"] as String!

        let iconName = playlistDictionary["icon"] as String!
        icon = UIImage(named: iconName)

        let largeIconName = playlistDictionary["largeIcon"] as String!
        largeIcon = UIImage(named: largeIconName)

        artists += playlistDictionary["artists"] as [String]

        let colorsDictionary = playlistDictionary["backgroundColor"] as [String: CGFloat]
        backgroundColor = rgbColorFromDictionary(colorsDictionary)

    }


    func rgbColorFromDictionary(colorDictionary: [String: CGFloat]) -> UIColor {

        let red = colorDictionary["red"]!
        let green = colorDictionary["green"]!
        let blue = colorDictionary["blue"]!
        let alpha = colorDictionary["alpha"]!

        return UIColor(red: red/255, green: green/255, blue: blue/255, alpha: alpha)
    }


}

And here is my code from my PlaylistMasterViewController.swift file:

import UIKit

class PlaylistMasterViewController: UIViewController {


    @IBOutlet weak var aButton: UIButton!
    @IBOutlet weak var playlistImageView0: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()


    aButton.setTitle("Press me!", forState: .Normal)

    let playlist = Playlist(index: 0)
        playlistImageView0.image = playlist.icon


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }





    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "ShowPlaylistDetail" {
            let playlistDetailController = segue.destinationViewController as PlaylistDetailViewController

            playlistDetailController.playlist = Playlist(index: 0)
        }

    }







}

Lastly, this is the code from my PlaylistDetailViewController file:

import UIKit

class PlaylistDetailViewController: UIViewController {

    var playlist: Playlist?

    @IBOutlet weak var playlistCoverImage: UIImageView!
    @IBOutlet weak var playlistTitle: UILabel!
    @IBOutlet weak var playlistDescription: UILabel!




    override func viewDidLoad() {
        super.viewDidLoad()

        if playlist != nil {
            playlistCoverImage.image = playlist!.icon
            playlistCoverImage.backgroundColor = playlist!.backgroundColor
            playlistTitle.text = playlist!.title
            playlistDescription.text = playlist!.description

        }

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }




}

I know this is a lot of code and it is a big question that I am asking, but this has been bothering me for hours and I would greatly appreciate if someone was able to help me!

17 Answers

Capital initial 'S' in

if segue.identifier == "ShowPlaylistDetailSegue" 

looks wrong ... that might be it!

Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

That was it! Thank you so so much for all the help :)

Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

That was it! Thank you so so much for all the help :)

One thing I noticed is that you are using the small icon in the detailViewController file. Your if statement should look like this:

if playlist != nil {
            playlistCoverImage.image = playlist!.largeIcon
            playlistCoverImage.backgroundColor = playlist!.backgroundColor
            playlistTitle.text = playlist!.title
            playlistDescription.text = playlist!.description

            playlistArtist0.text = playlist!.artists[0]
            playlistArtist1.text = playlist!.artists[1]
            playlistArtist2.text = playlist!.artists[2]
 }           
Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

Yeah I realized that shortly afterwards, sadly it does not fix the problem. Thank you though :)

When you say that stuff isn't showing up the way you want it to, what do you mean exactly? Are there any errors in your code when you run the app? Perhaps you have an auto-layout issue with some missing and/or misplaced constraints in your storyboard? If so, you may want to just clear all of your constraints and start fresh.

Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

I'm sorry if that was a bit unclear. Basically all of the info that is supposed to appear when you click on a playlist does not appear. Only the "placeholder text" and the placeholder images appear, instead of the text that was supposed to be fetched in this code:

if playlist != nil {
            playlistCoverImage.image = playlist!.largeIcon
            playlistCoverImage.backgroundColor = playlist!.backgroundColor
            playlistTitle.text = playlist!.title
            playlistDescription.text = playlist!.description

            playlistArtist0.text = playlist!.artists[0]
            playlistArtist0.text = playlist!.artists[1]
            playlistArtist0.text = playlist!.artists[2]

I have done some tests, like:

if playlist != nil {
println("Hi")
}

Nothing showed up, and therefore I figured the main problem behind all of this is that the playlist optional is returning nil, and therefore the actions within the if loop(not sure if that is the right term) are not being executed.
Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

I'm sorry if that was a bit unclear. Basically all of the info that is supposed to appear when you click on a playlist does not appear. Only the "placeholder text" and the placeholder images appear, instead of the text that was supposed to be fetched in this code:

if playlist != nil {
            playlistCoverImage.image = playlist!.largeIcon
            playlistCoverImage.backgroundColor = playlist!.backgroundColor
            playlistTitle.text = playlist!.title
            playlistDescription.text = playlist!.description

            playlistArtist0.text = playlist!.artists[0]
            playlistArtist0.text = playlist!.artists[1]
            playlistArtist0.text = playlist!.artists[2]

I have done some tests, like:

if playlist != nil {
println("Hi")
}

Nothing showed up, and therefore I figured the main problem behind all of this is that the playlist optional is returning nil, and therefore the actions within the if loop(not sure if that is the right term) are not being executed.

If your playlist object is nil then something went wrong connecting it to the MusicLibrary class.

The init(index: Int) constructor fires all this code - that looks fine in the above stuff.

Try writing the Dictionary out in Console once it has been instantiated - work out where the playlist can be created as nil and not progressed.

I have the code for this project but by the time it is finished there's quite a bit more to it so picking out your issue is difficult.

Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

I basically just copy-pasted the library from the teacher's notes, so I figured that it has to be correct. I just feel like I have gone through all of this code several times and I really can't locate the issue.

When you deleted the test IBOutlet in code, did you also make sure to delete the referencing outlet in the connections inspector in main.storyboard? That could cause issues with your data loading properly.

Immediately before the if playlist != nil put a statement; println("playlist \(playlist)")

See what that produces in the output.

Have you looked in the bottom output window in Xcode? It'll appear in the right hand pane of the two that comprise the bottom pane, if you understand that! (Not exactly clear!!)

Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

I did look there, however since I moved on with the track it might have something to do with the segue being removed between the master and the detail view controller. I will try this again as soon as I reestablish the connection with the touch-gesture instead.

Yes, if the segue has gone then the 'if' statement won't be reached.

Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

I have now reestablished the connection, and still nothing shows up in the console output. However if i put it outside the viewDidLoad function it displays an error: "Expected declaration". This does not happen inside the function.

I get the same - I think that's something to do with run-time code and class stuff. I don't really know.

But that is a compiler error which is nothing to do with the problem you have. You're running the code and not getting anything in the console when you call a println() just before the problem point. That means the code is never reaching that point. Try adding a breakpoint in the gutter to see if execution ever reaches that point.

Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

I added a breakpoint at the beginning of the viewDidLoad method, which was executed(I don't know the term for this, but to clarify, the app stopped and in Xcode it clarified that there was a breakpoint here.

This is odd!

Your breakpoint works as it halts execution but the println doesn't work in, basically, the same place.

We're missing something fundamental here and need to get right back to the execution path.

One last attempt - try a silly println("This code runs!!") just after super.viewDidLoad() - see if that appears in the console.

Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

Oddly enough, still nothing seems to be showing up.

Also, let me just clarify that I am extremely grateful for your effort in trying to help me :)

What is your operating system? Are you using xCode 6.1 or the 6.2 beta version?

Magnus - that code isn't being reached - the problem lies elsewhere. Let's have a think about the app navigation! Are your segues working? Do you move to the new ViewController when you tap the Master UIImage?

Kyle, I'm running Yosemite 10.10.1 and Xcode 6.1.1 - not a beta. ;-)

Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points

They seem to be working correctly, when I tap the UIImage I move to the playlistDetailView. This is what my views look like in the simulator.

http://cl.ly/image/3D2G220m1b3e http://cl.ly/image/3m2K2l3b1s2k

What does your segue function look like now? You amended a few things so let's start with that ...

Magnus Larsen
Magnus Larsen
Courses Plus Student 2,025 Points
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "ShowPlaylistDetailSegue" {
            let playlistDetailController = segue.destinationViewController as PlaylistDetailViewController

            playlistDetailController.playlist = Playlist(index: 0)
        }

    }


    @IBAction func showPlaylistDetail(sender: AnyObject) {

        performSegueWithIdentifier("showPlaylistDetailSegue", sender: sender)




    }

This is my segue function now.

OK - that's not revealing anything glaring, I don't think.

Try a couple of println()'s in there. e.g. println("I'm in showPlaylistDetail") and println("I'm in prepareForSegue")

There's something wrong somewhere - unfortunately, it might not be in the code. The storyboard stuff may be involved.

Woohoo \o/

We got there!!!

Gotta love Treehouse ...

How did you get there? I'm with the same problem.

Have you solved this problem? Make sure your Outlet connects the Label of the StoryBoard

Yes, I did it! Thank you very much!