Swift High Performance

3.1 (8 reviews total)
By Kostiantyn Koval
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Exploring Swift's Power and Performance

About this book

Swift is one of the most popular and powerful programming languages for building iOS and Mac OS applications, and continues to evolve with new features and capabilities. Swift is considered a replacement to Objective-C and has performance advantages over Objective-C and Python. Swift adopts safe programming patterns and adds modern features to make programming easier, more flexible, and more fun.

Develop Swift and discover best practices that allow you to build solid applications and optimize their performance.

First, a few of performance characteristics of Swift will be explained. You will implement new tools available in Swift, including Playgrounds and REPL. These will improve your code efficiency, enable you to analyse Swift code, and enhance performance. Next, the importance of building solid applications using multithreading concurrency and multi-core device architecture is covered, before moving on to best practices and techniques that you should utilize when building high performance applications, such as concurrency and lazy-loading. Finally, you will explore the underlying structure of Swift further, and learn how to disassemble and compile Swift code.

Publication date:
November 2015
Publisher
Packt
Pages
212
ISBN
9781785282201

 

Chapter 1. Exploring Swift's Power and Performance

In the 2014, Apple released a new programming language, called Swift. Swift has been designed from scratch with many powerful features. It is statically typed and very safe. It has a clean and nice syntax, it's fast, it's flexible, and it has many other advantages that you will learn later in the book. Swift seems to be very powerful and it has big potential. Apple has set big expectations for Swift, and their main goal for Swift is that it should be a replacement for Objective-C, which is going to happen in the near future.

In this chapter, you will become familiar with the Swift programming language, what it was made for, and what its advantages and features are. We will also make our first Swift application and see how easy it is to integrate with existing Objective-C code.

In this chapter, we will cover the following topics:

  • Welcome to Swift

  • Writing swift code

  • Swift interoperability

  • The importance of performance and performance key metrics

 

Swift speed


I can guess you opened this book because you are interested in speed and are probably wondering, "How fast can Swift be?" Before you even start learning Swift and discovering all the good things about it, let's answer it right here and right now.

Let's take an array of 100,000 random numbers; sort it in Swift, Objective-C, and C using the standard sort function from stdlib (sort in Swift, qsort in C, and compare in Objective-C); and measure how much time each would take.

Sorting an array with 100,000 integer elements gives us this:

Technology

Time taken

Swift

0.00600 sec

C

0.01396 sec

Objective-C

0.08705 sec

And the winner is, Swift! Swift is 14.5 times faster than Objective-C and 2.3 times faster than C.

In other examples and experiments, C is usually faster than Swift and Swift is way faster than Objective-C. These measurements were done with Xcode 7.0 beta 6 and Swift 2.0. It's important to highlight that the improvements in Swift 2.0 were mainly focused on making it cleaner, more powerful, safer, and more stable, and preparing it for open sourcing. Swift's performance hasn't reached its full potential yet, and the future is so exciting!

 

Welcome to Swift


The Swift programming language has been designed by Apple from the ground up. It was released with the slogan Objective-C without the C. The meaning of this phrase is that Swift doesn't have any limitation of backward compatibilities. It's totally new and with no old baggage. Before you start learning all the power of Swift, I think it would be useful to answer a few questions about why should you learn it, and if you have any doubts about that, I should dispel them.

Why should I learn Swift?

Swift is a very new programming language but it has become very popular and has gained huge traction. However, many iOS and OS X developers ask these questions:

  • Should I learn Swift?

  • What should I learn, Swift or Objective-C?

  • Is Objective-C going to stay or die?

  • Is Swift ready for production apps?

  • Is Swift faster than Objective-C or C?

  • What applications can I write using Swift?

My answer is, "Yes. Definitely!" You should learn Swift. It doesn't matter whether you are a new iOS and OS X developer or you have some Objective-C background; you should definitely learn Swift.

If you are new developer, then it's really useful to start with Swift, because you will learn programming basics and techniques in Swift, and further Swift learning would be much easier. Although it would definitely useful to learn Objective-C as well, I would recommend learning Swift first so that you build your programming mindset on Swift.

