Getting Started With iOS Programming

DISCLAIMER This tutorial is intended for people who are just starting out with iOS programming. It doesn’t assume any familiarity with Xcode and only assumes basic knowledge of Swift programming and OOP.

In this tutorial you’re going to make a tip calculator iOS application.

Gif

First Steps

To follow along with this tutorial you’ll need to have Xcode installed. Xcode is an integrated development environment (IDE) containing a suite of software development tools developed by Apple for developing software for OS X and iOS. You can download Xcode here.

To get started open Xcode. By default Xcode displays a new window with recent projects and various options to create new projects. Click the “Create a new Xcode project” button to create your first Project. Alternatively you can click File -> New -> Project (⇧⌘N) in the menu.

create new project

Xcode will present you with a set of templates to start your project off.

Go ahead and select the simplest of the provided templates, the Single View Application and hit Next. As the name implies this will create an application with a single screen that is initially empty.

single view application

Next off, Xcode will give you a set of options to configure your new project.

Enter “Tip Calculator” as the Product Name and make sure to set the Language to Swift and Devices to iPhone.

The Organization Name and Organization Identifier are used when you want to share your app on the AppStore or run your app on an actual iOS device.

Organization Name should be your name or the name of your company.

Organization Identifier are usually in the format “com.name” and are used together with your app name to uniquely identify your app.

Don’t worry about the Use Core Data, Include Unit Tests and Include UI Tests options for now. You’ll get a chance to use all of them in your iOS developer career :-).

project configuration

Hit the next button and Xcode will ask you where to save your project. After you have selected a destination, you’ll be greeted to the screen below.

Xcode Start

Getting to know Xcode

There are 3 areas of interest in Xcode:

The Content Area, located in the middle that shows you the currently open file or resource.

The Navigator, located on the left, currently shows you a list of files in your project. Among other things, you use the navigator to open certain files in your project.
Clicking on a file will open it in the content area. Notice that files can be grouped together in folders, these are calledgroups. Unfortunately groups in Xcode do not directly correspond to folders in the file system.

To hide/show the navigator either press the “hide/show navigator button” in the top right or use the keyboard shortcut⌘0.

Show Navigator

The Utilities Area, located on the right, shows information about the currently open file. Items in the utility area appear based on the file you’re editing. Most often you’ll use it when editing user interfaces.

To hide/show the utilities area either press the “hide/show utilities button” in the top right or use the keyboard shortcut ⌘⌥0.

Show Utilities

Now that you’re slightly familiar with Xcode’s interface, let’s get to work building the app!

Getting to know Interface Builder

Open the Main.storyboard file from the project navigator. Storyboards are the files that contain your application’s user interface (UI). Storyboards allow you to visually lay out your app , in some sense they’re similar to tools like Photoshop or Illustrator but intended for the sole purpose of building application interfaces. The tool that you use to edit storyboards in Xcode is called Interface Builder (IB).

Let’s look at some of the components of interface builder.

1 . The Content Area located in the middle is where you can see the UI you’re currently working on, it’s currently empty.

2 . The Document Outline on the left shows you a list of all the components that are part of the storyboard. Clicking on an item in the document outline will select it. Alternatively you can click on the item in the content area.
Currently there’s only 1 ViewController in the storyboard, for now you can think of a ViewController as being a screen in the app.

To hide / show the Document Outline press the hide/show document outline button in the bottom right corner of the content area.

3 . The Attributes Inspector in the top part of the Utilities panel on the right. Here you can edit properties of the currently selected item. For example try to change the background color to red.

4 . The Components Library in the bottom part of the Utilities panel. Here you have a list of components that you will use to build your user interface. Try dragging some items into the content area just to get a feeling on how this works.

Empty View Controller

Perhaps you noticed that the currently displayed view is square, that doesn’t look like any iOS device that currently exists. This is because by default Interface Builder wants you to design your views so they can adapt to different sizes across all different device screens. You can find out more about designing interfaces for different screens here.

For this tutorial we’ll keep things simple and build the UI for exactly one device.

Go ahead and select the View Controller item in the Document Outline.

View Controller Selected

In the Attribute Inspector expand the Size dropdown, and select one of the iPhone sizes. If you want to run the application on your own iPhone than you should select the appropriate size based on the device you have:

