• Skip to main content
  • Skip to primary sidebar

Ravi Shankar

Tweaking Apps

  • Swift
  • Tech Tips

ios

Add annotations and Polyline to MapView in Swift

July 6, 2015 By Ravi Shankar 21 Comments

In this article, we will see the instructions for adding annotation to MapView, Draw Polylines and Zoom to a region in Swift. Let us see this by adding stations to a Map for Chennai subrban trains and connect these stations using Map Overlay.

Project Setup

 

Create a new project by selecting Single View Application as the project template.

Enter the required information such project name, organization identifier etc.. as shown in the below screenshot. Then save the project in your desired location.

Add MapKit View

 

Navigate to Project navigator and select Main.storyboard file.

We are not using the Auto Layout for this demo, hence disable Use Auto Layout and disable size classes using the options available as part of the File Inspector

Drag and drop MapKit View from object library to the View Controller and make sure to resize the MapView to full view. Add IBOutlet in the ViewController for the MapKit and connect it to the MapKit View in the Interface builder. Also add import MapKit to include MapKit framework for your project.

[code language=”swift”]@IBOutlet weak var mapView: MKMapView!
[/code]

Now if you do a build and run the project in iPhone 6 simulator, you should see the following on simulator.

Zoom to specified region

 

Add the follwing piece of code in ViewController.swift file. And call this function from ViewController’s viewDidLoad function.

[code language=”swift”]//MARK:- Zoom to region

func zoomToRegion() {

let location = CLLocationCoordinate2D(latitude: 13.03297, longitude: 80.26518)

let region = MKCoordinateRegionMakeWithDistance(location, 5000.0, 7000.0)

mapView.setRegion(region, animated: true)
}
[/code]

 

CLLocationCoordinate2D is created by specifying latitude and longitude of the zoom location. Then using MKCoordinateRegionMakeWithDistance set the distance around the speicifed location. Then this region will set as the region for the MapView. Build and run the project should show Map zooming to the speicifed region as shown below.

 

Add plist file to project.

 

All the station details such as title, latitude and longitude are stored in a plist file. You can download the plist from gitHub. Right click on the Project folder (Project navigator) and select “Add Files to <Project name>” option. And select Copy items if needed option while adding the file.

The sample data structure of the plist file is shown below

 

Add place holder class Station

Create a new model class for holding the station data. This class should conform to MKAnnotation and NSObject protocol.

[code language=”swift”]import MapKit

class Station: NSObject, MKAnnotation {
var title: String?
var subtitle: String?
var latitude: Double
var longitude:Double

var coordinate: CLLocationCoordinate2D {
return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}

init(latitude: Double, longitude: Double) {
self.latitude = latitude
self.longitude = longitude
}
}[/code]

 

This class has properties for title, subtitle, latitude, longitude and coordinate. Any mappoint should have coordinate for the adding it to the map. This property is mandatory and it is defined in MKAnnotation protocol. The initializer in the class accepts the latitide and longitude details as they are needed for creating the coordinates.

Add annotation to MapKit

We need to iterate through the plist file and create annotation for each stations. Add the following function to ViewController.swift which does the same.

[code language=”swift”]//MARK:- Annotations

func getMapAnnotations() -&gt; [Station] {
var annotations:Array = [Station]()

//load plist file
var stations: NSArray?
if let path = NSBundle.mainBundle().pathForResource("stations", ofType: "plist") {
stations = NSArray(contentsOfFile: path)
}

//iterate and create annotations
if let items = stations {
for item in items {
let lat = item.valueForKey("lat") as! Double
let long = item.valueForKey("long")as! Double
let annotation = Station(latitude: lat, longitude: long)
annotation.title = item.valueForKey("title") as? String
annotations.append(annotation)
}
}

return annotations
}
[/code]

Add the following piece of code in viewDidLoad function.

[code language=”swift”]let annotations = getMapAnnotations()
// Add mappoints to Map
mapView.addAnnotations(annotations)[/code]

Now if you build and run the project, you should see the map with annotations. And on tapping any mappoint should display the title for that station.

Add Polyline to MapView

In order add Polyline overlay to map, we need to implement function defined in MKMapViewDelegate protocol. Add MkMapViewDelegate in the class declaration after UIViewController.

