Swift 3: Beyond the first look


Version:

Run the command to know the Swift version you are using,

~$ xcrun swift -version
Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42)
Target: x86_64-apple-macosx10.9
~$

Variable

Swift is a type-safe language. It can infer data type from default value provided.

Each variable need an initial value OR have to be declared with a type.

var aStringVariable = "Hello world"
var anotherStringVariable: String
var anIntVariable: Int                  // 64-bit signed integer
var anInt8Variable: Int8                // 8-bit signed integer
var anInt16Variable: Int16              // 16-bit signed integer
var anInt32Variable: Int32              // 32-bit signed integer
var anInt64Variable: Int64              // 64-bit signed integer
var anUnsignedIntVariable: UInt         // 64-bit unsigned integer
var anUnsignedInt8Variable: UInt8       // 8-bit unsigned integer
var anUnsignedInt16Variable: UInt16     // 16-bit unsigned integer
var anUnsignedInt32Variable: UInt32     // 32-bit unsigned integer
var anUnsignedInt64Variable: UInt64     // 64-bit unsigned integer
var aDoubleVariable: Double
var aFloatVariable: Float
var aBooleanVariable: Bool
var aCharacterVariable: Character

Some interesting notes:

  • Character can be double quoted in Swift. If not defined explicitly, it will be inferred as String, var myChar : Character = "a"
  • Boolean can’t be assigned to zero or one but true/false

Check variable type,

var lightSwitchOn: Bool = true
var dimmer: Int = 7
var dimmerWithDecimals: Float = 3.14
var veryPreciseDimmer: Double = 3.14159265359

// check variable type 
print(type(of: lightSwitchOn))
print(type(of: veryPreciseDimmer))

In general, there is no syntactical differences between Float and Double, but Double isn’t always better; use Float where speed is more important than accuracy.

var pi: Float = 3.14159265359
var pi2: Double = 3.14159265359

print(pi) // 3.14159
print(pi2) // 3.14159265359

Constant

Constant starts with ‘let’ keyword in Swift. Using ‘let’ is highly recommended whenever possible. Besides type safety there are some internal performance optimization by Swift compiler.

Literal vs Constants
A literal is a value that is written exactly as it’s meant to be interpreted. In contrast, a variable is a name that can represent different values during the execution of the program. And a constant is a name that represents the same value throughout a program. But a literal is not a name — it is the value itself.
Source:
http://stackoverflow.com/questions/485119/what-does-the-word-literal-mean

String

Declare String,

let aString = String()
let anotherString = ""

Swift string class is built from Unicode scalar values you can type emoji directly into string literals. To popup the emoji keyboard in Xcode playground, type control + command + space

let similarTruth = "💰can't buy me 💖"
let similarAnimal = "🐙"

Print all the characters in a String

var anotherString = "Hello"
for character in anotherString.characters {
    print (character)
}

Notice that String doesn’t have any length property

let aString = "Hello World"
print(theTruth.characters.count)

Reverse a String

var simpleString = "Hola"
var reversedString = simpleString.characters.reversed()
// Here, reversedString is a ReversedCollection<String.CharacterView>
// So you can not just write print(reversedString). Instead,

for character in reversedString {
    print (character)
}

String interpolation,

var name = "Kate"
var customizedBirthdayCheer = "Happy Birthday, \(name)!"

Finding a substring within a string,

var word = "fortunate"
word.contains("tuna")

Replacing a substring,

var password = "Mary had a little loris"
var newPassword = password.replacingOccurrences(of: "a", with: "A")

Conditional statement

  • Curly braces are REQUIRED, even if there is a single statement.
  • Parenthesis are not needed around the condition.
  • Pre/ Post -increment/ decrement are deprecated and will be removed in Swift 3.

If-else condition

let x = 5

if x < 5 {
    print("x < 5") } else if x == 5 {     print("x == 5") } else {     print ("x >= 5")
}

While loop

var index = 0
let x = 5

while index < x {
    index += 1      // index++ is deprecated
}

For loop

for i in 0 ... 10 { // for (var i = 0; i <= 10; i++ )
    print("i = \(i)")
}

for i in 0 ..< 10 { // for (var i = 0; i < 10; i++ )
    print("i = \(i) and i * i = \(i * i)")
}

Do while loop

var index = 0
let x = 5

repeat {
    index += 1
} while index < x

Optional basics

  • Variable/constant has to be intialized before used. Otherwise, compile error
  • Optional variable/constant can have a value OR it will be ‘nil’
  • Optional variable/constant is strongly typed too. Either contain a valid value or ‘nil’
  • Opitonal variable/constant can be set to ‘nil’ explicitely
  • Optional variable/constant need to be unwrapped before use. Before unwrap you need to be sure it has a value.
var optionalString: String?
var optionalInt: Int?

if optionalInt != nil {
    var anIntVariable = optionalInt! // unwrapping
    print (anIntVariable)
}

// OR

if let anIntVariable = optionalInt {
    // execution will be here iff optinalInt != nil
    print(anIntVariable) // by default unwrapped
} else {
    print("optionalInt is nil")
}

Function

Function with parameter and return type,

func calculateTip(priceOfMeal: Double) -> Double {
    return priceOfMeal * 0.15
}

let priceOfMeal = 43.27

let tip = calculateTip(priceOfMeal: priceOfMeal)

Function params are by default constant.

func placeFirstLetterLast(_ myString: String) -> String {
    var myString = myString
    myString.append(firstCharacter(of: myString))
    myString.remove(at: myString.startIndex)
    return myString
}

On calling a function, you need to specify the name of all variable as key:value (except the first one)

func foo() {
    // no params, no return type
}

func boo() -> String {
    return ""
    // no params, String return type
}

func coo(first: String) -> String {
    return first
    // one String param, String return type
}

func doo(first: String, second: Int) -> Int {
    return second
    // one String param, one Int param, Int return type
}

func moo(first: String, second: Int, third: Int = 2) -> Int {
    return third
    // Default param third set to 2
}

func koo(first: String) {
    // first = "Haha" // Error: params are constant
    // var first: String will make it a varaible
}

foo()
boo()
coo("Haha")
doo("Haha", second: 5) // Error: doo("Haha, 5)
moo("Haha", second: 5) // omit the default param
moo("Haha", second: 5, third: 3) // default param value

Chain function,

func addExcitementToString(string: String) -> String {
    return string + "!"
}