3.5inch – iPhone 4S 4 inch – iPhone 5 / 5S 4.7 inch – iPhone 6 / 6S 5.5 inch – iPhone 6+ / 6S+

For the purpose of this tutorial I’ll be working with the 4 inch iPhone.

Simulated Metrics

Size Dropdown

After you’ve selected the appropriate size your interface will look similar to this:

iPhone 4inch

Creating the Interface

Let’s start building the interface. First you’ll have to add some labels. Labels are read only components with static text used to identify different parts of the user interface.

Find the label component either by scrolling through the Component Library or by searching for “label” in the search field at the bottom.

Label Compoent

Now drag a label to the top middle part of your view controller. Notice that Interface Builder provides helpful blue guidelines that help you center your label and add some margin at the top.

Guide lines

Now, change the text of your label to “Tip Calculator”, you can do this either by double clicking the label or by changing the value in the Attributes Inspector under Text.

Tip Calculator Label

Notice that the label is no longer centered, you’ll have to recenter it, but first lets make the text bigger. Increase the font to 25 points. This can be done via the stepper next to Font in the Attributes Inspector.

Font

Next notice that the label has become cut off once you increased the text size.

Tip Calculator Large

You could manually adjust the size of the label, but a better solution is to use the shortcut ⌘=. This runs the command Editor -> Size to Fit Content.

Now drag the label to center it, remember to use the blue guidelines to help you out.

Centered Label

Next add a label below the title label, on the left edge of the screen and change it’s title to “Cost:”.

Cost Label 1

Cost Label 2

You’ll want a text field next to the cost label, a text field is an component that displays editable text. Tapping on a text field will allow you to edit the text in it when you run your app.

Text Field Component

Text Field Adding

Resize the the text field until you hit the right margin of the screen.

Text Field Resized

Next in the Attributes Inspector change the textfield Placeholder property to “Cost of your meal”. The placeholder is displayed when the textfield has no text, offering the user some hints on what they should type in the text field.

Your view will look like this now: Label + Textfield

Next add another label, aligned to the left below the cost label. Set this label's text to “Tip Percent”.

Percent Label

Add another label below the “Tip Percent” label. This label will display the actual percent that you want the tip to be. Be generous and set it’s text to “20”.

Tip Value

Let’s make the number stand out a bit. Make the text bold by editing the label’s Font property in the Attribute Inspector. Click the “T” button to the right of “System 17.0” and from the Style dropdown select Bold.

Font Bold

Again the text becomes cut off. A problem you’ll encounter later is that different texts with the same number of characters can have different sizes. For example “11” is shorter than “44”. You should make the label wider to accommodate different texts. Remember to keep it centered.

Larger Value

Also we’ll want the text in the label to be centered rather than being aligned to the left. From the attribute inspector select the Centered button to the right of Alignment.

Center Align

Next you’ll add a slider to the UI. A slider is used to select a value from a possible range of values. Go ahead and drag a slider to the right of the “Tip Percent” label. Adjust it’s width until you hit the right margin and place it vertically between the “Tip Percent” and “20” labels.

Slider

Slider added

By default a slider has a value between 0 and 1. But for our app we’ll want to use the a value between 0 and 100. Go ahead and edit the Minimum, Maximum and Current values in the Attributes Inspector, make sure to set theCurrent value to 20 so that it’s synced up with the “20” label. The slider's UI will update whenever you set one of these attributes.

Slider values

Finally we’ll want to add some UI that displays the final cost of a meal. Add a label titled “Final Cost:” below the “Tip Percent” UI.

Final cost

To the right of the “Final Cost” label add an empty label. This label will be filled programmatically based on the cost of the meal and the tip percent.

Final Final

Let’s make a final aesthetic change to the design. We’ll change all our labels to a lighter shade of black. Go ahead and select the “Cost:”, “Tip Percent” and “Final Cost:” labels. You can simultaneously edit multiple objects that have the same properties. From the Attributes Inspector expand the Color dropdown and choose Dark Gray Color.

Colors

All Selected

You can run the app right now using the iOS Simulator. First you’ll have to select the device you want to run the app on from the iOS Device dropdown. If you followed along exactly with this tutorial you should select iPhone 5.
After selecting the device just press the “Run” button in the top left corner or use the shortcut ⌘R.