[code language=”swift”]class ViewController: UIViewController, MKMapViewDelegate {[/code]

Then make sure to set the delegate property of the mapview to self so that the ViewController can implement and handle the MKMapViewDelegate functions. Add the following piece of code in viewDidLoad function after the annotations.

[code language=”swift”]
mapView.delegate = self
// Connect all the mappoints using Poly line.

var points: [CLLocationCoordinate2D] = [CLLocationCoordinate2D]()

for annotation in annotations {
points.append(annotation.coordinate)
}
var polyline = MKPolyline(coordinates: &amp;points, count: points.count)
mapView.addOverlay(polyline)
[/code]

create a array of CLLocationCoordinate2D by iterating through annotations. Then create an instance of MKPolyline class by passing array of CLLocationCoordinate2D and count of coordinates. Finally add this polyline to mapView overlay.

Implement the rendererForOverlay MKMapViewDelegate function and return an insatnce of MKPolylineRenderer class

[code language=”swift”]
//MARK:- MapViewDelegate methods

func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -&gt; MKOverlayRenderer! {
if overlay is MKPolyline {
var polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.strokeColor = UIColor.blueColor()
polylineRenderer.lineWidth = 5
return polylineRenderer
}

return nil
}
[/code]

 

Now build and run the app should display the Polyline on the Map.

Download the source code from here

Filed Under: ios, Programming, Swift, Xcode

Navigation Controller in iOS

July 1, 2015 By Ravi Shankar 1 Comment

Navigation contollers are quite commonly used in iOS App. Navigation Controllers contain stack of view controllers and provide a drill down approach for accessing the child view controllers. The top bar in a navigation controller is called the navigation bar which normally contains the title of the screen. The navigation bar in child View Controller will have a back button that appears automatically and will take you to Root ViewController.

Listed below are screenshots of apps with navigation controller.

Example Apps

 

Calendar App

Music App

The objective of this Navigation Contorller article is to explain the following

  1. How to embed ViewController inside Navigation Controller
  2. Add Title to Navigation Bar
  3. Creating a Push Segue
  4. ViewController transitions using Segue and programmatically
  5.  Programmatically dismiss ViewController.
  6. Add toolbars to navigation controller

Project Setup

Let us see the functioning of navigation controller with an example project. This project displays list of different colours and drill down on each colours will set the background of the ViewController to choosen colour.

Create a new Xcode project selecting tamplate as Single View Application.

In the Choose options for your new project, select Language as Swift.

Embed ViewController inside Navigation Controller

Navigate to Main.storyboard file in the project navigator and select ViewController. Then unmark the check boxes with caption as Use Auto Layout and Use Size Classes (using File Inspector) as this app is onlye for iPhone and not any other devices,

Now embed the ViewContoller inside a navigation contoller by selecting Navigation Contoller option under Editor -> Embed In menu option. The ViewController will be embeded in Navigation Controller as shown below.

Add Colours Enum

Add a new Swift file to the project and name the file and Colours. Open the file for editing and add the following code snippet.

[code language=”swift”]
enum Colours: String {
case Blue = “0000FF”
case Cyan = “00FFFF”
case Gold = “FFD700”
case Green = “008000”
case Khaki = “F0E68C”
case Orange = “FFA500”
case Red = “FF0000”
case Skyblue = “87CEEB”
case Tan = “D2B48C”
case Violet = “EE82EE”

static let allValues = [Blue,Cyan,Gold,Green,Khaki,Orange,Red,Skyblue,Tan,Violet]

func getDisplayName() -> String {
var displayName = “”

switch (self) {
case .Blue:
displayName = “Blue”
case .Cyan:
displayName = “Cyan”
case .Gold:
displayName = “Gold”
case .Green:
displayName = “Green”
case .Khaki:
displayName = “Khaki”
case .Orange:
displayName = “Orange”
case .Red:
displayName = “Red”
case .Skyblue:
displayName = “SkyBlue”
case .Tan:
displayName = “Tan”
case .Violet:
displayName = “Violet”
}
return displayName
}

static func getColours() -> [String] {
var colours:[String] = []

for colour in Colours.allValues {
colours.append(colour.getDisplayName())
}
return colours
}

static func getEnumFromSelectedValue(selectedRow: Int) -> Colours{

var selected:Colours?

switch (selectedRow) {
case Colours.Blue.hashValue:
selected = .Blue
case Colours.Cyan.hashValue:
selected = .Cyan
case Colours.Gold.hashValue:
selected = .Gold
case Colours.Green.hashValue:
selected = .Green
case Colours.Khaki.hashValue:
selected = .Khaki
case Colours.Orange.hashValue:
selected = .Orange
case Colours.Red.hashValue:
selected = .Red
case Colours.Skyblue.hashValue:
selected = .Skyblue
case Colours.Tan.hashValue:
selected = .Tan
case Colours.Violet.hashValue:
selected = .Violet
default:
break
}

return selected!
}

// Credit below function to http://www.anthonydamota.me/blog/en/use-a-hex-color-code-with-uicolor-on-swift/

static func getUIColorFromHex(colorCode: String, alpha: Float = 1.0) -> UIColor{
var scanner = NSScanner(string:colorCode)
var color:UInt32 = 0;
scanner.scanHexInt(&color)

let mask = 0x000000FF
let r = CGFloat(Float(Int(color >> 16) & mask)/255.0)
let g = CGFloat(Float(Int(color >> 8) & mask)/255.0)
let b = CGFloat(Float(Int(color) & mask)/255.0)

return UIColor(red: r, green: g, blue: b, alpha: CGFloat(alpha))
}
}
[/code]

In the above code snippet, we have added enum that holds a list of colours and following functions

  • getDisplayName() – Retrieve the Colour name from Enum value
  • getColours() – Returns the list of colours.
  • getEnumFromSelectedValue() – Return enum on based on selected value
  • getUIColorFromHex() – returns the UIColor object based on Hex Colour code.

Adding UITableView

In order to display different colours, let us add a UITableView to the ViewController (which is embeded in Navigation Controller). Drag and drop a UITableView from Object library to the ViewController. Then set the datasource and delegate property of the tableview to the ViewController. Add IBOutlet TableView variable and connect it to the UITableView in the Interface Builder. If you find difficulty in following these steps check out UITableView demo in Swift.

Setup data for TableView

Add an instance level variable to the ViewController class for storing data

[code language=”swift”]var data:[String] = [String]()[/code]

And in viewDidLoad function add this line data = Colours.getColours() to populate data with the array of colours. Then implement the following UITableViewDataSource methods numberOfRowsInSection and cellForRowAtIndexPath as shown below.

[code language=”swift”]//MARK:- UITableViewDataSource methods

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(“CellIdentifier”, forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = data[indexPath.row]
return cell
}
[/code]

Navigate to Main.storyboard file and add UITableViewCell to the TableView. Make sure to provide identifier for the prototype cell as “CellIdentifier”. Now if you build and run the project you sould see the initial screen with empty navigation bar and with following set of colours

Add Title to Navigation Bar

You can use Interface builder to add title to navigation bar by double clicking on the center of the Navigation bar.

And if you want to add title programmatically then use the following code snippet. Place this code snippet in viewDidAppear function.

[code language=”swift”] navigationItem.title = “Colours”
[/code]

Create Push Segue

Drag and drop UIViewController from object library on to Storyboard. Now to setup relationship between this View Controller and the ViewController embeded in Navigation Controller you need to create a Push segue. This can be done by selecting the Prototype cell then press Control and drag drop to the new ViewController. Select the type of Segue as Push as shown below.

After creating the push segue relationship, you should notice that the newly added ViewController has a navigation bar at the top. Now if you build and run the project, you should be able to navigate between the ViewControllers (Did you notice the Colours button?).

Change background colour

We need to add the functionality that when a user taps any colour in the Main ViewContorller, the background colour of the child ViewController will be set to the selected colour.

Add a new file and choose the template for your new file as Cocoa Touch Class.

Make the new class as Subclass of UIViewController and provide the name as ColourViewController.swift

Using the Interface builder, set the class as ColourViewController (Identity Inspector) and also provide the Storyboard ID as ColourViewController

Now add colour property to the ColourViewController and this will hold enum value of the selected colour in the ManiViewController.

[code language=”swift”]
var colour: Int?[/code]

And in the viewDidLoad function add the following code snippet.

[code language=”swift”]override func viewDidLoad() {
super.viewDidLoad()

if let colour = colour {
let hex:Colours = Colours.getEnumFromSelectedValue(colour)
view.backgroundColor = Colours.getUIColorFromHex(hex.rawValue, alpha: 1.0)

navigationItem.title = hex.getDisplayName()
}
}[/code]

The above code snippet retrieves the colour enum and corresponding UIColor by passing the color hex code. This colour is then set as the background colour of the current view. Also the display name of the colour is set as the title for the navigation bar.

Add prepareForSegue funciton

Navigate to back to the ViewController.swift file and add the following prepareForSegue funciton.

[code language=”swift”]//MARK:- PrepareForSegue

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == “Colour” {
let colourViewController:ColourViewController = segue.destinationViewController as! ColourViewController
let selectedRow = tableView.indexPathForSelectedRow()?.row
colourViewController.colour = selectedRow
}
}[/code]