If you already have some experience in Objective-C, then you should try Swift as soon as possible. It will not only give you the knowledge of a new programming language, but also open the door to new ideas and ways of solving problems in Objective-C. We can see that Objective-C has started evolving right now because of Swift.

Objective-C has many limitations because of its backward capabilities with C. It was created 23 years ago, in 1983, but it will die much sooner than Swift.

After the release of Swift version 1.0, in only a year's time we have seen many Swift applications successfully developed and released on the App Store. In this time period, many Swift tools and open source libraries that increase development productivity have been created.

During WWDC 2015, Apple announced that Swift will be made open source. This means that Swift can be used to write any software and not only iOS or OS X apps. You can write a piece of server-side code or web app in Swift. This is one more reason you should learn it.

On the other hand, we see that Swift is under constant development. There were many changes and improvements in version 1.2, and there were even more changes in version 2.0. Although it's very easy to upgrade to the newer Swift version with the Xcode migrator, it's something you should think about.

Swift has some promising performance characteristics. We have seen a huge performance improvement in the Swift 1.2 release, and some improvements in Swift 2.0 as well. You have seen from the previous example how fast Swift is, and in general, Swift has more potential to achieve high performance than Objective-C.

Finally, I want to mention a phrase I really like, by Bryan Irace:

When the iOS SDK says "Jump", ask "How High?"

Don't wait, learn Swift!

 

Swift's features and benefits


At this point, you know that you should learn Swift, and you shouldn't have any doubts. Let's take a look what makes Swift so amazing and powerful. Here is a list of a few important features that we are going to cover:

  • Clean and beautiful syntax

  • Type-safe

  • Reach types system

  • Powerful value types

  • A multiparadigm language—object-oriented, protocol-oriented, and functional

  • Generic purpose

  • Fast

  • Safe

Clean and beautiful

Powerful features and performance are important, but I think that cleanness and beauty are no less important. You write and read code everyday, and it has to be clean and beautiful so that you can enjoy it. Swift is very clean and beautiful, and the following are the main features that make it so.

No semicolons

Semicolons were created for the compiler. They help the compiler understand the source code and split it into commands and instructions. But the source code is written for people, and we should probably get rid of the compiler instructions from it:

var number = 10
number + 5

// Not recommended
var count = 1;
var age = 18; age++

There is no need for a semicolon (;) at the end of every instruction. It may seem like a very small feature, but it makes code so much nicer and easier to write and read. You can, however, put semicolons if you want. A semicolon is required when you have two instructions on the same line. There are also some exceptions when you have to use semicolons, a for loop as an example (for var i = 0; i < 10; i++), but in that context, they are used for a different purpose.

Tip

I strongly recommend not using semicolons, and avoid using more than one instruction in the same line.

Type inference

With type inference, you don't need to specify the types of variables and constants. Swift automatically detects the correct type from the context. Sometimes, however, you have to specify the type explicitly and provide type annotation. When there is no value assigned to the variable, Swift can't predict what type that variable should be:

var count = 10            //count: Int
var name = "Sara"         //name: String
var empty = name.isEmpty   //empty: Bool

// Not recommended
var count: Int = 10
var name: String = "Sara"
var empty: Bool = name.isEmpty

// When you must provide type annotation
var count: Int
var name: String

count = 10
name = "Sara"

In most cases, Swift can understand a variable's type from the value assigned to it.

Tip

Don't use type annotation if it's not required. Giving your variables descriptive names should be enough. This makes your code clean and nice to read.

Other clean code Swift features