// chained together twice
let excitedString = addExcitementToString(string: addExcitementToString(string: "yay"))

// chained together 4 times
let reallyExcitedString = addExcitementToString(string: addExcitementToString(string: addExcitementToString(string: addExcitementToString(string: "wahoo"))))

External and Local Parameter Names,

// Prints out a string
func reverseAndPrint(_ string: String) {
    var reversedString = ""
    for character in string.characters {
        reversedString = "\(character)" + reversedString
    }
    print(reversedString)
}

// Takes a named parameter.
// forwardString - External parameter name 
// string - Local parameter name 
func reverseAndPrint(forwardString string: String) {
    var reversedString = ""
    for character in string.characters {
        reversedString = "\(character)" + reversedString
    }
    print(reversedString)
}

reverseAndPrint("regal")
reverseAndPrint(forwardString:"time")

If no external parameter name is needed then we can use _

Pure Functions
A pure function is a function that only operates on the values it receives, and that returns a new value.

A huge benefit of pure functions is that they are easier to understand and easier to reuse because a pure function has no effect on any existing object in the app. Instead, a pure function generates something new: a return value. We can easily integrate pure functions into any app without worrying if they will affect existing objects.

Class

  • Instance variable need to initialized with default value OR the class need to have a constructor
  • Constructor is a special function with name ‘init’
  • Current instance reference is ‘self’
class Person {
    var firstName: String = "Sherlock"
    var lastName: String = "Holms"
    var age: Int

    init() {
        // Constructor
        self.age = 50
    }

    // Method
    func getDescription() -> String {
        return "FirstName: \(self.firstName) and LastName: \(self.lastName) and Age: \(self.age)"
    }
}

var p = Person()    // Creating object
print("FirstName: \(p.firstName)")
print(p.getDescription())

instanceof OR is of type

class Person {
    var firstName: String = "Sherlock"
    var lastName: String = "Holms"
}

class Student: Person {
    var id: String = "0123456789"
}

var s = Student()

if s is Person {
    print("s is a Person too")

    var p = s as Person // casting to Person
    print(p.firstName)

} else {
    print ("This will not be executed")
}

iOS 9: Beyond the first look


Get all subviews

let childViews = view.subviews

for aView in childViews {
    if aView is UILabel {
        let aLabel = aView as UILabel
    } else if aView is UIButton {
        let aButton = aView as UIButton
    } else if aView is UIImageView {
        let aImageView = aView as UIImageView
    }
}

Table views

  • iOS table view is one column wide (with multiple rows)
  • One row contains one cell. This cell contains the views of that particular row

Let’s create a simple tableview

  1. Drag a Table View (not Table View Controller) into your main view controller.
  2. Resolve auto layout issues (Select Table View => Editor => Resolve Auto Layout Issues => Reset to Suggested Constraints)
  3. Connect dataSource and delegate Outlets to view controller (from Connections Inspector)

UITableViewDataSource controls the following

  • Configuring a table view
  • Inserting or deleting table rows
  • Reordering table rows

Configuring a table view

There are several methods you can use to configure your table view. Look at the apple documentation for elaborated information. For a quick overview look at the list

– tableView:cellForRowAtIndexPath: (Required)
Asks the data source for a cell to insert in a particular location of the table view.

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

– tableView:numberOfRowsInSection: (Required)
Tells the data source to return the number of rows in a given section of a table view.

func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int

– numberOfSectionsInTableView:
Asks the data source to return the number of sections in the table view.

optional func numberOfSectionsInTableView
(_ tableView: UITableView) -> Int

Implementation of the required methods

class ViewController: UIViewController, UITableViewDataSource {

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel!.text = "Cell number \(indexPath.row)"

        return cell
    }
}

Now we will create some dummy data and make use of the tableview accordingly

class ViewController: UIViewController, UITableViewDataSource {

    let section1Data = ["Section 1a", "Section 1b", "Section 1c", "Section 1d"]
    let section2Data = ["Section 2a", "Section 2b", "Section 2c", "Section 2d", "Section 2e"]
    let section3Data = ["Section 3a", "Section 3b", "Section 3c"]

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 3
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch section {
        case 0: return section1Data.count
        case 1: return section2Data.count
        case 2: return section3Data.count
        default: return 0
        }
    }

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

        var item : String

        switch indexPath.section {
        case 0:
            item = section1Data [indexPath.row]
            break
        case 1:
            item = section2Data [indexPath.row]
            break
        case 2:
            item = section3Data [indexPath.row]
            break
        default:
            item = ""
        }

        cell.textLabel!.text = item

        return cell
    }

    func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        switch section {
        case 0:
            return "Section 01"
        case 1:
            return "Section 02"
        case 2:
            return "Section 03"
        default:
            return ""
        }
    }

    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.
    }
}

UITableViewDelegate controls the following

  • Behaviour
  • Appearance
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    ... 

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        print("User clicked. Section \(indexPath.section) and row \(indexPath.row)")
    }

    func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
        let deleteAction = UITableViewRowAction(style: .Default, title: "Delete", handler: {
            action, indexPath in
            
            // Delete from data
            switch indexPath.section {
            case 0:
                break
            case 1:
                break
            case 2:
                break
            }
            
            tableView.reloadData()
            
            tableView.editing = false
        })
        
        let retActions = [deleteAction]
        return retActions
    }

    ...
}

Alert view

let confirmAlert = UIAlertController(title: "Deleting row", message: "Do you really want to delete?", preferredStyle: .Alert)
let posAction = UIAlertAction(title: "Yes", style: .Destructive, handler: {
    action in
    print("Yes button clicked")
})
let negAction = UIAlertAction(title: "No", style: .Default, handler: nil)
        
confirmAlert.addAction(posAction)
confirmAlert.addAction(negAction)
        
presentViewController(confirmAlert, animated: true, completion: nil)

Add App icon

  • Select Assets.xcassets -> AppIcon -> Attirbutes Inspector
  • You should see all possible image sizes you would like to provide
  • Select each of the icon and see the Image section in Attirbutes Inspector
  • You will see the Size property, but it is in point mode, not pixel. Then you will see the Scale property and know the actual pixel sized image you need to provide. px = pt * scale

Launcher screen

  • Usually launcher screen would be the first screen of the application without any data loaded.
  • You can mimic the controls of the first screen and put those is same fashion in launcher screen.