The above function instantiates the ColourViewContoller from segue.destinationViewController and sets the selected colour form the tableView to the colour property of the ColourViewController.

Now if you build and run the app, you should see the list of colours and on selecting any colour shoud take you to the Child ViewController and setting the background colour to the selected colour. Also you should be able to navigate back by tapping the Colours button in the navigation bar.

Adding toolbars to Navigation Controllers

Let us see how to programmatically add toolbars to a ViewController embeded in a Navigation Controller. Open ViewController.swift for editing and add the following functions

[code language=”swift”]//MARK:- Add toolbar items
func addToolBarItems() {

let segue = UIBarButtonItem(title: “Segue”, style: .Plain, target: self, action: “segueCall”)
let nonSegue = UIBarButtonItem(title: “Non Segue”, style: .Plain, target: self, action: “nonSegueCall”)
let seperator = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: self, action: nil)

var items = [segue,seperator,nonSegue]

self.setToolbarItems(items as [AnyObject], animated: true)
navigationController?.setToolbarHidden(false, animated: true)
}

//MARK:- Segue call
func segueCall(){
performSegueWithIdentifier(“Colour”, sender: self)
}

//MARK:- Non Segue call
func nonSegueCall() {
let childViewController = storyboard?.instantiateViewControllerWithIdentifier(“ColourViewController”) as! ColourViewController
navigationController?.pushViewController(childViewController, animated: true)
}[/code]

addToolBarItems funciton creates a UIBarButtonItems along with a separator (flexible space). These array of UIBarButtonItems are then added to the ViewController using setToolBarItems function. Also we need to unhide the toolbar in navigation contoller using setToolbarHidden function.

The segueCall function shows how to programmatically call segue transition using performSegueWithIdentifier. The nonSegueCall function is used for ViewController transitions inside navigation controller but without using a Segue. Build and Run the app should now display toolbar at bottom of the ViewController.

Finally we will see how to programmatically dismiss ViewController embeded in navigation controller. Open ColourViewController.swift for editing and add the following piece of code which add a toolbar item and dismiss the ViewController by calling navigationController?.popViewControllerAnimated(true)

[code language=”swift”]//MARK:- Add toolbar items

func addToolBarItems() {

let nonSegue = UIBarButtonItem(title: “Non Segue”, style: .Plain, target: self, action: “nonSegueCall”)
var items = [nonSegue]

self.setToolbarItems(items as [AnyObject], animated: true)
}

func nonSegueCall() {
navigationController?.popViewControllerAnimated(true)
}[/code]

Tapping on Non Segue should dismiss the Child ViewController and take you to the main ViewController.

Download the source code from here.

Filed Under: ios, Xcode Tagged With: NavigationController, Segue, Toolbars

Swift Demo – Add Progress Bar

June 24, 2015 By Ravi Shankar Leave a Comment

In this short tutorial, we will see the steps required to add UIProgressView to a Swift IOS Project.

UIProgressView and UILabel showing the current progress will be added programmatically to the View Controller. Create a Single View Application and navigate to ViewController.swift file.

Add UIProgressView and UILabel

Add the following code snippet below the class definition. This code snippet adds variables for UILabel and UIProgressView.

[code language=”swift”] var progressView: UIProgressView?
var progressLabel: UILabel?
[/code]

Now add the following function which initialises and adds UIProgressView and UILabel to the view.

[code language=”swift”]//MARK:- Controls
func addControls() {
// Create Progress View Control
progressView = UIProgressView(progressViewStyle: UIProgressViewStyle.Default)
progressView?.center = self.view.center
view.addSubview(progressView!)

// Add Label
progressLabel = UILabel()
let frame = CGRectMake(view.center.x – 25, view.center.y – 100, 100, 50)
progressLabel?.frame = frame
view.addSubview(progressLabel!)
}
[/code]