The list of all of Swift's clean code features is very long; here are few of them: closure syntax, functions' default parameter values, functions' external parameter names, default initializers, subscripts, and operators:

  • Clean closure syntax: A closure is a standalone block of code that can be treated as a light unnamed function. It has the same functionality as a function but has a cleaner syntax. You can assign it to a variable, call it, or pass it as an argument to a function. For example, { $0 + 10 } is a closure:

    let add10 = { $0 + 10 }
    add10(5)
    
    let numbers = [1, 2, 3, 4]
    numbers.map { $0 + 10 }
    numbers.map(add10)
  • Default parameter values and external names: While declaring a function, you can define default values for parameters and give them different external names, which are used when you call that function. With default parameters, you can define one function but call it with different arguments. This reduces the need for creating unnecessary functions:

    func complexFunc (x: Int, _ y: Int = 0, extraNumber z: Int = 0, name: String = "default") -> String{
        return  "\(name): \(x) + \(y) + \(z) = \(x + y + z)"
    }
    
    complexFunc(10)
    complexFunc(10, 11)
    complexFunc(10, 11, extraNumber: 20, name: "name")
  • Default and memberwise initializers: Swift can create initializers for struct and base classes in some scenarios for you. Less code, better code:

    struct Person {
        let name: String
        let lastName: String
        let age: Int
    }
    
    Person(name: "Jon", lastName: "Bosh", age: 23)
  • Subscripts: This is a nice way of accessing the member elements of a collection. You can use any type as a key:

    let numbers = [1, 2, 3, 4]
    let num2 = numbers[2]
    
    let population = [
      "China" : 1_370_940_000,
      "Australia" : 23_830_900
    ]
    population["Australia"]

    You can also define a subscript operator for your own types or extend existing types by adding own subscript operator to them in an extension:

    // Custom subscript
    struct Stack {
      private var items: [Int]
      
      subscript (index: Int) -> Int {
        return items[index]
      }
    
      // Stack standard functions
      mutating func push(item: Int) {
        items.append(item)
      }
      
      mutating func pop() -> Int {
        return items.removeLast()
      }
    }
    
    var stack = Stack(items: [10, 2])
    stack.push(6)
    stack[2]
    stack.pop()
  • Operators: These are symbols that represent functionality, for example, the + operator. You can extend your types to support standard operators or create your own custom operators:

    let numbers = [10, 20]
    let array = [1, 2, 3]
    let res = array + numbers
    
    struct Vector {
      let x: Int
      let y: Int
    }
    
    func + (lhs: Vector, rhs: Vector) -> Vector {
      return Vector(x: lhs.x + rhs.x, y: lhs.y + rhs.y);
    }
    
    let a = Vector(x: 10, y: 5)
    let b = Vector(x: 2, y: 3)
    
    let c = a + b

    Tip

    Define your custom operators carefully. They can make code cleaner, but they can also bring much more complexity into the code and make it hard to understand.

  • guard: The guard statement is used to check whether a condition is met before continuing to execute the code. If the condition isn't met, it must exit the scope. The guard statement removes nested conditional statements and the Pyramid of Doom problem:

    Note

    Read more about the Pyramid of Doom at https://en.wikipedia.org/wiki/Pyramid_of_doom_(programming).

    func doItGuard(x: Int?, y: Int) {
      guard let x = x else { return }
      //handle x 
      print(x)
        
      guard y > 10 else { return }
      //handle y
      print(y)
     }

A clean code summary

As you can see, Swift is very clean and nice. The best way to show how clean and beautiful Swift is is by trying to implement the same functionality in Swift and Objective-C.

Let's say we have a list of people and we need to find the people with a certain age criteria and make their names lowercase.

This is what the Swift version of this code will look like:

struct Person {
  let name: String
  let age: Int
}

let people = [
  Person(name: "Sam", age: 10),
  Person(name: "Sara", age: 24),
  Person(name: "Ola", age: 42),
  Person(name: "Jon", age: 19)
]

let kids = people.filter { person in person.age < 18 }
let names = people.map { $0.name.lowercaseString }

The following is what the Objective-C version of this code will look like:

//Person.h File
@import Foundation;

@interface Person : NSObject

@property (nonatomic) NSString *name;
@property (nonatomic) NSInteger age;

- (instancetype)initWithName:(NSString *)name age:(NSInteger)age;

@end

//Person.m File
#import "Person.h"