For more informaiton, follow this guide

Add a new ViewController

  • Add a new ViewController (or, variant) in storyboard
  • Create a new Cocoa Touch Class (Swift file), make it a subclass of UIViewController (or, variant)
  • Select the ViewController from storyboard and open Identity Inspector and link with the Swift file
  • Now we need to make a way to go to the new screen. Let’s review show method first.
    • Create a button in FirstViewController and Control+Drag it to the SecondViewController and select Action Segue (Show)
  • Another way is to create a NavigationViewController.
    • Select the FirstViewController and Editor => Embed In => Navigation Controller
    • For displaying a title, go to viewDidLoad() method and override self.title = “”

Add a new TabbarController

  • We can start by opening a new project with Tabbed Application option
  • Create a new ViewController in storyboard and control+drag from TabbarController (bottom) to new ViewController
  • This time select Relationship Segues (view controllers)
  • Individual tabbar icon or text can be change by selecting that individual tab text/icon.

Auto Layout and handling multiple screens

  • Auto Layout is enabled by default. Still if you need to check, Open storyboard => Show File Inspector => Check (Use Auto Layout)
  • First place the controls in square sized view controller and then make use of Resolve Auto Layout Issues (Bottom-Right corner) => Reset to Suggessted Constraints
  • General suggestion: If you get yellow/red sign in Auto Layout then go to Document Outline screen of storyboard and tap on the top right corner button
  • Clear constraint of a paritcular view by selecting Resolve Auto Layout Issues (Bottom-Right corner) => Clear Constraints
  • For more info: https://developer.apple.com/design/adaptivity/
  • Alternatively you can use a handy library: http://snapkit.io

Stack Views

  • Stack views are much more like LinearLayout in Android. They can either be horizontal or vertical. Unlike LinearLayout they can NOT have any view properties (color etc)
  • Unlike Android, you are supposed to use nested stack views in iOS
  • There are 3 properties in stack views that you need to take care of
    • Alignment
    • Distribution
    • Spacing
  • General suggestion: First place controls roughly on the storyboard
    • Select the controls
    • Editor -> Embed In -> Stack view
    • Xcode should embed the controls with proper subviews. If not you can change it from Attributes Inspector.
  • Selecting stack view from storyboard can be tricky. Also, dragging the stack view to setup it’s width and height will not work as expected. Workaround is, select stack view from Document Outline view. Setup constraint using Pin button (Bottom-right corner)
  • Now play with the 3 attributes (Alignment, Distribution and Spacing) from Attributes Inspector to make things right your choice.
  • You might see some warnings regarding stack views and those might be a false alarm. Select the stack view, go to the Size Inspector and decrement the value of x by one and change it back to original. If it was a false alarm it should go away.

Dynamic layout for different screens

You can take advantage of size classes as it will allow you to design specific layout for specific screen. For example, you can reduce the font size only when the layout will render in iPhone 4 landscape mode. Remember, Auto layout constraints will be applied first than Size classes.

You should see “w any h Any” at the bottom of the storyboard. Tap on it and select a variation. At the bottm of the new dialog you can see the list of the screen this particular variation will take effect.

There are two keywords: Compact and Regular. Here, Compact essentially means, limited. You need to take extra care when you see compact width/height.

For more information, follow this guide

General suggestion: You should play with the size classes at the very end. In addition, you should do the experiments in separate branch, thus you can always revert back to the previous working branch.

After selecting a variant the bottom bar of the storyboard will turn into blue and the storyboard view controller will take the specific device frame that you selected in variant.

Change the font

  • Select the label.
  • Go to Attributes Inspector
  • Do not change the font. Instead, click on the (+) button beside font.
  • Select the proper variation base and you should see a separate font change inputbox
  • Change font and size using the input box.
  • Use Assistance Editor (Preview mode) to see how things will look finally in different devices

Change size of a view

  • Make sure the auto layout constraints have been set.
  • Select the control you would like to change the size.
  • Go to Size Inspector. In the Constraints section, change the constraint value (width/height) by clicked Edit button
  • Check your work in Assistance Editor (Preview mode)
  • You might need to set the auto layout contraints again based on the changes you made

Remove a view/item

  • Select the control you would like to delete.
  • Hit Command + Delete.
  • The control should still be visible in Document Outline view but greyed out

Xcode 7: Beyond the first look


Version:

I am using Xcode Version 7.3.1 (7D1014)

Most used keyboard shortcuts Xcode

Action Shortcut Symbol
Run Command + R ⌘ + R
Stop Command + . ⌘ + .
Show Project Navigator Command + 1 ⌘ + 1
Show Quick Help Inspector Option + Command + 2 ⌥ + ⌘ + 2

Most used keyboard shortcuts iOS simulator

Action Shortcut Symbol
Scale 100% Command + 1 ⌘ + 1
Scale 75% Command + 2 ⌘ + 2
Scale 50% Command + 3 ⌘ + 3
Scale 33% Command + 4 ⌘ + 4
Scale 25% Command + 5 ⌘ + 5

Recommended Preferences

  • Goto Xcode preferences (⌘ + ,)
    • Select tab (Text Editing)
      • Check (Line numbers)
    • Select tab (Accounts)
      • Select + (bottom left corner)
      • Add Apple ID
      • Add your apple account credential. This will enable you to run your app in your iOS device. From Xcode 7, you do not need to have a paid account for this. However, uploading app to the App store still require you to have a paid developer account.
    • Select tab (Components)
      • Select sub tab (Documentation)
      • Download the documentations you required. For example, for iOS development it would be helpful to have iOS x.x Documentation and Xcode x.x documentation.

Most used keyboard shortcuts Storyboard

Action Shortcut Symbol
Copy elements Option + Click + Drag ⌥ + Click + Drag
Align Left Edges Command + [ ⌘ + [
Align Right Edges Command + ] ⌘ + ]
Size to Fit Content Command + = ⌘ + =

Embed all views into a single view

  1. Select all the views, you want to embed in
  2. Editor => Embed In => View/ Scroll View/ Stack View
  3. Editor => Resolve Auto Layout Issues => Reset to Suggested Constraints

Debug views in Xcode

  • Run the app. While it is running locate a button in debug section: Debug View Hierarchy
  • See the slider? Drag it to right to zoom in and separate the views
  • Drag on blank area and you can rotate, move the views