ProgressView style can be set to Default or Bar type. And UILabel needs to be appear just above the ProgressView hence we added an offset from view center.

Add GestureRecogonizers

This demo starts and resets the progress on single and double tap gesture event. The following code snippet adds single and double tap gesture recognisers to the view. This also specifies the function that needs to be called when user does a single or double tap.

[code language=”swift”]func addGestures() {
// Add Single Tap and Doube Tap Gestures
let tap = UITapGestureRecognizer(target: self, action: "handleTap:")
tap.numberOfTapsRequired = 1

let doubleTap = UITapGestureRecognizer(target: self, action: "handleDoubleTap:")
doubleTap.numberOfTapsRequired = 2

view.addGestureRecognizer(tap)
view.addGestureRecognizer(doubleTap)
tap.requireGestureRecognizerToFail(doubleTap)
}
[/code]

Now add the required functions for the gesture recogonizer events.

[code language=”swift”]// Start Progress View
func handleTap(sender: UITapGestureRecognizer) {
if sender.state == .Ended {
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "updateProgress", userInfo: nil, repeats: true)
}
}
//MARK:- Double Tap
// Reset Progress View
func handleDoubleTap(sender: UITapGestureRecognizer) {
if sender.state == .Ended {
progressView?.progress = 0.0
progressLabel?.text = "0 %"
timer?.invalidate()
}
}[/code]

Display Progress

The actual progress will be displayed by the following piece of code in the updateProgress function. You can change progress interval by setting appropriate value to progress property of UIProgressView.

[code language=”swift”]//MARK:- Increment Progress
func updateProgress() {
progressView?.progress += 0.05
let progressValue = self.progressView?.progress
progressLabel?.text = "\(progressValue! * 100) %"
}[/code]

Finally we need to add the addControls and addGestures to the viewDidLoad method.

[code language=”swift”]override func viewDidLoad() {
super.viewDidLoad()
addControls()
addGestures()
}[/code]

Download source code from here (SwiftDemo – ProgressView)

Filed Under: ios, Xcode Tagged With: Gestures, UIProgressView

DatePicker Demo in Swift

June 17, 2015 By Ravi Shankar 6 Comments

In this short tutorial, we are going to see the steps required use DatePicker in a iOS / Swift project. This demo is done by adding the DatePicker controls to Interface Builder and not programmatically.

Date Picker Mode

Date Picker control allow developers to specify the mode such as Date, Time, Date and Time and Count Down Timer. Listed below are the screenshots of each Date Picker mode.

Date Picker (Mode – Time)

Date Picker Mode set to time

Date Picker (Mode – Date)

Date Picker Mode set to Date

Date Picker (Mode – Date and Time)

Date and Time mode set for Date Picker

Using the Date and Time mode does not provide option to pick year. Hence in this demo we are going to use two date picker controls, one for date and another for time.

Add ViewContoller and Controls

Add a View Controller (or use existing ViewController) to storyboard then drag and drop 2 date picker controls to the View Controller. Also add a UILabel for displaying the selected date and time values. For the first Date Picker set the mode to Date and for the second as Time.

Add DatePickerController class

Now add a new file to the project and choose the template as Cocoa Touch class. Provde the name for your class file as DatePickerController. Add the following lines of code that adds IBOutlets to the ViewController

[code language=”swift”]@IBOutlet var datePicker:UIDatePicker!
@IBOutlet var timePicker:UIDatePicker!
@IBOutlet var dateTimeDisplay:UILabel![/code]

Select the ViewController in the Storyboard and set the class in the Identity Inspector to DatePickerController. Now click Show Assistant Editor then Control + drag and drop date picker to class file. Select connect as Action and provide the name for the function as datePickerChanged.

Now you should see the following function added to your class file.

[code language=”swift”]
@IBAction func datePickerChanged(sender: AnyObject) {
}[/code]

Repeat this exercise for the TimePicker (second date picker control) with function name as timePickerChanged.

[code language=”swift”]@IBAction func timePickerChanged(sender: AnyObject) {
}[/code]

Also make sure to connect all the IBOutlets from the class file to the corresponding controls in View Controller.

Set Date and Time

Add the following piece of Date Formatter code just below the IBOutlets definition. We are using two instance of NSDateFormatter to specify the date and time style for each date picker controls.

[code language=”swift”]let dateFormatter = NSDateFormatter()
let timeFormatter = NSDateFormatter()[/code]

Add the following function that formats the date and time and assigns the value to UILabel.

[code language=”swift”]//MARK:- Date and time
func setDateAndTime() {
dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
timeFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
dateTimeDisplay.text = dateFormatter.stringFromDate(datePicker.date) + ” ” + timeFormatter.stringFromDate(timePicker.date)
}[/code]

Add the function call to the date picker’s Value Changed methods.

[code language=”swift”]@IBAction func datePickerChanged(sender: AnyObject) {
setDateAndTime()
}
@IBAction func timePickerChanged(sender: AnyObject) {
setDateAndTime()
}[/code]

Download the source code from here (SwiftDemo -> DatePicker)

Filed Under: ios, Programming, Xcode Tagged With: DatePicker, Swift

TableView Demo in Swift

June 10, 2015 By Ravi Shankar 1 Comment

In this tutorial, we will see some of the common UITableView operations such as Adding, Updating, Deleting and Moving records using Swift.

Let us start with a TableView placed over a ViewController instead of using UITableViewController. By this way you will learn lot more about the functionality of UITableView. Add a new file and select Cocoa Touch Class as a template for the new file.

In “Choose options for your new file” screen, enter the class name as TableViewDemoController with subclass as UIViewController. Then save the new file under your preferred location.

User Interface