@implementation Person

- (instancetype)initWithName:(NSString *)name age:(NSInteger)age {
  self = [super init];
  if (!self) return nil;

  _name = name;
  _age = age;

  return self;
}

@end

NSArray *people = @[
    [[Person alloc] initWithName:@"Sam" age:10],
    [[Person alloc] initWithName:@"Sara" age:24],
    [[Person alloc] initWithName:@"Ola" age:42],
    [[Person alloc] initWithName:@"Jon" age:19]
];

NSArray *kids = [people filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"age < 18"]];

NSMutableArray *names = [NSMutableArray new];
for (Person *person in people) {
  [names addObject:person.name.lowercaseString];
}

The results are quite astonishing. The Swift code has 14 lines, whereas the Objective-C code has 40 lines, with .h and .m files. Now you see the difference.

Safe

Swift is a very safe programming language, and it does a lot of security checks at compile time. The goal is to catch as many issues as possible during compiling and not when you run an application.

Swift is a type-safe programming language. If you made any mistakes with a type, such as trying to add an Int and a String or passing the wrong argument to a function, you will get an error:

let number = 10
let part = 1.5

number + part; // Error

let result = Double(number) + part

Swift doesn't do any typecasting for you; you have to do it explicitly, and this makes Swift even safer. In this example, we had to cast an Int number to the Double type before adding it.

Optionals

A very important safe type that was introduced in Swift is an optional. An optional is a way of representing the absence of a value—nil. You can't assign nil to a variable with the String type. Instead, you must declare that this variable can be nil by making it the optional String? type:

var name: String = "Sara"
name = nil //Error. You can't assign nil to a non-optional type

var maybeName: String?
maybeName = "Sara"
maybeName = nil // This is allowed now

To make a type an optional type, you must put a question mark (?) after the type, for example, Int?, String?, and Person?.

You can also declare an optional type using the Optional keyword, Optional<String>, but the shorter way with using ? is preferred:

var someName: Optional<String>

Optionals are like a box that contains some value or nothing. Before using the value, you need to unwrap it first. This technique is called unwrapping optionals, or optional binding if you assign an unwrapped value to a constant:

if let name = maybeName {
  var res = "Name - " + name
} else {
  print("No name")
}

Tip

You must always check whether an optional has a value before accessing it.

Error handling

Swift 2.0 has powerful and very simple-to-use error handling. Its syntax is very similar to the exception handling syntax in other languages, but it works in a different way. It has the throw, catch, and try keywords. Swift error handling consists of a few components, explained as follows:

  • An error object represents an error, and it must conform to the ErrorType protocol:

    enum MyErrors: ErrorType {
      case NotFound 
      case BadInstruction
    }

    Tip

    Swift enumerations fit best for representing a group of related error objects.

  • Every function that can throw an error must be declared using the throws keyword after its parameters' list:

    func dangerous(x: Int) throws
    func dangerousIncrease(x: Int) throws -> Int
  • To throw an error, use the throw keyword:

    throw MyErrors.BadInstruction
  • When you are calling a function that can throw an error, you must use the try keyword. This indicates that a function can fail and further code will not be executed:

      try dangerous(10)
  • If an error occurs, it must be caught and handled with the do and try keywords or thrown further by declaring that function with throws:

    do {
      try dangerous(10)
    }
    catch {
      print("error")
    }

Let's take a look at a code example that shows how to work with exceptions in Swift:

enum Error: ErrorType {
  case NotNumber(String)
  case Empty
}

func increase(x: String) throws -> String {
  if x.isEmpty {
    throw Error.Empty
  }
  
  guard let num = Int(x) else {
    throw Error.NotNumber(x)
  }
  
  return String(num + 1)
}

do {
  try increase("10")
  try increase("Hi")
}
catch Error.Empty {
  print("Empty")
}
catch Error.NotNumber (let string) {
  print("\"\(string)\" is not a number")
}
catch {
  print(error)
}

There are many other safety features in Swift:

  • Memory safety ensures that values are initialized before use.

  • Two-phase initialization process with security checks

  • Required method overriding and many others