Class structure quick look

  • Open a Swift class
  • Editor
    • Code Folding
      • Fold Methods and Functions
      • Fold Comment Blocks

Xamarin iOS: Learning by Examples: Part#3


This is a continuation of a previous post.

Display a map

Follow the code snippet. It contains necessary comments inside the code.

private MKMapView mkMap;
private CLLocationManager locManager = new CLLocationManager();

public override void ViewDidLoad()
{
	base.ViewDidLoad ();

	// Full screen map
	mkMap = new MKMapView (View.Bounds);

	mkMap.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;

	// You can use other types
	mkMap.MapType = MKMapType.Hybrid;

	View.AddSubview (mkMap);

	double lat = 23.7000;
	double lon = 90.3667;

	var dhakaCity = new CLLocationCoordinate2D (lat, lon);
	var zoomLevel = MKCoordinateRegion.FromDistance (dhakaCity, 2500, 2500);

	mkMap.CenterCoordinate = dhakaCity;
	mkMap.Region = zoomLevel;

	mkMap.AddAnnotation (new MKPointAnnotation() {
		Title = "Marker",
		Coordinate = new CLLocationCoordinate2D(lat, lon)
	});

	// Asking for permission
	locManager.RequestWhenInUseAuthorization ();

	mkMap.ShowsUserLocation = true;
}

Make your app social

Using Xamarin capability we can post our message in Twitter/Facebook etc in a consistent manner and of course using shared code.

Here is the code snippet with necessary comments to post a message in Twitter/Facebook based on availability.

private SLComposeViewController slcVC;

public override void ViewDidLoad()
{
	base.ViewDidLoad ();

	if (SLComposeViewController.IsAvailable (SLServiceKind.Facebook)) {
		postInSocial (SLServiceKind.Facebook);
	} else if (SLComposeViewController.IsAvailable (SLServiceKind.Twitter)) {
		postInSocial (SLServiceKind.Twitter);
	} else {
		new UIAlertView("No social", "No social available", null, "OK", null).Show ();
	}
}

private void postInSocial(int serviceKind)
{
	slcVC = SLComposeViewController.FromService (serviceKind);
	slcVC.SetInitialText ("This text will be posted");
	slcVC.CompletionHandler += (result) =&gt; {
		InvokeOnMainThread (() =&gt; {
			DismissViewController (true, null);
			new UIAlertView("Posted", "Message posted in Social", null, "OK", null).Show ();
		});
	};

	PresentViewController (slcVC, true, null);
}

Take pictures from camera

We can take pictures in Xamarin in two ways.

  1. Using UIImagePickerController offered by iOS. This will only work on iOS.
  2. Using Xamarin.Mobile to hide the details. This will work on Android too and we will get the benefits of shared code. This is a separate component that needs to be downloaded from Xamarin component store.

Task:

  1. Install Xamarin.Mobile component from Xamarin components store
  2. Follow this code snippet…
private MediaPicker mPicker = new MediaPicker();
private MediaPickerController mPickerController;
private TaskScheduler tScheduler = TaskScheduler.FromCurrentSynchronizationContext();

public void triggerTakePicture()
{
	if (!mPicker.IsCameraAvailable)
	{
		new UIAlertView("No Camera", "No Camera found in this device", null, "OK", null).Show ();
	} else
	{
		mPickerController = mPicker.GetTakePhotoUI (new StoreCameraMediaOptions {
			Name = "picFile.jpg",
			Directory = "Photos/"
		});

		PresentViewController (mPickerController, true, null);

		mPickerController.GetResultAsync().ContinueWith(e =&gt; {
			// Get the image from here
			UIImage.FromFile(e.Result.Path);
			DismissViewController(true, null);
		}, tScheduler);
	}
}

Consume REST API service

We are going to consume weather data as a REST API services.

URL:
api.openweathermap.org/data/2.5/weather?q=London,uk

public class WeatherAPIService
{
	private string apiURL = "api.openweathermap.org/data/2.5/weather?q=London,uk";

	public WeatherAPIService ()
	{
		Task.Run (() => this.GetDataAsync (apiURL)).Wait ();
	}

	public async void GetDataAsync(string apiURL)
	{
		string responseJSONString = null;

		using (var httpClient = new HttpClient()) {
			try {
				Task<HttpResponseMessage> getResponse = httpClient.GetAsync (apiURL);
				HttpResponseMessage response = await getResponse;

				responseJSONString = await response.Content.ReadAsStringAsync ();
			} catch (Exception e)
			{
				string errMessage = e.Message;
			}
		}
	}
}

Add artworks to the app

Adding artworks to the app is pretty easy. By artwork we mean, app icon, splash image etc. Lets get this done by one step at a time.

App icons 

  1. Open info.plist file. You will see a section called “Universal Icons”. Add icons there as per sizes mentioned on each box. Naming convention does not need to follow.
  2. After adding those icons click on “Migrate to Asset Catalog”.
  3. All the icons can be found in Recourses -> Images.xcassets. Inside that folder you will find “Contents.json” file. Opening that will display similar page to add more icons.

Splash screen

Adding images for each sized splash screen could be costly. We will use universal storyboard for splash screen.

  1. Create a storyboard file named LaunchScreen.storyboard. It is a universal storyboard with one View controller.
  2. Open info.plist file. You will see a section called “Universal Launch Images”. At the bottom on this section select “LaunchScreen” (name of the storyboard file).
  3. You are good to go!

Please make a comment if you find the writing useful and/or you found any problems in the writing, I will fix the errors.

Thank you. 

 

Xamarin iOS: Learning by Examples: Part#2


This is a continuation of a previous post.

Create iOS Project

  • Right click on the Solution name (DemoAppName) -> Add -> Add New Project… -> iOS -> App -> General -> Single View App -> Next.
  • Name: DemoAppiOS
  • Organization Identifier: com.wordpress.tausiq (Give your own reverse domain name)
  • For now we are going to work on only iPhone. So, deselect iPad.
  • Select Target carefully. Your application needs minimum of this version to work. I am using iOS 8.3
  • Allow some time to eventually get the status, “Packages successfully added.” on the status bar (Top middle)

iOS Framework Structure

References: This folder contains files from .NET framework. Also it contains Xamarin.iOS, that is the wrapper around iOS framework and provides us the access to use them through C#/.NET

Main.cs: This is the entry point of project. The equivalent

AppDelegate.cs: The equivalent class of AppDelegate.swift in iOS. This is the application instance of the app.

