This article has been updated for Swift 3
One of the most versatile UI elements which you come across in iOS development is UITableView.With a combination of custom cell and animation its possibilities are endless.From fancy menu to image scroll you must have found it at many places. In fact UITableView is so versatile that you can truly divide UI in two parts those which can be made using UITableView and those which cannot.I must admit in one of my lazy spur i rotated UITableView using CGAffineTransform to implement horizontal scroll.
XCode and Swift version used
XCode 8.2
Swift 3
Getting Started
In this tutorial you will be creating a simple UITableView with custom UITableViewCell using data from a plist file.We will use services of www.dummyimage.com they provide placeholder image in dimension and color you need.By the end of tutorial we will do following tasks:-
1.Create a Storyboard project
2.Setup UITableView in Storyboard
3.Create Custom UITableViewCell with .swift class
4.Use a plist file as data source.
5.Download image asynchronously.
Setting up project
Open XCode create a new project.Select “single tab” application on the resulting window
After that you will have to name your project and select language and other option.I have named my project ASTableViewTutorial you can choose a name of your choice however it will be convenient to follow names i have chosen.
you can have your own organization name and identifiers. Click “Next” and you have just created a project which will have a single view and will use Swift language.
Set up UITableView in Storyboard
Now you ned to select Main.storyboard file now in interface hierarchy you will see ViewController and when you open it you will se a view select it . Drag and drop UITableView into the view from “Object Library” as shown in following image
Setup the autolayout of tableview so that it occupies all the space on view.(If you are new to autolayouts then refer to autolayout tutorial for beginners) .Now set the tableview delegate and datasource to viewcontroller. Right click on the tableview select datasource drag to viewcontroller and leave as done in the following image
http://i1380.photobucket.com/albums/ah191/amar_11s/Amarendrasingh/coonectdelegate_zpsi8fublta.png
Do similarly for datasource.make outlet of your tableview in viewcontroller.swift file and name it asTableView .
@IBOutlet var asTableView:UITableView!;
.Now we have to create datasource and delegate methods in our ViewController.swift file ,first make your ViewController conform to the UITableView delegate and datasource.
class ViewController: UIViewController ,UITableViewDataSource,UITableViewDelegate
your class definition first line should look like this.
now copy paste the following methods in your ViwController.swift file
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0; } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { return UITableViewCell(); } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { }
As you can observe that we have used the bare minimum functions required.We are returning 0 and UITableViewCell(); just to suppress the error.Because we are yet to setup our datasource and custom cell. CONGRATSSS!!! you have successfully completed first step and setup UITableView on Storyboard. Moving ahead we will configure and setup our custom cell.
Creating custom UITableViewCell with custom .swift class
Drag a UITableViewCell from object gallery on your tableview.Set your tableview row height to 75 on tableview size inspector. You need to set your tableviewcell’s identifier in attribute inspector, see the following image
In the above image you can see that we have set the identifier in attribute inspector to “ASCustomTableViewCell“ Now add a UIImage and UILabel on your tableview cell from object gallery.Set the layouts of imageview and label such that imageview is of fixed height and width and label occupies all the remaining space(If you are new to autolayouts then refer to autolayout tutorial for beginners).Now your cell should look something like this (ignore the project navigator)
Now we will create a swift file for our custom tableviewcell . Go to project navigator right click on the ASTableViewTutorial and select new file -> select Cocoas Touch Class from resulting window->select UITableViewCell as subclass name your class ASCutomTableViewCell again you can choose any name,Let the language be swift click on next.
once you click on next you will see ASCutomTableViewCell.swift class on in your project navigator.
Now we will have to change the class of our custom tableviewcell. for that select your table view cell in interface editor and change class to ASCutomTableViewCell in Identity inspector as shown in following image.
So now you have set up the custom class for your tableview cell. we can now create outlet for your UIImage and UILabel in tableview cell, in ASCutomTableViewCell.swift. Open asistant editor and make outlets for both the ui elements as shown in image. Don’t worry about the extra code.
As you can see we have made two outlets
@IBOutlet var asUilabel: UILabel! @IBOutlet var ASImageView: UIImageView!
now we need to have a method which can set these UI elements so we will add this function
func setCellData(_ imageURL: String, andLabelText text:String ) { self.asUilabel.text = text; let url = URL(string: imageURL); DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async { let data1 = try? Data(contentsOf: url!); DispatchQueue.main.async { self.ASImageView.image = UIImage(data: data1!); } } }
as you can see in the code snippet above that you have just made a function which takes a url and text and sets them up in cell.Now your class code must be something like this
// // ASCutomTableViewCell.swift // ASTableViewTutorial // // Created by Amarendra on 3/8/16. // Copyright © 2016 AmarendraSingh.in All rights reserved. // import UIKit class ASCutomTableViewCell: UITableViewCell { @IBOutlet var asUilabel: UILabel! @IBOutlet var ASImageView: UIImageView! 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 setCellData(_ imageURL: String, andLabelText text:String ) { self.asUilabel.text = text; let url = URL(string: imageURL); let data1 = try? Data(contentsOf: url!); self.ASImageView.image = UIImage(data: data1!); } }
so you noticed that we are fetching image in synchronous mode !!! no issues you will do it later.
Setting up a plist file as datasource
We will now create a plist file and fill our image URL using www.dummyimage.com .First add a plist file in your project name it ASImageURLList.plist ,set its root to array type and add image url created using dummyimage the format is https://dummyimage.com/<size>/<hex color code> add them in your plist till “<size>” leave the color code part we will generate dynamic hex color code using Swift 3 UIColor Utilities .Now our datasource is ready.
We are not done yet we will create a database handler for out info plist.Lets create a singleton for it. to do this add a new cocoastouchfile to your project as subclass of NSObject name it ASImageHandlerSingleton Add the following line of code in global scope
// // ASImageHandlerSingleton.swift // ASTableViewTutorial // // Created by Amarendra on 3/8/16. // Copyright © 2016 AmarendraSingh. All rights reserved. // import UIKit class ASImageHandlerSingleton: NSObject { static let shareInsatance = ASImageHandlerSingleton(); fileprivate var arrayImage:NSArray?; override init(){ let path = Bundle.main.path(forResource: "ASImageURLList", ofType:"plist"); arrayImage = NSArray(contentsOfFile: path!); } func getImageUrl(_ index:NSInteger)->String{ let ar = self.arrayImage![index] as! String; return ar.appending(randomHexColorCode()); } func getCount()->NSInteger{ return self.arrayImage!.count-1; } func randomHexColorCode() -> String{ let a = ["1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"]; return "".appending(a[Int(arc4random_uniform(15))]).appending(a[Int(arc4random_uniform(15))]).appending(a[Int(arc4random_uniform(15))]) } }
As you can see you just overrode the init method to fetch data from our plist file and load it in our arrayImage. You also added two utility methods to get count and image url at index from the imageArray.
in order to use our plist as datasource we will have to do some changes in our ViewController file.In class scope add following code
var dataSource:ASImageHandlerSingleton!=ASImageHandlerSingleton();
we just created a ref of our singleton.
now in numberOfRowsInSection method return dataSource.getCount(); so we are returning number of rows depending upon elements in our datasource.
Now add the following code to cellForRowAtIndexPath
let cell = tableView.dequeueReusableCell(withIdentifier: "ASCustomTableViewCell", for: indexPath) as! ASCutomTableViewCell; cell.setCellData(dataSource.getImageUrl(indexPath.row),andLabelText: "tadddaa") return cell;
now your ViewController code should look like this
// // ViewController.swift // ASTableViewTutorial // // Created by Amarendra on 3/8/16. // Copyright © 2016 AmarendraSingh.in All rights reserved. // import UIKit class ViewController: UIViewController ,UITableViewDataSource,UITableViewDelegate{ @IBOutlet var ASTableView:UITableView!; var dataSource:ASImageHandlerSingleton!=ASImageHandlerSingleton(); override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return dataSource.getCount(); } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ASCustomTableViewCell", for: indexPath) as! ASCutomTableViewCell; cell.setCellData(dataSource.getImageUrl(indexPath.row),andLabelText: "tadddaa") return cell; } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { } }
We have not bothered with data for our label its just shows a simple text value. If every thing is fine you can now run your project.It should out put something like below.
did you notice the different color images you are downloading?. You must have noticed that the load is very slow and scroll is choppy.Yes you got it its because we loaded image in synchronous mode while setting up our cell time to revisit setCellData method of ASCutomTableViewCell .
change the code to
func setCellData(_ imageURL: String, andLabelText text:String ) { self.asUilabel.text = text; let url = URL(string: imageURL); DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async { let data1 = try? Data(contentsOf: url!); DispatchQueue.main.async { self.ASImageView.image = UIImage(data: data1!); } } }
as you see we dispatched the task on global thread so that the function returns immediately and once the data is fetched we grab hold of main thread to setup imageview’s image.
What you just did
In above tutorial you successfully create a UITableview in a project in Swift 3 using storyboard and used a plist file as your database.You also carried out asynchronous download of images from www.dummyimage.com .Guess what YOU ARE AWESOME !!!