Rich type system

Swift has the following powerful types:

  • Structures are flexible building blocks that can hold data and methods to manipulate that data. Structures are very similar to classes but they are value type:

    struct Person {
      let name: String
      let lastName: String
    
      func fullName() -> String {
        return name + " " + lastName
      }
    }
    
    let sara = Person(name: "Sara", lastName: "Johan")
    sara.fullName()
  • Tuples are a way of grouping multiple values into one type. Values inside a tuple can have different types. Tuples are very useful for returning multiple values from a function. You can access values inside a tuple by either index or name if the tuple has named elements; or you can assign each item in the tuple to a constant or a variable:

    let numbers = (1, 5.5)
    numbers.0
    numbers.1
    
    let result: (code: Int, message: String) = (404, "Not fount")
    result.code
    result.message
    
    let (code ,message) = (404, "Not fount")
  • Range represents a range of numbers from x to y. There are also two range operators that help create ranges: closed range operator and half-open range operator:

    let range = Range(start: 0, end: 100)
    let ten = 1...10 //Closed range, include last value 10
    let nine = 0..<10 //half-open, not include 10
  • Enumeration represents a group of common related values. An enumeration's member can be empty, have a raw value, or have an associated value of any type. Enumerations are first-class types; they can have methods, computed properties, initializer, and other features. They are great for type-safe coding:

    enum Action: String {
      case TakePhoto
      case SendEmail
      case Delete
    }
    
    let sendEmail = Action.SendEmail
    sendEmail.rawValue //"SendEmail"
    
    let delete = Action(rawValue: "Delete")

Powerful value types

There are two very powerful value types in Swift: struct and enum. Almost all types in the Swift standard library are implemented as immutable value types using struct or enum, for example, Range, String, Array, Int, Dictionary, Optionals, and others.

Value types have four big advantages over reference types, they are:

  • Immutable

  • Thread safe

  • Single owned

  • Allocated on the stack memory

Value types are immutable and only have a single owner. The value data is copied on assignment and when passing it as an argument to a function:

var str = "Hello"
var str2 = str

str += " :)"

Note

Swift is smart enough to perform value copying only if the value is mutated. Value copying doesn't happen on an assignment, that is str2 = str, but on value mutation, that is str += ":)". If you remove that line of code, str and str2 would share the same immutable data.

A multiparadigm language

Swift is a multiparadigm programming language. It supports many different programming styles, such as object-oriented, protocol-oriented, functional, generic, block-structured, imperative, and declarative programming. Let's take a look at a few of them in more detail here.

Object oriented

Swift supports the object-oriented programming style. It has classes with the single inheritance model, the ability to conform to protocols, access control, nested types and initializers, properties with observers, and other features of OOP.

Protocol oriented

The concept of protocols and protocol-oriented programming is not new, but Swift protocols have some powerful features that make them special. The general idea of protocol-oriented programming is to use protocols instead of types. In this way, we can create a very flexible system with weak binding to concrete types.

In Swift, you can extend protocols and provide a method's default implementation:

extension CollectionType {

  func findFirst (find: (Self.Generator.Element) -> Bool) -> Self.Generator.Element? {
    
    for x in self { 
      if find(x) {
        return x
      }
    }
    return nil
  }
}

Now, every type that implements CollectionType has a findFirst method:

let a = [1, 200, 400]
let r = a.findFirst { $0  > 100 }

One big advantage of using protocol-oriented programming is that we can add methods to related types and use the dot (.) syntax for method chaining instead of using free functions and passing arguments:

let ar = [1, 200, 400]

//Old way
map(filter(map(ar) { $0 * 2 }) { $0 > 50 }) { $0 + 10 } 

//New way
ar.map{ $0 * 2 } .filter{ $0 > 50 } .map{ $0 + 10 }

Functional

Swift also supports the functional programming style. In functional languages, a function is a type and it is treated in the same way as other types, such as Int; also, it is called a first class function. Functions can be assigned to a variable and passed as an argument to other functions. This really helps to decouple your code and makes it more reusable.