Main.storyboard: Same as iOS storyboard. Actually you can use this same file in Xcode and add/edit components as you like. Xamarin studio can also handle to edit this file.

ViewController.cs: Same as iOS. ViewControllers contains the functionality of the UI. Each ViewController in storyboard is usually associated with one ViewController file.

*.plist: There are two plist files. Entitlements.plist and Info.plist. Former one contains the permissions for the app and later one contains the configuration information of the app.

To run this application first we need to select this project and make it a startup project. Right click on DemoAppiOS -> Set As Startup Project.

Run

Create some UI

in iOS we can create view using different ways. Such as,

  • Storyboard
  • XIB
  • Code

We will use Storyboard in Xamarin.iOS for a number of advantages

  • Overview of the whole projects UI/flow
  • Segue
  • Auto Layout etc.

Task

  1. Open Main.storyboard. There should be a View Controller by default, if not, Search and drag a View Controller from “Toolbox” window.
  2. Drag other UI controls (ImageView, Label, Button) on the View Controller.

Screen Shot 2016-01-31 at 5.51.59 PM.png

Tips:

  1. Skin can be changes using VIEW AS dropdown
  2. Constraints can be set using Recommended constraint option.
  3. Give a name of each UI component. Select the component -> Properties window -> Identity section -> Name. UI binding is automatic. That is, you can reference each component from code by using it’s name. [This binding is actually happening in ViewController.designer.cs file. It is an auto generated file, do not make an attempt to edit this file.]
using System;

using UIKit;
using AudioToolbox;
using DemoAppName.Core;

namespace DemoAppiOS
{
	public partial class ViewController : UIViewController
	{

		public User aUser {
			get;
			set;
		}

		public ViewController (IntPtr handle) : base (handle)
		{
			UserDataService dataService = new UserDataService ();
			aUser = dataService.GetUserById (1);
		}

		public override void ViewDidLoad ()
		{
			base.ViewDidLoad ();
			// Perform any additional setup after loading the view, typically from a nib.

			BindUI ();
		}

		private void BindUI()
		{
			// Create a /Images folder under DemoApp.iOS
			ImgView.Image = UIImage.FromFile (&amp;amp;amp;quot;Images/&amp;amp;amp;quot; + aUser.ProfileImagePath);

			lblDescription.Text = aUser.Email;

			btnClickMe.TouchUpInside += (object sender, EventArgs e) =&amp;amp;amp;gt; {
				new UIAlertView(&amp;amp;amp;quot;Alert Title&amp;amp;amp;quot;, &amp;amp;amp;quot;Alert Message&amp;amp;amp;quot;, null, &amp;amp;amp;quot;OK&amp;amp;amp;quot;, null).Show ();
			};
		}

		public override void DidReceiveMemoryWarning ()
		{
			base.DidReceiveMemoryWarning ();
			// Release any cached data, images, etc that aren't in use.
		}
	}
}

Display a Table View

I am assuming that audience know how to create a TableView in iOS. I will discuss only how to display a TableView using Xamarin.

    1. Drag a Table View Controller or Table View to the existing controller.
    2. Add a folder named /DataSources and create a class inside it, named: UserTableDataSource.cs
using System;
using UIKit;
using System.Collections.Generic;
using DemoAppName.Core;
using Foundation;

namespace DemoAppiOS
{
	public class UserTableDataSources : UITableViewSource
	{
		private List&amp;amp;amp;lt;User&amp;amp;amp;gt; users;
		NSString cellIdentifier = new NSString (&amp;amp;amp;quot;UserCell&amp;amp;amp;quot;);

		public UserTableDataSources (List&amp;amp;amp;lt;User&amp;amp;amp;gt; users, UITableViewController tvController)
		{
			this.users = users;
		}

		public override nint RowsInSection (UITableView tableView, nint section)
		{
			return users.Count;
		}

		public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
		{
			UITableViewCell cell = tableView.DequeueReusableCell (cellIdentifier) as UITableViewCell;

			if (cell == null) {
				cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);
			}

			var user = users [indexPath.Row];

			cell.TextLabel.Text = user.FirstName;
			cell.ImageView.Image = UIImage.FromFile (&amp;amp;amp;quot;Images&amp;amp;amp;quot; + user.ProfileImagePath);
			cell.DetailTextLabel = user.Email;

			return cell;
		}

	};
}

    1. Select the Table View Controller -> Properties window -> Identity section -> Enter Name: “UserTableViewController” and press Enter. Xamarin will create a class named “UserTableViewController”.
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
using DemoAppName.Core;

namespace DemoAppiOS
{
	partial class UserTableViewController : UITableViewController
	{
		UserDataService uService = new UserDataService();

		public UserTableViewController (IntPtr handle) : base (handle)
		{
		}

		public override void ViewDidLoad()
		{
			var users = uService.GetAllUsers ();
			var dataSource = new UserTableDataSources (users, this);
			TableView.Source = dataSource;
		}
	}
}

Custom cell in Table View

Create a folder named: “ui” and create a class named: UserTableCell. This class will consists of Three label and one Image.

using System;
using UIKit;
using Foundation;
using ObjCRuntime;
using CoreText;
using CoreLocation;
using CoreTelephony;
using System.Drawing;
using CoreGraphics;
using CoreImage;

namespace DemoAppiOS
{
	public class UserTableCell: UITableViewCell
	{
		UILabel lblFirstName;
		UILabel lblLastName;
		UILabel lblEmail;
		UIImageView imgV;

		public UserTableCell ()
		{
		}

		public UserTableCell (NSString cellId) : base (UITableViewCellStyle.Default, cellId)
		{
			SelectionStyle = UITableViewCellSelectionStyle.Default;

			ContentView.BackgroundColor = UIColor.DarkGray;

			lblFirstName = new UILabel () {
				TextColor = UIColor.Black,
				BackgroundColor = UIColor.Clear
			};

			lblLastName = new UILabel () {
				TextColor = UIColor.Blue,
				BackgroundColor = UIColor.Clear
			};

			lblEmail = new UILabel () {
				Font = UIFont.FromName (&quot;AmeraicanTypeWriter&quot;, 14f),
				TextAlignment = UITextAlignment.Center,
				BackgroundColor = UIColor.Clear
			};

			imgV = new UIImageView ();

			ContentView.Add (lblFirstName);
			ContentView.Add (lblLastName);
			ContentView.Add (lblEmail);
			ContentView.Add (imgV);
		}