Navigate to Main.stotyboard then drag and drop a ViewController from Object Libray to Storyboard. Select the ViewController and click Show Identity Inspection and enter the class name as “TableViewDemoController”

Drag and drop Table View from object library to the View Controlller and make sure Table View is aligned properly. Now place a Table View Cell from object library on top of the TableView.

Set the identifier for Prototype cell to “CellIdentifier” using Show Identity Inspector.

Now select the tableview in the Document Outline pane and click Connection Inspector under Utilies pane. Connect the dataSource and delegate Outlets to the TableViewDemoController (yellow color circle on top View Controller)

Display Data

In this demo, we will be seeing how to display list of Socia Media icons. Here are the steps to load those icons in TableView.

First create a Struct that would act as a place holder for holding the name and image file name. Right click on the Project, select New File. In template screen, choose Swift file and provide name as SocialMedia and save the file.

Edit SocialMedia.swift and add the following code snippet. Apart name and imageName property, this also has computed property that returms UIImage based upon the image file name.

[code language=”swift”]import UIKit

struct SocialMedia {

var name:String
var imageName:String
var image: UIImage {
get {
return UIImage(named: imageName)!
}
}
}[/code]

Now Drag and drop social icon images from folder to Xcode project (download images from gitHub repoistory). Navigate TableViewDemoController.swift and add the following code snippet.

[code language=”swift”]var data:[SocialMedia] = [SocialMedia]()

//MARK:- Populate data

func loadData() -> [SocialMedia] {

data.append(SocialMedia(name:"Evernote",imageName:"evernote"))
data.append(SocialMedia(name:"Facebook",imageName:"facebook"))
data.append(SocialMedia(name:"GitHub",imageName:"github"))
data.append(SocialMedia(name:"Google",imageName:"google"))
data.append(SocialMedia(name:"LinkedIn",imageName:"linkedin"))
data.append(SocialMedia(name:"Paypal",imageName:"paypal"))
data.append(SocialMedia(name:"Pinterest",imageName:"pinterest"))
data.append(SocialMedia(name:"Twitter",imageName:"twitter"))
data.append(SocialMedia(name:"Vimeo",imageName:"vimeo"))
data.append(SocialMedia(name:"youtube",imageName:"YouTube"))

return data
}
[/code]

We have declared an array called data which will hold all the SocialMedia icon related information. The function loadData is used for adding all the social media images. Now call this function in the viewDidLoad method.

[code language=”swift”]override func viewDidLoad() {
super.viewDidLoad()
// call loaddata
loadData()
}
[/code]

In order display data, ViewController needs to conform UITableViewDataSource protocol. Add UITableViewDataSource
to the class declaration next to UIViewController.

[code language=”swift”]class TableViewDemoController: UIViewController, UITableViewDataSource {
[/code]

Then implement the following methods in TableViewDemoController class, these required methods when a class conforms to UITableViewDataSource protocol.

[code language=”swift”]//MARK:- UITableViewDataSource methods

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

var cell = tableView.dequeueReusableCellWithIdentifier("CellIdentifier") as! UITableViewCell

let mediaIcon = data[indexPath.row] as SocialMedia

cell.textLabel?.text = mediaIcon.name
cell.imageView?.image = mediaIcon.image

return cell
}
[/code]

Finally we need to create IBOutlet for tableView and connect with tableView control in Storyboard.

[code language=”swift”]@IBOutlet var tableView: UITableView!
[/code]

Now you should be able to build and run the project. This should show list all Social Media icons as shown below

Customize UITableView

In order the customize the tableview, the TableViewDemoController class needs to conform to UITableViewDelegate protocol. Let us say you want to increase the height of tableview rows. Then implement the function heightForRowAtIndexPath to return the height for each row.

[code language=”swift”]func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60.0
}
[/code]

Build and run the project should show the difference in height.

Add and Update row

Navigate to Main.storyboard and add a new View Controller to Interface builder. This View Controller will be used for capturing name of the icon when adding a new row.

This View Controller has a text field to accept the name of the Social Media icon, Done button to save the entered informatiom and Cancel button to cancel the operation. Make sure to create Unwind segue for Done and Cancel button by Control drag and drop each button to Exit icon on the View Controller. Also provide the identifer for the Unwind segue as addAction and cancelAction.

Navigate to TableViewDemoController and add Bar Button Item to the left hand side. Set the Identifier of Bar Button Item to Add.

Now Control + Drag from the Add button to DetailViewController and select Segue as Push with identifier as “addAction”. Similarly to allow users to edit the existing row, Control + Drag TableView prototype cell to DetailViewController and set identifier for the Push segue as “editAction”.

Add a new Cocoa Touch Class file to the existing project with Sub class as UIViewController and name of the file as DetailViewController. Set this file as the class name in the Identity Inspector of DetailViewController in Interface builder.

Update the DetailViewController.swift and replace the existing code with the following lines of code.

[code language=”swift”]import UIKit

class DetailViewController: UIViewController {

var socialMedia: SocialMedia?
var index:Int?

@IBOutlet var textFeild:UITextField?

override func viewDidLoad() {
super.viewDidLoad()

if let name = socialMedia?.name {
textFeild?.text = name
}
}

// MARK:- PrepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let name = textFeild?.text
if segue.identifier == "addAction" {
if var socialMedia = socialMedia {
self.socialMedia?.name = name!
} else {
socialMedia = SocialMedia(name:name!,imageName:"unknown")
}
}
}

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

}[/code]

 

We have declared two variables socialMedia and index which will be populated when user taps an esitsing row in the TableView. Also you should find a IBOutlet for UITextField, make sure to connect this with TextField in the Interface Builder.

In the viewDidLoad function, if the user is editing an existing row then the textfield is updated with that value. The prepareForSegue method is called when the user taps Done or Cancel button. And based on the action, a new social media icon is added or an existing row is updated.