A great example is a filter function of an array. It takes a function that performs the actual filtering logic, and it gives us so much flexibility:

// Array filter function from Swift standard library
func filter(includeElement: (T) -> Bool) -> [T]

let numbers = [1, 2, 4]

func isEven (x: Int) -> Bool {
    return x % 2 == 0
}
let res = numbers.filter(isEven)

Generic purpose

Swift has a very powerful feature called generics. Generics allow you to write generic code without mentioning a specific type that it should work with. Generics are very useful for building algorithms, reusable code, and frameworks. The best way to explain generics is by showing an example. Let's create a minimum function that will return a smaller value:

func minimum(x: Int, _ y: Int) -> Int {
  return (x < y) ? x : y
}

minimum(10, 11)
minimum(11,5, 14.3) // error

This function has a limitation; it will work only with integers. However, the logic of getting a smaller value is the same for all types—compare them and return the smaller value. This is very generic code.

Let's make our minimum function generic and work with different types:

func minimum <T : Comparable>(x: T, _ y: T) -> T {
  return (x < y) ? x : y
}

minimum (10, 11)
minimum (10.5, 1.4)
minimum ("A", "ABC")

Tip

The Swift standard library has already implemented a generic min function. Use that instead.

Fast

Swift is designed to be fast and have high performance, and this is achieved with the following techniques:

  • Compile-time method binding

  • Strong typing and compile time optimization

  • Memory layout optimization

Later, we will cover in more detail how Swift uses these techniques to improve performance.

 

Swift interoperability


There are two main points that Apple thought of when introducing Swift:

  • The usage of the Cocoa framework and established Cocoa patterns

  • Easy to adopt and migrate

Apple understood that and took it very seriously while working on Swift. They made Swift work seamlessly with Objective-C and Cocoa. You can use all Objective-C code in Swift, and you can even use Swift in Objective-C.

It's very crucial to be able to use the Cocoa framework. All of the code that is written in Objective-C is available for use in Swift, both Apple frameworks and third-party libraries as well.

Using Objective-C in Swift

All the Cocoa frameworks written in Objective-C are available in Swift by default. You just need to import them and then use them. Swift doesn't have header files; instead, you need to use a module name. You can also include your own Swift frameworks in the same way:

import Foundation
import UIKit
import Alamofire // Custom framework

Setup

To include your own Objective-C source files, you need to do a small setup first. The process is a bit different for the application target and framework target. The main idea is the same—to import the Objective-C header files.

The application target

For the application target, you need to create a bridging header. A bridging header is a plain Objective-C header file in which you specify the Objective-C import statements.

Xcode will show a popup, offering to create, and set up a bridging header for you when you add the Objective-C file to a Swift project, or vice versa for the first time. This is the best and the most convenient way to add it.

If you decline the Xcode help, you can create a bridging header yourself anytime. To do that, you need to follow these steps:

  1. Add a new header file to the project.

  2. Go to Target | Build Settings.

  3. Search for Objective-C Bridging Header and specify the path to the bridging header file created in step 1.

Once you set up bridging header, the next step is to add import statements to it:

Bridging.h

//
//  Use this file to import your target's public headers that you //  would like to expose to Swift.

#import "MyClass.h"
The framework target

For the framework target, you simply need to import the .h Objective-C header files to the framework's umbrella header. The Objective-C header files must be marked as public. The umbrella header is the header in which you specify your publicly available API. Usually, it looks like this—the ExampleFramework.h umbrella header:

#import <UIKit/UIKit.h>

//! Project version number for MySwiftKit.
FOUNDATION_EXPORT double MySwiftKitVersionNumber;

//! Project version string for MySwiftKit.
FOUNDATION_EXPORT const unsigned char MySwiftKitVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <MySwiftKit/PublicHeader.h>

#import <SimpleFramework/MyClass.h>

Calling Objective-C code