		// set the layout (UI component's) position
		public override void LayoutSubViews ()
		{
			base.LayoutSubviews ();

			imgV.Frame = new RectangleF (8, 8, (float)ContentView.Bounds.Width - 8, 160);
			lblFirstName.Frame = new RectangleF (8, 168, (float)ContentView.Bounds.Width - 8, 48);
			lblLastName.Frame = new RectangleF (8, 224, (float)ContentView.Bounds.Width - 8, 48);
			lblEmail.Frame = new RectangleF (8, 280, (float)ContentView.Bounds.Width - 8, 48);
		}

		// set the values in UI
		public void SetValues (string firstName, string lastName, string email, UIImage img)
		{
			imgV.Image = img;
			lblFirstName.Text = firstName;
			lblLastName.Text = lastName;
			lblEmail.Text = email;
		}
	}
}

We also need to update UserTableDataSources.cs file and incorporate UserTableCell.

using System;
using UIKit;
using System.Collections.Generic;
using DemoAppName.Core;
using Foundation;

namespace DemoAppiOS
{
	public class UserTableDataSources : UITableViewSource
	{
		private List&lt;User&gt; users;

		// This string must match with identifier of each cell
		NSString cellIdentifier = new NSString (&quot;UserCell&quot;);

		public UserTableDataSources (List&lt;User&gt; users, UITableViewController tvController)
		{
			this.users = users;
		}

		public override nint RowsInSection (UITableView tableView, nint section)
		{
			return users.Count;
		}

		public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
		{
			UserTableCell cell = tableView.DequeueReusableCell (cellIdentifier) as UserTableCell;

			if (cell == null) {
				cell = new UserTableCell (cellIdentifier);
			}

			cell.SetValues (
				users [indexPath.Row].FirstName,
				users [indexPath.Row].LastName,
				users [indexPath.Row].Email,
				UIImage.FromFile (&quot;Images/&quot; + users [indexPath.Row].ProfileImagePath) );

			return cell;
		}

	};
}

Do not forget to update cell identifier in storyboard of cell

Moving to next screen

Navigating to next screen usually follows 4 types of pattern.

  1. Single View (Stack)
  2. Tab
  3. Master details
  4. Navigation drawer

Task:

  1. Drag a “Navigation Controller” in storyboard.
  2. Delete “Root View Controller” comes with it.
  3. Drag the starting segue to point to the “Navigation Controller”
  4. Control + Drag from Navigation Controller to ViewController and create a segue. Relationship: Root
  5. Control + Drag from ViewController to UserTableViewController and create a segue. Manual Segue: Show
  6. Drag another View controller from Toolbox window and name it “UserDetailViewController”. Select the View controller -> Properties window -> Identity -> Class -> UserDetailsViewController -> Press enter. A class with named UserDetailViewController.cs will be created automatically.
  7. Control + Drag from UserTableViewController cell to UserDetailsViewController and create a segue. Manual Segue: Show. Select the segue -> Properties window -> Identifier -> Segue: UserDetailsSegue

Finally it should look like this,

Screen Shot 2016-02-01 at 7.33.18 PM.png

Update UserDetailsViewController.cs like below,

using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
using DemoAppName.Core;

namespace DemoAppiOS
{
	public partial class UserDetailViewController : UIViewController
	{
		public User SelectedItem;

		public UserDetailViewController (IntPtr handle) : base (handle)
		{
		}
	}
}

Update UserTableDataSources.cs and UserTableViewController.cs as following,

using System;
using UIKit;
using System.Collections.Generic;
using DemoAppName.Core;
using Foundation;

namespace DemoAppiOS
{
	public class UserTableDataSources : UITableViewSource
	{
		private List&lt;User&gt; users;

		// This string must match with identifier of each cell
		NSString cellIdentifier = new NSString (&quot;UserCell&quot;);

		public UserTableDataSources (List&lt;User&gt; users, UITableViewController tvController)
		{
			this.users = users;
		}

		public override nint RowsInSection (UITableView tableView, nint section)
		{
			return users.Count;
		}

		public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
		{
			UserTableCell cell = tableView.DequeueReusableCell (cellIdentifier) as UserTableCell;

			if (cell == null) {
				cell = new UserTableCell (cellIdentifier);
			}

			cell.SetValues (
				users [indexPath.Row].FirstName,
				users [indexPath.Row].LastName,
				users [indexPath.Row].Email,
				UIImage.FromFile (&quot;Images/&quot; + users [indexPath.Row].ProfileImagePath));

			return cell;
		}

		public User GetItem(int index)
		{
			return users [index];
		}

	};
}

using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
using DemoAppName.Core;

namespace DemoAppiOS
{
	partial class UserTableViewController : UITableViewController
	{
		UserDataService uService = new UserDataService ();

		public UserTableViewController (IntPtr handle) : base (handle)
		{
		}

		public override void ViewDidLoad ()
		{
			var users = uService.GetAllUsers ();
			var dataSource = new UserTableDataSources (users, this);
			TableView.Source = dataSource;
		}

		public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
		{
			base.PrepareForSegue ();

			if (segue.Identifier == &quot;UserDetailsSegue&quot;) {
				var userDetailsVC = segue.DestinationViewController as UserDetailViewController;

				if (userDetailsVC != null) {
					var data = TableView.Source as UserTableDataSources;
					var selectedRow = TableView.IndexPathForSelectedRow;
					var item = data.GetItem (selectedRow.Row);
					userDetailsVC.SelectedItem = item;
				}
			}
		}
	}
}

Display a Modal View Controller

If we would like to display the UserDetailViewController as a Modal view controller, then we need to do things manually. That is, We will call the UserDetailViewController to display and we need to write code to dismiss that as well to go back to previous screen.

Lets delete the PrepareForSegue method and write this method instead in UserTableViewController.cs

		public async void onSelectedTableRow(User selectedUser)
		{
			UserDetailViewController userDetailVC = this.Storyboard.InstantiateViewController (&quot;UserDetailViewController&quot;)
			as UserDetailViewController;

			if (userDetailVC != null) {
				userDetailVC.ModalTransitionStyle = UIModalTransitionStyle.PartialCurl;
				userDetailVC.SelectedItem = selectedUser;

				await PresentViewControllerAsync (userDetailVC, true);
			}

		}