Run App

The iOS Simulator application will start and display the screen of your app. Notice that you can drag the slider and enter text in the text field. The app isn’t functional of course, you haven’t written any code yet. We’ll fix that up next!

Simulator

The iOS Simulator enables you to simulate different iOS and Apple Watch devices and several versions of the iOS operating system. Essentially the iOS simulator let’s you test your app without using an actual iOS device.

Some essential iOS Simulator shortcuts:

⌘⇧H – Equivalent of pressing the home button on a device
⌘→ and ⌘← – Rotate the device clockwise / counter-clockwise
⌘K – Show / Hide the keyboard

Making Connections

Now you might wonder, “laying out my design in interface builder is all fine and dandy but how do I actually make all of this work ?”.

You’ll need a way to access your UI components from code, for example you’ll want to set the text of the “Final Cost”label programmatically. Also you’ll need a way to detect when a UI component has changed, i.e. the text field'stext has changed or the slider has moved.

UI Components are accessed in code via IBOutlets.
Actions on those components are detected via IBActions.

Let’s look at some ways in which we can hook up the UI.

Each screen in an app has an associated View Controller. Currently there is only 1 View Controller named “ViewController”. Each View Controller has an associated Swift class. For our View Controller this is the classViewController.swift. The code that accesses UI elements and is responsible for the app logic will go in this file.

Go ahead an open the ViewController.swift file. You will see something like this.

import UIKit

class ViewController: UIViewController {

   override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

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


}

Let’s add our text field as an IBOutlet.

At the top of the ViewController class add the line @IBOutlet var costTextField: UITextField!. Let’s discuss in detail what this does.

IBOutlets are properties on the ViewController class that are marked with a special keyword.

All IBOutlets have to be prefixed with the @IBOutlet keyword. This is used to mark them as IBOutlets and make them visible to Interface Builder.

The type of an IBOutlet depends on the type component you want to add. For the text field the type isUITextField. All UI components share the UI prefix in their class name.

You should also notice the ! after UITextField. This marks the property as a force unwrapped optional. This lets us access the text field without using Optional Chaining. It’s typical for IBOutlets to be forced unwrapped optionals.

Naming outlets Another thing to note is the name we gave to our outlet: costTextField. We could have called it whatever valid name we wanted: x, cost, csttf, etc. But generally you’ll want to give your outlets and variables informative names so that you can easily tell what you’re dealing with. A good naming convention is to add a suffix to the outlet that indicates it’s type. i.e. costTextField, nameLabel, submitButton etc. This is known as Hungarian Notation.

class ViewController: UIViewController {

    @IBOutlet var costTextField: UITextField!
...
}

Next we’ll have to hook up the IBOutlet in Interface Builder. Open the Main.storyboard file and control() click onView Controller in the Document Outline. A popup will appear listing various properties of the View Controller, this popup is used to connect IBOutlets.

Notice that your costTextField appear at the top of the Outlets section.

Outlet Open

To connect the outlet you have to drag the small circle on the right of costTextField to the text field in the UI.

Outlet Drag

The costTextField outlet will change it’s background color to a lighter gray after you’ve done this.

Outlet Connected

Now we can access the text field in the UI from code! Let’s change the text programmatically. You’ll add code in theViewController's viewDidLoad() method. This method is called when the ViewController's view is loaded in memory. Essentially you can’t access UI elements before viewDidLoad is called.

You can access a text field's text via the text property of type String. Go ahead and modify the text in theviewDidLoad method. Make sure to include your code after the super.viewDidLoad() call.

class ViewController {
...
    override func viewDidLoad() {
        super.viewDidLoad()

        self.costTextField.text = "Yey! We're finally writing code"
    }
...
}

If you run the app right now you’ll see that the text field's text has changed to the provided code.

Finally, Code

IBOutlets are only the first half of the connections you can make via Interface Builder. The other half are IBActions, these are used to inform you when certain UI events are triggered in your app. Examples: the value of a textfieldchanged, the value of slider changed, a button was pressed. etc.

Let’s create an IBAction that informs us when the value of our slider has changed.

Open the ViewController.swift file and add the following method above viewDidLoad.

class ViewController {
...
    @IBAction func tipSliderChanged(sender: UISlider) {
    }
...
}

