I am using UISegmentControl to display objective type questions in table view. But, if I select one segment in any one of cell, then if I scroll, some segment values are changed. I dont know how to solve that.
Kindly guide me.
Cell size : 160px
Segment tint color : blue color
Coding
//UIViewController
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell
return cell
}
//UITableViewCell CLASS
class segmentTblCell: UITableViewCell {
#IBOutlet weak var segMent: UISegmentedControl!
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
}
}
Screen shot below:
You're having this problem because of how dequeueReusableCellWithIdentifier: works. Each time a cell get scrolled out of screen, it enters a cache area where it will be reused.
Let's say you have 100 cells. All their segmentedControl objects are set to first. You tap on one to change it's value. As the cell moves out of view, it enters the cache, where it will be dequeued if you scroll down further.
It's important to understand this, because the segmentedControl object is not actually changing. It looks like it's changing because of the dequeue behaviour.
To solve this problem, you will need to implement a dataSource that stores the segmentedControl object's value so you can reinitialize it correctly every time a cell is dequeued.
Method 1: Prevent reusability of cells by, Holding all cell objects in an array
var arraysCells : NSMutableArray = []//globally declare this
in viewDidLoad()
for num in yourQuestionArray//this loop is to create all cells at beginning
{
var nib:Array = NSBundle.mainBundle().loadNibNamed("SegmentTableViewCell", owner: self, options: nil)
var cell = nib[0] as? SegmentTableViewCell
arraysCells.addObject(cell!);
}
in tableViewDelegate,
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return arraysCells.objectAtIndex(indexPath.row) as! UITableViewCell
}
you can find the selected segment values (answer) by iterating arraysCells
NOTE: Method 1 will be slow, if you have big number of cells
Method 2: Reuse the cell as normal, but save the states(enterd values) Using Delegate and arrays.
in custom UITableViewCell
#objc protocol SegmentTableViewCellDelegate {
func controller(controller: SegmentTableViewCell, selectedSegmentIndex:Int, indexPath : NSIndexPath)
}
class SegmentTableViewCell: UITableViewCell {
var delegate: AnyObject?
var indexPath : NSIndexPath?
#IBOutlet weak var segment: UISegmentedControl! //outlet of segmented Control
#IBAction func onSegmentValueChanged(sender: UISegmentedControl/*if the parameter type is AnyObject changed it as UISegmentedControl*/)//action for Segment
{
self.delegate?.controller(self, selectedSegmentIndex: sender.selectedSegmentIndex, indexPath: indexPath!)
}
in viewController
class MasterViewController: SegmentTableViewCellDelegate{
var selectedAnswerIndex : NSMutableArray = [] //globally declare this
var selectedSegmentsIndexPath : NSMutableArray = [] //globally declare this
func controller(controller: SegmentTableViewCell, selectedSegmentIndex:Int, indexPath : NSIndexPath)
{
if(selectedSegmentsIndexPath.containsObject(indexPath))
{
selectedAnswerIndex.removeObjectAtIndex(selectedSegmentsIndexPath.indexOfObject(indexPath))
selectedSegmentsIndexPath.removeObject(indexPath)
}
selectedAnswerIndex.addObject(selectedSegmentIndex)
selectedSegmentsIndexPath.addObject(indexPath)
}
in cellForRowAtIndexPath (tableView Delegate)
if(selectedSegmentsIndexPath.containsObject(indexPath))
{
cell?.segment.selectedSegmentIndex = selectedAnswerIndex.objectAtIndex(selectedSegmentsIndexPath.indexOfObject(indexPath)) as! Int
}
cell?.delegate = self
cell?.indexPath = indexPath
you can get the result by
for index in selectedSegmentsIndexPath
{
var cellIndexPath = index as! NSIndexPath
var answer : Int = selectedAnswerIndex.objectAtIndex(selectedSegmentsIndexPath.indexOfObject(cellIndexPath)) as! Int
NSLog("You have enterd answer \(answer) for question number \(cellIndexPath.row)")
}
#KelvinLau's is perfect
you can do that by using var segmentedTracker : [NSIndexPath:Int] = [:]
on segmentedValueChanged set the value of the selectedIndex ie: segmentedTracker[indexPath] = valueOf the selected index
then in cellForRowAtIndexPath check for the value let selected = [segmentedTracker]
cell.yourSegmentedControlReference.selectedIndex = selected
please note this is a pseudocode I don't remember the properties name. From here you can figure it out by urself
I think to use UISegmentControl in UITableViewCell may be wrong.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UISegmentedControl_Class/
I have never seen the kind of that in iOS application.
The problem is that UITableViewCell is reused by dequeueReusableCellWithIdentifier method. So some UISegmentControl values are changed when scrolling.
Although it is not best solution, you can use Static Cells. What you need to do is that only switch Static cells. And If so, you don't write code of UITableViewCell.
Year 2018: Updated Answer
Find my easiest answer in this UISegement inside UITableViewCell
=======================================================
Year 2015
I have tested in my own way. My coding is below. Kindly guide me, whether it is right way or wrong way? My problem get solved. This code stops reusable cell.
My Coding Below:
//UIViewController
var globalCell = segmentTblCell() //CUSTOM UITableViewCell Class
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell
globalCell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell //THIS LINE - STOPS REUSABLE TABLE.
return cell
}
Related
Is there a way to reset tableview height so that no empty rows are showed. For an example, a tableview displays 3 rows but there is only one row having real data. I'd like the tableview shrinks it size so there is only one row display
I guess you have a View Controller like this
class Controller: UITableViewController {
private var data: [String?] = ["One", nil, "Three", nil, nil]
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCellID")!
cell.textLabel?.text = data[indexPath.row]
return cell
}
}
Since your model (data in my example) contains nil values you are getting a table view like this
One
_
Three
_
_
Removing the empty rows
Now you want instead a table view like this right?
One
Three
Filtering your model
Since the UI (the table view) is just a representation of your model you need to change your model.
It's pretty easy
class Controller: UITableViewController {
private var data: [String?] = ["One", nil, "Three", nil, nil]
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCellID")!
cell.textLabel?.text = data[indexPath.row]
return cell
}
override func viewDidLoad() {
data = data.filter { $0 != nil }
super.viewDidLoad()
}
}
As you can see, inside viewDidLoad() I removed the bill values from the data array. Now you'll get only cells for real values.
I think you need remove the empty data before execute func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int.
//EDITED
I give you this possible solution, maybe there are more ways to do it, you can try with this.
class MyViewController: UITableViewDataSource, UITableViewDelegate {
private var realHeight = 0
private var data : [String] = []
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCellID")!
cell.textLabel?.text = data[indexPath.row]
self.realHeight += self.tableView.rowHeight //Increase real height value.
return cell
}
func loadData() { //This function reload the data
self.realHeight = 0
self.tableView.reloadData()
//Update tableViewHeight here, use self.realHeight. You can use constraints or update directly the frame.
}
}
The solution is have a counter that represents the sum of all visibles rows height. e.g If you have n cells then your height will be self.tableView.rowHeight * n, then you ever will have an effective height.
I recommend you to create a constraint for the table height and when the cells change, you only need change the constant of the constraint, is more easy than change the frame.
I understand that I need to implement required methods in the controller and establish a relationship between view and controller.. but where do the identifier "tableView" in
func tableView(mintabell: UITableView, numberOfRowsInSection section: Int) -> Int
{
return items.count
}
come from and what if I want several tableviews on same view? How to declare them separately?
These are the protocols that you need to declare for a TableView
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return createCellAndReturnItHere
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfCellsInSection
}
In terms of having more than one tableview in one ViewController.. If you have an outlet for each tableview then you can check which one you need inside the protocol functions:
#IBOutlet weak var tableViewOne: UITableView!
#IBOutlet weak var tableViewTwo: UITableView!
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if tableView == self.tableViewOne {
return createCellForTableViewOneAndReturnItHere
} else {
return createCellForTableViewOneAndReturnItHere
}
}
Think of it like a box. Every tableView that is subscribed to the protocol grabs in that box leaves its fingerprint and takes what it gets. So if you have multiple tableViews in one controller you can distinguish them by checking for equality.
Example:
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let firstTableView = UITableView()
let secondTableView = UITableView()
viewDidLoad() {
firstTableView.delegate = self
secondTableView.delegate = self
firstTableView.dataSource = self
secondTableView.dataSource = self
}
// ... some othe methods...
func tableView(mintabell: UITableView, numberOfRowsInSection section: Int) -> Int
{
if tableView == firstTableView {
return 10
}
if tableView == secondTableView {
return 20
}
return 0
}
}
Delegates are implemented by the developer and called by iOS not the developer. The tableView is passed by iOS and points to the particular tableview.
If you have several tableviews with the same delegate you can compare the passed tableview parameter to the tableviews you have implemented to determine which one.
Alternatively, create a tableView delegate and datasource per tableView. This will eliminate testing which tableView removing a lot of conditional logic from the code.
First of all, you don't necessarily always have to implement a protocol for every view. Only when you have a view which has delegate that needs implementing, you will have to conform that protocol responsible for that delegate implementation.
So for tableView, first you drag a UITableView in your Controller from the Object Library and then a UITableViewCell under the Table View.
Now go to the ViewController.swift file and add
#IBOutlet var myFirstTableView: UITableView!
right after the line.
class ViewController: UIViewController
P.S: If you have more than one table then you could just declare the extra table's here., like-
#IBOutlet var mySecondTableView: UITableView!
Now, let's assume, you have one table. Now, you need to add the list of protocols. So, just add UITableViewDelegate, UITableViewDataSource with
class ViewController: UIViewController
appended by comma.
Adding this should give you an error but that's okay. This is because you have not added the required method listed under that UITableViewDatasource protocol.
So, just add those required methods and implement it accordingly.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("myCell") as! UITableViewCell
cell.textLabel?.text = "test"
return cell
}
Here, I said, I will have 3 cells whose identifier is "myCell" and the cell's textLabel will have a text, "test".
Now, we forgot a very important step and that is to assign the cell identifier to our TableView Cell. So, go to the storyboard and select the TableView Cell and insert "myCell" as an identifier for your cell.
If you had more than one table, then you would check for which TableView, you are loading your data. So, you could assign a unique tag to each table explicitly(you can do that either from storyboard or from code), and based on that tag, you would implement your methods. Let's say you have 3 tables and the assigned tag is 1,2 and 3. So, you could do something like,
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView.tag == 1{
return 3
}
else if tableView.tag == 2{
return 4
}
else{
return 1
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
if tableView.tag == 1{
cell.textLabel?.text = "test1"
}
else if tableView.tag == 2{
cell.textLabel?.text = "test2"
}
else{
cell.textLabel?.text = "test"
}
return cell
}
I have an app that has a custom button in a custom cell. If you select the cell it segues to the a detail view, which is perfect. If I select a button in a cell, the code below prints the cell index into the console.
I need to access the contents of the selected cell (Using the button) and add them to an array or dictionary. I am new to this so struggling to find out how to access the contents of the cell. I tried using didselectrowatindexpath, but I don't know how to force the index to be that of the tag...
So basically, if there are 3 cells with 'Dog', 'Cat', 'Bird' as the cell.repeatLabel.text in each cell and I select the buttons in the rows 1 and 3 (Index 0 and 2), it should add 'Dog' and 'Bird' to the array/dictionary.
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postsCollection.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: CustomCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
// Configure the cell...
var currentRepeat = postsCollection[indexPath.row]
cell.repeatLabel?.text = currentRepeat.product
cell.repeatCount?.text = "Repeat: " + String(currentRepeat.currentrepeat) + " of " + String(currentRepeat.totalrepeat)
cell.accessoryType = UITableViewCellAccessoryType.DetailDisclosureButton
cell.checkButton.tag = indexPath.row;
cell.checkButton.addTarget(self, action: Selector("selectItem:"), forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
func selectItem(sender:UIButton){
println("Selected item in row \(sender.tag)")
}
OPTION 1. Handling it with delegation
The right way of handling events fired from your cell's subviews is to use delegation.
So you can follow the steps:
1. Above your class definition write a protocol with a single instance method inside your custom cell:
protocol CustomCellDelegate {
func cellButtonTapped(cell: CustomCell)
}
2. Inside your class definition declare a delegate variable and call the protocol method on the delegate:
var delegate: CustomCellDelegate?
#IBAction func buttonTapped(sender: AnyObject) {
delegate?.cellButtonTapped(self)
}
3. Conform to the CustomCellDelegate in the class where your table view is:
class ViewController: CustomCellDelegate
4. Set your cell's delegate
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as CustomCell
cell.delegate = self
return cell
}
5. Implement the required method in your view controller class.
EDIT: First define an empty array and then modify it like this:
private var selectedItems = [String]()
func cellButtonTapped(cell: CustomCell) {
let indexPath = self.tableView.indexPathForRowAtPoint(cell.center)!
let selectedItem = items[indexPath.row]
if let selectedItemIndex = find(selectedItems, selectedItem) {
selectedItems.removeAtIndex(selectedItemIndex)
} else {
selectedItems.append(selectedItem)
}
}
where items is an array defined in my view controller:
private let items = ["Dog", "Cat", "Elephant", "Fox", "Ant", "Dolphin", "Donkey", "Horse", "Frog", "Cow", "Goose", "Turtle", "Sheep"]
OPTION 2. Handling it using closures
I've decided to come back and show you another way of handling these type of situations. Using a closure in this case will result in less code and you'll achieve your goal.
1. Declare a closure variable inside your cell class:
var tapped: ((CustomCell) -> Void)?
2. Invoke the closure inside your button handler.
#IBAction func buttonTapped(sender: AnyObject) {
tapped?(self)
}
3. In tableView(_:cellForRowAtIndexPath:) in the containing view controller class :
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell
cell.tapped = { [unowned self] (selectedCell) -> Void in
let path = tableView.indexPathForRowAtPoint(selectedCell.center)!
let selectedItem = self.items[path.row]
println("the selected item is \(selectedItem)")
}
Since you have 1 section in the table view you can get the cell object as below.
let indexPath = NSIndexPath(forRow: tag, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CustomCell!
where tag you will get from button tag.
Swift 3
I just get solution for access cell in #IBAction function using superview of button tag.
let cell = sender.superview?.superview as! ProductCell
var intQty = Int(cell.txtQty.text!);
intQty = intQty! + 1
let strQty = String(describing: intQty!);
cell.txtQty.text = strQty
#IBAction func buttonTap(sender: UIButton) {
let button = sender as UIButton
let indexPath = self.tableView.indexPathForRowAtPoint(sender.center)!
}
I updated option 1 of the answer from Vasil Garov for Swift 3
1. Create a protocol for your CustomCell:
protocol CustomCellDelegate {
func cellButtonTapped(cell: CustomCell)
}
2. For your TableViewCell declare a delegate variable and call the protocol method on it:
var delegate: CustomCellDelegate?
#IBAction func buttonTapped(sender: AnyObject) {
delegate?.cellButtonTapped(self)
}
3. Conform to the CustomCellDelegate in the class where your tableView is:
class ViewController: CustomCellDelegate
4. Set your cell's delegate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as CustomCell
cell.delegate = self
return cell
}
5. Implement the required method in your ViewController.
Based on Cao's answer, here is a solution to handle buttons in a collection view cell.
#IBAction func actionButton(sender: UIButton) {
let point = collectionView.convertPoint(sender.center, fromView: sender.superview)
let indexPath = collectionView.indexPathForItemAtPoint(point)
}
Be aware that the convertPoint() function call will translate the button point coordinates in the collection view space. Without, indexPath will always refer to the same cell number 0
XCODE 8: Important Note
Do not forget to set the tags to a different value than 0.
If you attempt to cast an object with tag = 0 it might work but in some weird cases it doesn't.
The fix is to set the tags to different values.
Hope it helps someone.
I have a strange issue with my tableView.
I have a List of audio tracks and a segue to an audio player in order to play the selected track at a specific row. Everything works fine!
I wanted to change the background color for the selected row in the table so that, once the user play the audio and come back to the list of tracks (my Table View Controller) , he can see which are the previously selected rows.
But when I run It change me the color not only for the row at index path I selected but also to the item at index path + 10.
If I select the First Row it change me the color for the row at the index: 0, 10, 20, 30...
In order to change the color of the selected cell I did the follow:
// MARK: - Navigation
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("audioPlayer", sender: tableView)
var selectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath) as CustomTableViewCell
selectedCell.contentView.backgroundColor = UIColor.greenColor()
selectedCell.backgroundColor = UIColor.blueColor()
Please find a screenshot of my issue, I have selected just three rows: 1, 3, 5 but I get selected 1,3,5,11,13,15,21,23 and so on... :
https://www.dropbox.com/s/bhymu6q05l7tex7/problemaCelleColore.PNG?dl=0
For further details - if can help - here it is my Custom Table View class:
import UIKit
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var artista: UILabel!
#IBOutlet weak var brano: UILabel!
var ascoltato = false
#IBOutlet weak var labelRiproduciAscoltato: 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
}
func setCell(artista: String, brano: String){
self.artista.text = artista
self.brano.text = brano
}
} // END MY CUSTOM TABLE VIEW CELL
Here it is the method cellForRowAtIndexPath in my TableViewController:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath) as CustomTableViewCell
var tracks : Brani //Brani is my custom Object for handle my tracks
cell.setCell(tracks.title!, brano: tracks.author!)
return cell
}
I am running on iPad Air with iOS 7.1.
Thank you in advance for any suggestion or advice related to my issue.
This is probably because UITableViewCells are recycled. This means the formerly selected tableViewCell gets reused by the cells at the lower indexes. This is expected behavior of a UITableView and makes sense, as it saves memory usage. To fix the issue, you will need to have your datasource keep a track of which cell is selected, and updated the cell's background color accordingly.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("audioPlayer", sender: tableView)
//datasource is updated with selected state
//cell is updated with color change
}
Then in your cellForRowAtIndexPath method:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath) as CustomTableViewCell
var tracks : Brani //Brani is my custom Object for handle my tracks
cell.setCell(tracks.title!, brano: tracks.author!)
//update cell style here as well (by checking the datasource for selected or not).
return cell
}
the main role is to display the playlists names in table view, but it show me word "name" in about 500 cells!
I can make a simple errors, because i only learning swift, and it is my first programming language
There is the code:
import UIKit
import MediaPlayer
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var tableData = MPMediaQuery.playlistsQuery()
var songname: NSString = MPMediaPlaylistPropertyName
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.tableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.tableData.items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel.text = songname
return cell
}
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("Row \(indexPath.row) selected")
}
}
Your problem is that you're displaying MPMediaPlaylistPropertyName in the cell which is most likely just the constant string "name"
What you need to do is set the cell's textLabel with the actual name of the playlist which would look something like this in your cellForRowAtIndexPath method
Replace
cell.textLabel.text = songname
With
let playlist: MPMediaPlaylist = tableData.collections[indexPath.row] as MPMediaPlaylist
let playlistName = playlist.valueForProperty(MPMediaPlaylistPropertyName) as NSString
cell.textLabel.text = playlistName;
Also, you need to make sure you're getting the count from the collections of the tableData so in your number of rowsInSectionMethod change:
return self.tableData.items.count
to
return self.tableData.collections.count
For A bit more understanding, what we're doing in the cellForRowAtIndexPath now is:
Getting a specific MPMediaPlaylist item for that particular row
Getting the Name of the playlist and assigning it to a variable
Assigning that name to the cells textLabel
Let me know if you have any other questions
You have to cleanup the cell data since you are re-using the cells,
Right after line
var cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
do
cell.textLabel.text = ""