Now we need a call onSelectedTableRow method from UserDataSources.cs file


using System;
using UIKit;
using System.Collections.Generic;
using DemoAppName.Core;
using Foundation;

namespace DemoAppiOS
{
	public class UserTableDataSources : UITableViewSource
	{
		private List&lt;User&gt; users;

		// This string must match with identifier of each cell
		NSString cellIdentifier = new NSString (&quot;UserCell&quot;);

		UserTableViewController userTVC;

		public UserTableDataSources (List&lt;User&gt; users, UITableViewController tvController)
		{
			this.users = users;
			userTVC = tvController;
		}

		public override nint RowsInSection (UITableView tableView, nint section)
		{
			return users.Count;
		}

		public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
		{
			UserTableCell cell = tableView.DequeueReusableCell (cellIdentifier) as UserTableCell;

			if (cell == null) {
				cell = new UserTableCell (cellIdentifier);
			}

			cell.SetValues (
				users [indexPath.Row].FirstName,
				users [indexPath.Row].LastName,
				users [indexPath.Row].Email,
				UIImage.FromFile (&quot;Images/&quot; + users [indexPath.Row].ProfileImagePath));

			return cell;
		}

		public User GetItem(int index)
		{
			return users [index];
		}

		public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
		{
			var selectedItem = users [indexPath.Row];
			userTVC.onSelectedTableRow (selectedItem);
			tableView.DeselectRow (indexPath, true);
		}

	};
}

From UserDetailViewController.cs we need to call the following method at some point. Preferably after clicking on a button,

this.DismissModalViewController(true);

Xamarin iOS: Learning by Examples: Part#1


Target Audience:

I expect you have basic iOS development experiences. A “Hello World” app written by you and installed in an iOS device would be suffice.

Also you have minimal working knowledge on C# language. You don’t have to be a guru. It also might possible if you know Java or C++. It should be hard for you to follow along C#.

Why Xamarin

  • Single language C# with convenience of .NET platform/libraries.
  • Native UI and Code sharing capabilities
  • Performance is as good as Native apps.

Xamarin cons

  • UI is not shared. As such, you need to have working knowledge of both Android and iOS platforms separately to develop apps in Xamarin. You will build Android UI with Android xml and iOS UI with storyboard. They have Xamarin.Forms, but thats a whole other story. I will try to write another series based on Xamarin.Forms
  • Implicitly the above point also means you need to have working knowledge of Android (Java/Xml), iOS (Swift/Storyboard) and C#/.NET. A great looking learning curve …helping_hand_on_edge_800_wht_10663
  • Xamarin is a commercial product. You need to pay $25 for each platform. So, building for iOS + Android + Windows, you need to pay $75/month. They do have a trial version and followed by a Starter edition after the trial period. However, it will get you only that much a free version can get.
  • Application size will be a bit larger than Native apps. like, 2.5 MB as of now.

Which part of code will be shared?

Following components can be shared across platforms

  • Models
  • Service layer
  • Data + Data access layer
  • Business layer
  • Network layer

Shared components will be written in C#. On top of this C# layer we will create UI layer using Xamarin.iOS and/or Xamarin.Android. App layer (connection between UI and App) will also be written in C#, but it won’t be shared. On average you can share 60% code, rest 40% will be UI and App layer.

PCL (Portable Class Library)

PCL is a C# library that can be used as a library project on multiple platforms. PCL follows common denominator approach. That means, you can incorporate common features of the platforms in a PCL library.

Task:

  • Download and Install Xamarin Studio.
    • I am using Mac. You can use either Mac or Windows. For iOS development, Mac OS is required. If we choose to develop in Windows, you need to be connected with a Mac for building iOS app.
  • Create a New Solution -> Other -> Miscellaneous -> Blank solution. Do not enter any Project name. Only enter a Solution name. For example, DemoAppName.
  • Right click on newly created solution and Add -> Add New Project… -> Cross-platform -> Portable Library -> Name: DemoAppName.Core
  • Right click MyClass.cs -> Remove -> Delete.
  • Right click on DemoAppName.Core -> Add -> New Folder -> Name: Model
  • Right click on Model -> Add -> New File… -> Name: User.cs

This model class User contains basic informations of an User.

using System;
using System.Collections.Generic;

namespace DemoAppName.Core
{
	public class User
	{
		public User ()
		{
		}

		public int UserId {
			get;
			set;
		}

		public string FirstName {
			get;
			set;
		}

		public string LastName {
			get;
			set;
		}

		public int Age {
			get;
			set;
		}

		public string ProfileImagePath {
			get;
			set;
		}

		public bool Active {
			get;
			set;
		}

		public string Email {
			get;
			set;
		}

		public List<string> PhoneNumbers {
			get;
			set;
		}
	}
}

Lets Create another model class named ProfessionalGroup, that will be a collection of Users. Each ProfessionalGroup will contain a number of Users.

using System;
using System.Collections.Generic;

namespace DemoAppName.Core
{
	public class ProfessionGroup
	{
		public ProfessionGroup ()
		{
		}

		public int ProfessionId {
			get;
			set;
		}

		public string Title {
			get;
			set;
		}

		public string ImagePath {
			get;
			set;
		}

		public List<User> People {
			get;
			set;
		}
	}
}

Create a UserRepo.cs class. This class will contain a demo collection of ProfessionalGroup objects. It will also contain some convenient method to query the ProfessionalGroup collection.

Create a folder named Data and place the UserRepo.cs class inside it.

using System;
using System.Collections.Generic;
using System.Linq;

namespace DemoAppName.Core
{
	public class UserRepo
	{
		public UserRepo ()
		{
		}

		/*
		 * Returns all Users in the collection
		 */
		public List<User> GetAllUsers()
		{
			IEnumerable <User> ret =
				from professionGroup in professionGroups
				from user in professionGroup.People
				select user;
			return ret.ToList<User> ();
		}

		/*
		 * Return a User with specific Id
		 */
		public User GetUserById(int id)
		{
			IEnumerable <User> ret =
				from professionalGroup in professionGroups
				from user in professionalGroup.People
				where user.UserId == id
				select user;

			return ret.FirstOrDefault ();
		}

		/*
		 * Get the list of all ProfessionalGroup
		 */
		public List<ProfessionGroup> GetProfessionalGroups()
		{
			return professionGroups;
		}