All IBActions are methods prefixed by the keyword @IBAction. IBActions don’t return any value and always take a single parameter, the UI element that has triggered the action.

Naming Actions As with outlets it’s a good practice to give informative names to your IBActions and methods in general. A good naming convention is to use <<COMPONENT NAME>><<ACTION>> or <<ACTION>><<COMPONENT NAME>> ex:tipSliderChanged, submitButtonWasPressed, didTapSubmitButton, changedTipSlider etc.

Let’s connect an IBAction. Open the Main.storyboard file again. control() click on View Controller just like you did when adding an outlet. Now, notice the bottom section Received Action here you can see your tipSliderChanged:action.

IBAction

To connect an action drag from the action to the slider in the UI. A popup will appear.

IBAction connect

IBAction events

Select the Value Changed action from the popup. This will cause your tipSliderChanged method to be called whenever the value of the slider has changed. i.e. when you drag the slider around.

The popup will update to show you that you’ve successfully connected the action.

IBAction connected

Next let’s write some simple code that sets the costTextField's text to the value of the slider. You access the value of an UISlider via it’s value property of type Float. Go ahead and set the costTextField's text to the slider’s value.

class ViewController {
...
    @IBAction func tipSliderChanged(sender: UISlider) {
        self.costTextField.text = "\(sender.value)"
    }
...
}

When you run the app now you can see that the cost text field is modified whenever you drag the slider.

Slider Screenshot

More Connections

Let’s look at another way of adding connections. This method is generally faster but you’ll still have to use the previous method when modifying connections.

To get started open the Assistant Editor by clicking the Show Assistant Editor on the top right or using the shortcut⌥⌘↵. The Assistant Editor allows you to view 2 files side by side. When opening the Assistant Editor from a storyboard it will show you the corresponding swift file for the selected view controller.

Assistant Editor

Next you’ll have to drag UI components from the Storyboard to the source code on the right. Hold control() and drag the label to the right of “Final Cost:” below the costTextField property.

Connecting Outlets

Now a dialog will show up that will ask you for details on the connection you want to make. Set the name of the newlabel to finalCostLabel. Hit the Connect button and Xcode will automatically generate the code needed to connect the label.

Now do the same for the “20” label, name it tipPercentLabel.

Connecting Outlets Dialog

Next we’ll look at connecting IBActions in a similar way. Let’s connect an action that tells us when the text in the cost text field changes. Control() click on the textfield. A popup will appear listing all the possible events.

Actions Popup

Next drag from the circle to the right of Editing Changed to the line above the viewDidLoad method.

Connecting Actions

A dialog will appear asking for details on the action you want to add. Set the Name of the action tocostTextFieldChanged and the Type to UITextField, generally it’s a good to set the type of an action to the actual type of the object involved instead of using the default AnyObject.

Connecting Actions Dialog

Your code should look like this now.

import UIKit

class ViewController: UIViewController {

    @IBOutlet var costTextField: UITextField!
    @IBOutlet weak var finalCostLabel: UILabel!
    @IBOutlet weak var tipPercentLabel: UILabel!

    @IBAction func tipSliderChanged(sender: UISlider) {
        self.costTextField.text = "\(sender.value)"
    }

    @IBAction func costTextFieldChanged(sender: UITextField) {

    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.costTextField.text = "Yey! We're finally writing code"
    }

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

}

You’re done with hooking up the connections. Now, on to coding.

Coding

Setting up the UI and connecting outlets is only the first part of building an iOS app. The interesting part lies in coding the various interactions and implementing the app’s logic.

To get started you’ll need a way to keep track of the data in the app. Let’s think about what data we need. We’ll need to keep track of the currently inputed cost of a meal and of the tip percent. We’ll store this data in 2 Float variables. Declare these variables at the top of the ViewController class below all the outlet declarations.

Models The data in our app is called the Domain Model or simply Model. Notice that this data is separate from ourUI, it will be used to populate the UI but it exists independently of it.

class ViewController {
...
    var mealCost: Float = 0.0
    var tipPercent: Float = 20.0
...
}

Next let’s write a function called finalCost that computes the final cost of our meal. Code that operates on the model processing it or producing new data is called Buisness Logic. Notice that the finalCost function exists independently of the UI of our app.