Once you are done with the setup, you can use all Objective-C APIs in Swift. You can create instances, call methods, inherit from Objective-C classes, conform to protocols, and do other things that you can do in Objective-C. In this example, we will use the Foundation classes, but the rules are the same for third-party code as well:

import UIKit
import Foundation

let date = NSDate()
date.timeIntervalSinceNow

UIColor.blackColor()
UIColor(red: 0.5, green: 1, blue: 1, alpha: 1)

class MyView: UIView {
    //custom implementation
}

Tip

Inherit from Objective-C classes only if you need it. This can have a negative impact on performance.

There is free bridging between Swift types and Objective-C Foundation types. Automatic bridging happens on assignment and when you pass it as an argument to a function:

let array = [1, 2, 3]

func takeArray(array: NSArray) { }

var objcArray: NSArray = array
takeArray(array)

Converting from Objective-C to a Swift type requires explicit type casting. There are two types of casting: downcasting and upcasting. Casting is usually an unsafe operation, which could fail, and that's why it returns an optional type:

//Upcasting or safe casting
let otherArray: [AnyObject] = objcArray as [AnyObject]

//Downcasting, unsafe casting
if let safeNums = objcArray as? [Int] {
  safeNums[0] + 10 //11
}

let string: NSString = "Hi"
let str: String = string as String

The String type has gone one step even further. You can invoke the Objective-C foundation methods on the Swift String type without any type casting:

var name: String = "Name"
name.stringByAppendingString(": Sara")

Swift made a small improvement to Objective-C code so that it looks more Swift-style. The biggest change is made to instance creation and the style of the initialization code. The init, the initWith, and other factory methods are transformed into Swift initializers:

//Objective-C

- (instancetype)initWithFrame:(CGRect)frame;
+ (UIColor *)colorWithWhite:(CGFloat)white alpha:(CGFloat)alpha;

// Swift 
init(frame: CGRect)
init(white: CGFloat, alpha: CGFloat)

The other change is made to NS_ENUM and NS_OPTIONS. They become native Swift types: enum and RawOptionSetType.

As you can see, the API looks a bit different. Because Swift strives for cleanliness, it removes word duplications from the API nomenclature. The other method calls, properties, and names, are the same as they were in Objective-C, so it should be easy to find and understand them.

What is happening behind the scenes is that Swift is generating special interface files to interact with Objective-C. You can see these Swift interface files by holding down the command key and clicking on the type, NSDate and UIColor in our example.

Using Swift in Objective-C

It is also possible to use Swift in Objective-C. It makes Swift very easy to adapt to an existing project. You can start by adding one Swift file, and move more functionality to Swift over time.

The setup process is much easier than that for including Objective-C in Swift. All you need to do is import Swift's autogenerated header to Objective-C. The naming convention of the files for application targets is ProductModuleName + -Swift.h, and for frameworks, it is <ProductName/ProductModuleName + -Swift.h>.

Take a look at the following examples:

#import "SwiftApp-Swift.h"
#import <MySwiftKit/MySwiftKit-Swift.h>

You can inspect the content of that autogenerated file by holding down the command key and clicking on it. By default, Swift classes aren't exposed for use in Objective-C. There are two ways of making Swift classes available in Objective-C:

  • Mark the Swift class, protocol, or enumeration with the @objc attribute.

    You can mark classes, methods, protocols, and enumerations with the @objc attribute. The @objc attribute also accepts the alternative name that is used for Objective-C. When you expose a Swift class by marking it with the @objc attribute, it has to inherit from the Objective-C class, and the enumeration must have a raw Int value:

    @objc(KOKPerson) class Person: NSObject {
      @objc(isMan) func man() -> Bool {
        ...
      }
    }
    @objc enum Options: Int {
      case One
      case Two
    }

    Now, the KOKPerson class with the isMan method is available for use in Objective-C.

  • Inherit from an Objective-C class, NSObject for example:

    When you inherit from an Objective-C class, your Swift class automatically becomes available in Objective-C. You don't need to perform any extra steps in such cases. You can also mark it with the @objc attribute and provide an alternative name:

    class Person: NSObject {
    }