		/**
		 * Get a list of all users under a specific ProfessionalGroup
		 */
		public List<User> GetUsersOfGroupId(int groupId)
		{
			var group = professionGroups.Where (h => h.ProfessionId == groupId).FirstOrDefault ();

			if (group != null) {
				return group.People;
			}

			return null;
		}

		/**
		 * Get All active users in the collection
		 */
		public List<User> GetActiveUsers()
		{
			IEnumerable <User> ret =
				from professionalGroup in professionGroups
				from user in professionalGroup.People
				where user.Active
				select user;
			return ret.ToList<User> ();
		}

		/**
		 * Dummy data of ProfessionGroup. Each ProfessionGroup will contain a number of User.
		 */
		private static List<ProfessionGroup> professionGroups = new List<ProfessionGroup>()
		{
			new ProfessionGroup()
			{
				ProfessionId = 1,
				Title = "Doctor",
				ImagePath = "",
				People = new List<User>()
				{
					new User ()
					{
						UserId = 1,
						FirstName = "DFN1",
						LastName = "DLN1",
						Age = 30,
						ProfileImagePath = "",
						Active = true,
						Email = "DFN1@gmail.com",
						PhoneNumbers = new List<string>() { "+0123456789", "+0123456789"}
					},
					new User ()
					{
						UserId = 2,
						FirstName = "DFN2",
						LastName = "DLN2",
						Age = 32,
						ProfileImagePath = "",
						Active = true,
						Email = "DFN2@gmail.com",
						PhoneNumbers = new List<string>() { "+0123456789", "+0123456789"}
					}
				}
			},
			new ProfessionGroup ()
			{
				ProfessionId = 2,
				Title = "Engineer",
				ImagePath = "",
				People = new List<User>()
				{
					new User ()
					{
						UserId = 3,
						FirstName = "EFN1",
						LastName = "ELN1",
						Age = 30,
						ProfileImagePath = "",
						Active = true,
						Email = "EFN1@gmail.com",
						PhoneNumbers = new List<string>() { "+0123456789", "+0123456789"}
					},
					new User ()
					{
						UserId = 4,
						FirstName = "EFN2",
						LastName = "ELN2",
						Age = 32,
						ProfileImagePath = "",
						Active = true,
						Email = "EFN2@gmail.com",
						PhoneNumbers = new List<string>() { "+0123456789", "+0123456789"}
					}
				}
			}
		};
	}
}

You may encounter an issue of not resolving method. Syntax highlighting will display the error like this,

Screen Shot 2016-01-31 at 1.59.53 PM.png

To resolve this case, Right click on the item -> Resolve -> using System.Linq;

Alternatively add this line at the top of the file,

using System.Linq;

To make separation of concern, create another class named UserDataService.cs under Service Folder (Create a folder named Service). This class will contain methods of same signature as UserRepo.cs. The purpose of this class to delegate task to UserRepo class.

using System;
using System.Collections.Generic;

namespace DemoAppName.Core
{
	public class UserDataService
	{

		private static UserRepo userRepository = new UserRepo();

		public UserDataService ()
		{
		}

		public List<User> GetAllUsers()
		{
			return userRepository.GetAllUsers ();
		}

		public User GetUserById(int id)
		{
			return userRepository.GetUserById (id);
		}

		public List<ProfessionGroup> GetProfessionalGroups()
		{
			return userRepository.GetProfessionalGroups ();
		}

		public List<User> GetUsersOfGroupId(int groupId)
		{
			return userRepository.GetUsersOfGroupId (groupId);
		}

		public List<User> GetActiveUsers()
		{
			return userRepository.GetActiveUsers ();
		}
	}
}

To be continued…

Swift 2.0 for programmers Part#4


Structures

Points to be noted

  • Int, Bool, Double, String, Array, Dictionary are all structures, not class
  • struct is identical to class. Change a class keyword to struct keyword
    and everything should work fine

Differnece between struct and class

  • Structures are value types (pass by value) unlike class
  • Swift generates member wise intializer for struct. Member wise initializer is a default init method, that contains all the member variable as parameters
  • struct do not take part in Inheritance
  • No deinit in struct

Operators

var a = 1   // Good
var b=1     // Also good
var c= 1    // Not good, compile error
var d =1    // Not good, compile error
a++         // Good
a--         // Good
++a         // Good 
--a         // Good

Points to be noted

  • Space on either side of the operators must be balanced.

Nil coalescing operator


var name : String?
var defaultName = "John Doe"

var personName = name ?? defaultName

Points to be noted

name is a optional variable, it may or may not have values. So when we are using name to initialize personName then we are running into a trouble. Nil coalescing operator in on rescue. If name has a value then personName will be initialized with it, otherwise defaultName will be used.

Type check

let button = UIButton()
let label = UILabel()
let view = UIView()

let collections = [button, label, view]

for item in collections {
    
    // we are checking if the "item" is UIButton type
    if item is UIButton {
        print("UIButton")
        
        // downcasting the item to UIButton
        let aButton = item as! UIButton
        
        // now we can access UIButton specific behavior
        aButton.setTitle("Hello", forState: UIControlState.Highlighted)
    }
    
    // Compact way to achieve the same objective as presented before
    if let bButton = item as? UIButton {
        bButton.setTitle("Hello", forState: UIControlState.Highlighted)
    }
}

Protocol

protocol OnClickListener {
    func click()
    func longClick()
    func getColor() -> String
    
    // real only property
    var clickCount : Int {get}
    
    // read-write property
    var text : String {get set}
}

class ImplementationClass: OnClickListener {
    
    init () {
        
    }
    
    func click() {
    }
    
    func longClick() {
        
    }
    
    func getColor() -> String {
        return "RED"
    }
    
    var clickCount : Int {
        return self.clickCount
    }
    
    var text : String {
        get {
            return self.text
        } set {
            self.text = newValue
        }
    }
    
    
}

var mImpl = ImplementationClass()
mImpl.text = "Button Name"
mImpl.clickCount

Extension


extension Int {
    func add(a : Int) -> Int {
        return self + a
    }
    
}

var a = 5
let res = a.add(3)

Generics

func printArray<T>(array: [T]) -> T {
    for item in array {
        print(item)
        print(" ")
    }
    
    return array [array.count - 1]
}

let lastInt = printArray([1, 2, 3])
let lastString = printArray(["Hello", "World", "Swift"])

=================== The End ===================