class ViewController {
...
    func finalCost() -> Float {
        return mealCost + tipPercent / 100.0 * mealCost
    }
...
}

Next let’s hook up our UI to our model. We’ll want to update the model whenever the UI changes.

We’ll hook up the slider by setting the tipPercent to the slider’s value. You’ll also want to change thetipPercentLabel's text to reflect the new value.

class ViewController {
...
    @IBAction func tipSliderChanged(sender: UISlider) {
        self.tipPercent = sender.value
        self.tipPercentLabel.text = "\(self.tipPercent)"
    }
...
}

And we’ll hook up the textfield by setting the mealCost whenever the text field changes. Notice that a UITextField'stext property is declared as an optional (String?) so it can potentially be non-existent (nil). Note that the value nilis different from the empty string (""). Also converting a String to a Float can fail and return nil. For example how do you convert the string hello to a Float?

We’ll just hand-wave these issues for now. Assume that these calls never fail* and use the ! force unwrap operator to get these values.

*this is a terrible assumption
class ViewController {
...
    @IBAction func costTextFieldChanged(sender: UITextField) {
        self.mealCost = Float(sender.text!)!
    }
...
}

Next we’ll want to update our finalCostLabel after UI changes. We’ll add the same code to both the tipSliderChangedand costTextFieldChanged methods.

class ViewController {
...
    @IBAction func tipSliderChanged(sender: UISlider) {
        self.tipPercent = sender.value
        self.tipPercentLabel.text = "\(self.tipPercent)"

        self.finalCostLabel.text = "\(finalCost())"
    }

    @IBAction func costTextFieldChanged(sender: UITextField) {
        self.mealCost = Float(sender.text!)!

        self.finalCostLabel.text = "\(finalCost())"
    }
...
}

And we’re done :). Tutorial’s over, time to make some awesome apps! … or are we?

Debugging

The app is functional right now. But it’s still rough around the edges.

Tip Calculator Buggy

Here are the current issues: 1. The label under “Tip Percent” is not updated correctly, it shows “…” 2. The app displays the default iOS Keyboard making it difficult to input numbers 3. The app crashes when the textField is empty or invalid

Let’s fix each of these issues:

1. The label under “Tip Percent” is not updated correctly, it shows “…”

This happens because the slider returns decimal numbers as it’s value. So the value could be something like20.03456221. The label doesn’t have enough space to display that text so it displays “…” instead. To fix this we’ll round our tipPercent to the nearest integer. Also when setting the tipPercentLabel's text we’ll want to cast tipPercent to an Int so that we get a text without a decimal dot. (20 vs 20.0)

class ViewController {
...
    @IBAction func tipSliderChanged(sender: UISlider) {

        self.tipPercent = round(sender.value)
        self.tipPercentLabel.text = "\(Int(self.tipPercent))"
        ...
    }
...
}

2. The app displays the default iOS Keyboard making it difficult to input numbers

To fix this we’ll change the text field’s keyboard type from interface builder.

Open the Main.storyboard, select the cost text field, in the Attributes Inspector expand the dropdown next toKeyboard Type and select Decimal Pad.

Number pad

Looking better. But the app still crashes when the text field is empty. Also restricting the input to numbers and punctuation doesn’t get rid of possible invalid input: you can still write text like 1.2.3 that will cause the app to crash.

3. The app crashes when the textField is empty or invalid

We’ll fix by making the mealCost an optional variable. If mealCost is nil then the data is invalid and we’ll handle it appropriately.

Go ahead and change the type of mealCost from Float to Float?.

class ViewController {
...
    var mealCost: Float?
...
}

Now that mealCost is an optional we’ll have to modify some other code. The finalCost function has to be modified to unwrap the optional. We’ll assume that the function is only called when mealCost has a non nil value.

class ViewController {
...
    func finalCost() -> Float {
        return mealCost! + tipPercent / 100.0 * mealCost!
    }
...
}

Next you have to modify both the tipSliderChanged and costTextFieldChanged functions. If mealCost is nil then thefinalCostLabel's text should be set to the empty string("").

class ViewController {
...
    @IBAction func tipSliderChanged(sender: UISlider) {

        self.tipPercent = round(sender.value)

        self.tipPercentLabel.text = "\(Int(self.tipPercent))"

        if mealCost != nil {
            self.finalCostLabel.text = "\(finalCost())"
        } else {
            self.finalCostLabel.text = ""
        }
    }