Features of Swift that are not available in Objective-C

There are some features of Swift that are not available in Objective-C, so if you plan to use Swift code from Objective-C, you should avoid using them. Here is the complete list of these features:

  • Structures

  • Generics

  • Tuples

  • Enumerations

  • Type aliases

  • Top-level functions

  • Curried functions

  • Global variables

  • Swift-style variadic parameters

  • Nested types

 

Performance – meaning and key metrics


There are two key characteristics of code:

  • Code quality: It has to be solid and flexible and have a good architecture

  • Code performance: It has to be fast

Making the code architecture very solid and stable is the most important task, but we shouldn't forget about making it fast as well. Achieving high performance can be a tricky and dangerous task. Here are a few things that you should keep in mind while working on performance improvement:

  • Don't optimize your code upfront

    There are many articles about this topic, why it's dangerous, and why you shouldn't do it. Just don't do it, and as Donald Knut says:

    "Premature optimization is the root of all evil"

  • Measure first

    Firstly, don't optimize upfront, and secondly, measure first. Measure the code's performance characteristics and optimize only those parts that are slow. Almost 95 percent of code doesn't require performance optimization.

    I totally agree with these points, but there is another type of performance optimization that we should think of upfront.

Everyday code performance

The small decisions that we make every day include the following:

  • What type should it be, Int or String?

  • Should I create a new class for a new functionality or add to an existing one?

  • Use an array? Or maybe a set?

It seems as if these don't have any impact on the application's performance, and in most cases, they don't. However, making the right decision not only improves an application's speed, but also makes it more stable. This gives higher performance in application development. The small changes that we make every day make a big impact at the end of the year.

The importance of performance

High performance is very crucial. The performance of an app is directly related to user experience. Users want to get results immediately; they don't want to wait for the view to load, see a long Loading indicator, or see a lagging animation.

Every year, our computers and devices become more and more powerful, with more CPU speed, memory, storage, and storage speed. Performance problems could seem irrelevant because of this, but the software complexity increases as well. We have more complex data to store and process. We need to show animations and do a lot of other things.

The first way of solving a performance problem is by adding more power. We can add more servers to handle data, but we can't update our clients' PC and mobile devices. Also, adding more power doesn't solve the code performance issue itself, but just delays it for some time.

The second, and correct, solution is to remove the issue that causes the performance problem. For that, we need to identify the problem, the slow piece of the code, and improve it.

The key metrics

There are many things that impact an application's performance and user experience. We will cover the following key metrics:

  • Operations' performance speed

  • Memory usage

  • Disk space usage

The most important of these and the one that has the biggest impact is the operations' performance speed. It tells us how fast a particular task can be performed, for example, creating a new user, reading from a file, downloading an image, searching for a person with a particular name, and so on.

 

Summary


Swift is a powerful and fast programming language. In this chapter, you learned about many powerful features of Swift and how easy it is to start coding in Swift and integrate it into existing projects. We also covered why performance is important and what you should be thinking about when working with it.

In the next chapter, we will do more coding in Swift, and you will learn how to use all the features of Swift to make a good application architecture.

About the Author

  • Kostiantyn Koval

    Kostiantyn Koval is a passionate developer with 5 years of experience. All the time, his main passion and work has been building iOS applications. So far, he has built many different applications, including games, enterprise apps, and big platforms. He fell in love with Swift the first minute he saw it, and keeps expressing this to the rest of the world.

    Other than iOS, he is also interested in technologies and languages such as Scala, Clojure, LLVM, Ruby, JavaScript, and others.

    He loves open source and blogging. You can find him on GitHub at https://github.com/kostiakoval and his blogs at https://medium.com/@kostiakoval. Other places to contact him are http://kostiakoval.github.io and Twitter at @KostiaKoval.

    His hobbies are programming, building start-ups, and making this world better with software.

    Browse publications by this author

Latest Reviews

(8 reviews total)
reasonably good tech book at an attractive price
Excellent
Good