Navigate back to TableViewDemoController and implement the following function that will be called on cancel or done operation in DetailViewController.

[code language=”swift”]//MARK:- Cancel and Done

@IBAction func cancel(segue:UIStoryboardSegue) {
// do nothing
}

@IBAction func done(segue:UIStoryboardSegue) {

let detailViewController = segue.sourceViewController as! DetailViewController
let socialMedia = detailViewController.socialMedia
if let selectedIndex = detailViewController.index {
data[selectedIndex] = socialMedia!
} else {
data.append(socialMedia!)
}
tableView.reloadData()
}[/code]

 

Delete and Move row

Delete operation can be added by implementing the following function in TableViewDemoController.

[code language=”swift”]func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
switch editingStyle {
case .Delete:
// remove the deleted item from the model
data.removeAtIndex(indexPath.row)
// remove the deleted item from the `UITableView`
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
default:
return
}
}[/code]

This would allow users to swipe and delete a row in TableView. The function checks whether the editing style is Delete, then the row is removed from the array as well from the TableView display.

In order to allow users to move the rows, the tableView editing property needs to be set to true. Add another Bar Button Item, this time to the right of TableViewDemoController and provide the caption as Edit. Then connect this button with the following IBAction function.

[code language=”swift”]//MARK:- Editing toggle

@IBAction func startEditing(sender: UIBarButtonItem) {
tableView.editing = !tableView.editing
}
[/code]

This button acts as a toggle switch to enable or disable tableview edit operation. Now add the following function required for Move operation.

[code language=”swift”]//MARK:- TableViewCell Move row methods
func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}

func tableView(tableView: UITableView,
moveRowAtIndexPath sourceIndexPath: NSIndexPath,
toIndexPath destinationIndexPath: NSIndexPath) {
let val = data.removeAtIndex(sourceIndexPath.row)
data.insert(val, atIndex: destinationIndexPath.row)
}
[/code]

Function canMoveRowAtIndexPath needs to return true and in moveRowAtIndexPath function, the tableView row data gets removed from the original index and inserted in to the new position.

Now the user can tap and hold the move option then drag and drop it to the desired position. When the tableview editing is set to true, it also provides delete button apart from the move operation.

Download the source code from here.

Social Media icons credit to Sebastiano Guerriero

Filed Under: ios, Swift, UITableView Tagged With: Swift, UITableView, Xcode

Memory management in Swift

June 7, 2015 By Ravi Shankar Leave a Comment

Memory management in Swift is done by Automatic Reference Counting or ARC. Whenever a variables holds an instance of a object the memory count for that object increases by 1. And when variable become out of scope or set to nil, the memory count decreases 1.

[code language=”swift”]class Teacher {
var name: String?
var course: String?

init (name: String, course: String) {
self.name = name
self.course = course
println("Reference count increased by 1")
}

deinit{
println("Reference count decreased by 1")
}
}

let teacher1 = Teacher(name: "Ravi", course: "Swift")

func createTeacher() {
let teacher2 = Teacher(name: "John", course: "Java")
}

createTeacher()[/code]

 

In the above example, we are creating two instances of Teacher class and storing it in variables teacher1 and teacher2. Since teacher2 variable is created within the function, it becomes out of scope after the function call. You should be able to observe the two init messages and one deinit (teacher2) message in console log. This should give you some idea on how reference counting works in Swift.

Increasing and decreasing of reference count are automatically handled by ARC but problem occurs when we have a strong reference cycle. A strong reference cycle refers to cyclic relationship between the objects.

[code language=”swift”]class Teacher {
var name:String?
var course:String?
var student: Student?

init(name: String, course:String) {
self.name = name
self.course = course

println("Reference count of Teacher increases by 1")
}

deinit {
println("Reference count of Teacher decreases by 1")
}
}

class Student {
var name:String?
var mentor: Teacher?

init(name: String, course:String) {
self.name = name

println("Reference count of Student increases by 1")
}

deinit {
println("Reference count of Student decreases by 1")
}
}

func createInstance() {
let teacher = Teacher(name: "Jason", course: "Swift")
let student = Student(name: "Adam", course: "Swift")
teacher.student = student
student.mentor = teacher
}

createInstance()[/code]

In the above code snippet, Teacher and Sudent classes have a strong reference cycle and both student and teacher instances remain in memory even after the end of function call. A strong reference cycle can be avoided by declaring any one of the instance as weak or unowned

[code language=”swift”]weak var student: Student?
[/code]

You can also unown the reference when you know the reference cannot be nil

[code language=”swift”]unowned var mentor: Teacher[/code]

Download playground file from gitHub (Memory Management)

Filed Under: ios, iPad, iPhone, Xcode Tagged With: ARC, iPad, Memory Management, Xcode

Closures, Extensions and Generics in Swift

May 22, 2015 By Ravi Shankar Leave a Comment

Closures

Closures are self contained lines of code that can be passed around the application and similar to blocks in Objective-C. A typical closure syntax in Swift looks as shown below

Closure Syntax

[code language=”swift”]{ (parameters) -> return type in
statements
}[/code]

Example closure in Swift