    @IBAction func costTextFieldChanged(sender: UITextField) {
        self.mealCost = Float(sender.text!)

        if mealCost != nil {
            self.finalCostLabel.text = "\(finalCost())"
        } else {
            self.finalCostLabel.text = ""
        }
    }
...
}

Duplicate Code

Notice the snippet of code:

if mealCost != nil {
    self.finalCostLabel.text = "\(finalCost())"
} else {
    self.finalCostLabel.text = ""
}

This snippet appears twice in our code, once in tipSliderChanged and once in costTextFieldChanged. This is calledduplicate code and is considered a bad practice when writing code. What if we wanted to modify this code to display “Invalid Data” whenever mealCost is nil. We’d have to modify the code in 2 places.

We’ll extract the snippet into a new method to make the design of our code better. Restructuring code to improve its design while maintaining the same functionality is known as Refactoring.

class ViewController {
...
    func updateFinalCostLabel() {
        if mealCost != nil {
            self.finalCostLabel.text = "\(finalCost())"
        } else {
            self.finalCostLabel.text = ""
        }
    }
...
}

Now the updateFinalCost method will be called from both tipSliderChanged and costTextFieldChanged. If we want to change how the finalCostLabel is updated we only have to make those changes once.

class ViewController {
...
    @IBAction func tipSliderChanged(sender: UISlider) {

        self.tipPercent = round(sender.value)

        self.tipPercentLabel.text = "\(Int(self.tipPercent))"

        updateFinalCostLabel()
    }

    @IBAction func costTextFieldChanged(sender: UITextField) {
        self.mealCost = Float(sender.text!)

        updateFinalCostLabel()
    }
...
}

Let’s make the app display “Invalid Cost!” if the mealCost is nil and the costTextField is empty.

class ViewController {
...
    func updateFinalCostLabel() {
        if mealCost != nil {
            self.finalCostLabel.text = "\(finalCost())"
        } else if (self.costTextField.text!.isEmpty) {
            self.finalCostLabel.text = ""
        } else {
            self.finalCostLabel.text = "Invalid Cost!"
        }
    }
...
}

Invalid Cost

Model View Controller

We’re done building the app! Now let’s discuss the structure of the app a bit further. All iOS apps share a fundamental architecture on which they are built. This Design Pattern / Architectural Pattern is called Model View Controller (MVC).

In MVC all objects fit into one of three roles: Model, View or Controller.

Views

View objects are visible to the user. They are designed to show information to the user and get his input. These include the UI components that we used throughout this tutorial. Examples of view objects we used are: labels, text fieldsand sliders.

Models

Model objects hold data and are unaware of the user interface. The app we built has a very simple model: 2 Floats,mealCost and tipPercent. Model objects usually model data from the real world. Typically an application’s model layer consists of classes that encapsulate various related bits of data together. Let’s say you’re building an restaurant rating app, there you’ll most likely have a model object of type Restaurant that has properties like: name, address,phoneNumber, ratings and others.

Controllers

Controller objects are the intermediaries between views and models. They update the view using data from the model and make sure that the data between the view and model stay in sync. Controller objects are usually the place where you handle user input and set up various view properties.

You can download the full source code of the app below:

Full Source Code

  5 comments for “Getting Started With iOS Programming

  1. September 19, 2015 at 7:24 pm

    This is a great tutorial. I shared it on Twitter and people liked it.
    Thanks much and keep it up. I appreciate all the great info that you guys are putting together for us.

    Thanks;
    Gabriel

  2. Selim
    September 23, 2015 at 2:47 am

    Start to finish this is an awesome tutorial for beginners. You have a great way of slowly introducing different concepts of the Xcode world along with the swift language. Fantastic work!

  3. November 24, 2015 at 10:27 am

    Very informative blog, thanks for share this, theses codes are working… :)

  4. Noel
    July 15, 2016 at 1:42 am

    I love it! Brilliant tutorial! Thank you.

  5. Carlos Manuel Guerra Rivas
    February 25, 2017 at 11:57 am

    Thank you

Leave a Reply

Your email address will not be published. Required fields are marked *

Subscribe
We send about one email per week with our latest tutorials and updates
Never display this again :)