[code language=”swift”]{ (name:String, message:String -> (String) in
message + ” ” + name + ” !!!”
}
greetings(“Ravi”,”Welcome”)
[/code]

 

In the above code example, a closure has been assigned to a variable. The purpose of this closure is to concatenate the string parameters and return the appended message as return parameter.

Type Inference

The example closure can modified to ignore to the parameter types and closure supports type inference.

[code language=”swift”]var greetings = { (name, message) -> (String) in
return message + ” ” + name + ” !!!”
}

greetings(“Ravi”,”Welcome”)[/code]

Implicit return

In single expression closure, you can omit the return keyword.

[code language=”swift”]var numbers = [23,45,67,89,89,78]
numbers.sort { (number1, number2) -> Bool in
return number1 < number2
}

// numbers.sort { number1, number2 in return number1 < number2 }
numbers.sort { number1, number2 in number1 < number2 } // Shorthand argument syntax
numbers.sort { $0 < swift }[/code]

Shorthand Argument Syntax

Swift supports shorthand argument names for inline closures. In the above example used for implicit returns, the two parameters can be removed and represented in shorthand arguments as shown below.

[code language=”swift”]numbers.sort { $0 < swift }
[/code]

Trailing Closure

In a function with closure as the last parameter, the closure can be treated as trailing closures i.e closures outside the function parenthesis call. This is quite helpful in reducing the long closure expression. For example, the sorted function has closure as the last parameter and with trailing closure this becomes as shown below.

[code language=”swift”]var numbers = [23,45,67,89,89,78]
var sortedNumbers = sorted(numbers, {$0 > swift}) // Without trailing closure
// var sortedNumbers = sorted(numbers) {$0 > swift} // represented as trailing closure

sortedNumbers[/code]

Extensions

Swift extensions are similar to category in Objective-C which adds new functionally to existing class, enumeration or Struct. Extension does not require the source code of original class or enumeration type or struct to extend their functionality.

Listed below is an example which extends String class. A new function fromDouble has been added to String class which takes a double value and returns String.

[code language=”swift”] extension String {
static func fromDouble(doubleValue: Double) -> String {
var temp = String(format: “%.2f”, doubleValue)
return temp as String
}
}
String.fromDouble(24.50)[/code]

Generics

Generics are code that produces the same result irrespective of the data type. Listed below is a function that accepts an array of type string and reverses the array items.

[code language=”swift”]let strTemp = [“Deepak”,”John”,”Steve”,”Ravi”,”Ganesh”]

// reverse array with String
func reverseString(items: Array) -> Array {
var temp = Array()
return items.reverse()
}
reverseString(strTemp)[/code]

Now the below function accepts array of number and reverses the items

[code language=”swift”] let numbers = [23,45,56,78,98]
// reverse array with numbers
func reverseNumber(items: Array) -> Array {
return items.reverse()
}
reverseNumber(numbers)[/code]

Generics solves the problem of having different set of code for different data types by implemting the functionality for a generic type.

[code language=”swift”]let strTemp = [“Deepak”,”John”,”Steve”,”Ravi”,”Ganesh”]
let numbers = [23,45,56,78,98]

func reverseItems(items:[T])-> [T] {
return items.reverse()
}
reverseItems(strTemp)
reverseItems(numbers)[/code]

You can also implement a Generic class with this function as shown below.

[code language=”swift”]let strTemp = [“Deepak”,”John”,”Steve”,”Ravi”,”Ganesh”]

class ReverseDemo {
func reverseItems(items:[P])-> [P] {
return items.reverse()
}
}
let reverseDemo = ReverseDemo()
reverseDemo.reverseItems(strTemp)
[/code]

Swift Operations with Generics

Let us say you want to create a generic function that returns the square value of the given number. The immediate solution that comes to your mind is

[code language=”swift”]func squareOfNumber(number:M -> M{
return number * number
}
[/code]

This is not as straight forward as we think, you would notice an error – “Binary operator ‘*’ cannot be applied to two M operands”. The generic data type does not recogonize the operator ‘*’. We can fix this by creating a new protocol that tells about this operator ‘*’ and Generic type should conform to this protocol as shown below.

[code language=”swift”]protocol Multipliable {
func *(lhs:Self, rhs: Self) -> Self
}

func squareOfNumber(number:M -> M{
return number * number
}
[/code]

Then add an extension to Int, Float and other required types and make them conform to Multipliable protocol.

[code language=”swift”]extension Int: Multipliable {}
extension Float: Multipliable {}

squareOfNumber(20)[/code]

Download source code from gitHub (Generic)

Filed Under: Apple, Develop, ios, Programming Tagged With: Closures, Extensions

Tuples, Enums and Protocols in Swift

May 14, 2015 By Ravi Shankar Leave a Comment

Tuples in Swift allows user to assign group of values to a variable, constant and even return parameter of a function. In the below example, a employee constant is assigned Int and String values. And to access these parameters, we need to use .0 and .1

[code language=”swift”]let employee = (103, “Deepak”)
employee.0
employee.1[/code]

Now let us say you want to assign proper name for these parameters so that you could access these values using those names instead of 0 and 1.

[code language=”swift”]let employee = (id:103, name:“Deepak”)
employee.id
employee.name[/code]

Here id and name are parameter names provided for employee id and employee name. You can also declare the data types for the tuple values like Int and String

[code language=”swift”]let employee:(id:Int, name:String = (102, “Deepak”)
employee.id
employee.name[/code]

Tuples and switch cases are powerful combination, look at an example below where Tuple has been used with switch cases. The _ is used for matching any values.

[code language=”swift”]let employee:(id:Int, name:String) = (102, “Deepak”)
switch (employee) {
case (103…105,_):
println(“developer”)
case (106…108,_):
println(“tester”)
case (_,“Deepak”):
println(“CEO”)
default:
println(“Contractor”)
}[/code]

Enums

Enum in Swift allows users to group related values to a single data type. Swift enum has lot of new features compared to its predecessor Objective-C. Let us see this with an example enum type for all Months in a year.

[code language=”swift”]enum Months {
case January, February, March, April, May, June, July, August, September, October, November, December
}

enum Month {
case January, February, March, April, May, June, July, August, September, October, November, December
}[/code]

Now you can define a variable or a constant of type month as shown below.

[code language=”swift”]let currentMonth = Month.May[/code]

And variable or constant is declared with the data type then you can use the short form.

[code language=”swift”]let currentMonth:Month = .May[/code]

Enum with Raw Value

Enum in Swift can be assigned a RawValue when declaring and the value can be of any data type. Let us day you want to specify the String value of each Month

[code language=”swift”]enum Month: String {
case January = “January”, February = “February”, March = “March”, April = “April”, May = “May”, June = “June”, July = “July”, August = “August”, September = “September”, October = “October”, November = “November”, December = “December”
}[/code]

The RawValue can be printed by accessing .rawValue on the enum variable or constant.

[code language=”swift”]let currentMonth:Month = .May
currentMonth.rawValue[/code]

Enum with Associated Value

Same like RawValue, enum can also have associated value and of data type.

[code language=”swift”]enum Month {
case January(String), February(String), March(String), April(String), May(String), June(String), July(String), August(String), September(String), October(String), November(String), December(String)
}

let currentMonth:Month = .May(“Summer Vacation”)

switch currentMonth {
case .May(let message):
println(message)
default:
println(“No Values”)
}[/code]

In the above example, Month enum values are declared with an associated value of data type String. And while assign the enum value the associated value is also provided to the currentMonth constant. Using the switch the associated value is retrieved.

Enum can have member function

Enum in Swift can also have member function. In the below example code, we have declared the Month enum with rawValue of type Int. Now add a member function to calculate the number of months left from the currently assigned value.

[code language=”swift”]enum Month: Int {
case January = 1, February, March, April, May, June, July, August, September, October, November, December func monthsLeftForYearEnd() -&gt; Int {
return Month.December.rawValue – self.rawValue
}
}

let month: Month = .May
month.monthsLeftForYearEnd()[/code]

Constant month is assigned a enum value of .May and you can find out the number of months left for the year end by accessing the monthsLeftForYearEnd.

Enum can have Initialiser

Swift’s enum can have initialiser too where you can set the default enum value or do some initial processing. If you add init function as shown below, the default enum value will be set to July.

[code language=”swift”]enum Month: Int {
case January = 1, February, March, April, May, June, July, August, September, October, November, December
init() {
self = .July
}

func monthsLeftForYearEnd() -&gt; Int {
return Month.December.rawValue – self.rawValue
}
}

let month = Month()
month.monthsLeftForYearEnd()[/code]

Protocols

Protocol in Swift defines the contract for a class or struct. This is similar to the interface in other languages like java. Protocol only defines the member function or variables and the actual implementation should be done in the conforming class or struct. Protocol can be be useful in the following ways

  • To add common behaviour across related or unrelated classes.
  • Supports in the implementation of delegation pattern

Let us see a typical example of protocol in Swift where we defining a Protocol called LivingThings with one method eat.

[code language=”swift”]protocol LivingThings {
func eat() -&gt; String
}[/code]

Any class or struct conforming to this Protocol should add implementation to eat method. In the below code example, we have got two classes Animal and Human which conform to LivingThings. implementation for the eat method has been added to both the classes.

[code language=”swift”]class Animal: LivingThings {
func eat() -&gt; String {
return “Animal Food"
}
}

class Human: LivingThings {
func eat() -&gt; String {
return "Human Food"
}
}

let john = Human()
john.eat()

let cat = Animal()
cat.eat()[/code]

If a class conforming to a Protocol does not implement the required methods then you will find error message “error: type ‘Human’ does not conform to protocol ‘LivingThings’”

Protocol with Optional Methods

In Swift, Protocol with optional method can be defined by specifying the optional before the method definition and adding @objc keyword before protocol. Listed below is an example with Speakable protocol that has an optional method speak

[code language=”swift”]
protocol LivingThings {
func eat() -&gt; String
}

@objc protocol Speakable {
optional func speak() -&gt; String
}

class Human: LivingThings, Speakable {
func eat() -&gt; String {
return "Human Food"
}

func speak() -&gt; String {
return "Human can Speak"
}
}

let john = Human()
john.eat()
john.speak()[/code]

Protocol and Delegation Pattern

A delegate pattern is used when you want a class to act on behalf of another class or for a callback mechanism. In the below code example we have defined a protocol (ImportDataDelegate) with two methods startImport and finishedImport. The DataImport class conforms to this Protocol and adds implementation to these methods. The DemoImport class acts on behalf of DataImport class by declaring a variable delegate of type ImportDataDelegate.

[code language=”swift”]protocol ImportDataDelegate {
func startImport()
func finishedImport()
}

class DataImport: ImportDataDelegate {
func startImport() {
println("Import started")
}

func finishedImport() {
println("Import finished")
}
}

class DemoImport {
var delegate: ImportDataDelegate?

func startProcess() {
delegate?.startImport()
println("Doing some work …")
delegate?.finishedImport()
}
}[/code]

This is how you pass the DataImport class to delegate variable of the DemoImport.

[code language=”swift”]let demoImport = DemoImport()
demoImport.delegate = DataImport()
demoImport.startProcess()[/code]

Filed Under: Apple, Develop, ios, Programming Tagged With: Apple, delegate pattern, Optional Methods, Protocol

  1. Pages:
  2. «
  3. 1
  4. 2
  5. 3
  6. 4
  7. 5
  8. 6
  9. 7
  10. 8
  11. 9
  12. 10
  13. »
« Previous Page
Next Page »

Primary Sidebar

TwitterLinkedin

Recent Posts

  • How to block keywords in Jio broadband
  • How to disable opening an app automatically at login in Mac
  • How to set preferred Wifi network on Mac
  • Attribute Unavailable: Estimated section warning before iOS 11.0
  • How to recover Firefox password from Time Machine backup

Pages

  • About
  • Privacy Policy
  • Terms and Conditions

Copyright 2022 © rshankar.com

Terms and Conditions - Privacy Policy