Introduction to Core ML

At WWDC 2017, Apple released a lot of exciting frameworks and APIs for us developer to use. Among all the new frameworks, one of the most popular is definitely Core ML. Core ML is a framework that can be harnessed to integrate machine learning models into your app. The best part about Core ML is that you don’t require extensive knowledge about neural networks or machine learning. Another bonus feature about Core ML is that you can use pre-trained data models as long as you convert it into a Core ML model. For demonstration purpose, we will be using a Core ML model that is available on Apple’s Developer Website. Without further ado, let’s start to learn Core ML.

What’s Core ML

Core ML lets you integrate a broad variety of machine learning model types into your app. In addition to supporting extensive deep learning with over 30 layer types, it also supports standard models such as tree ensembles, SVMs, and generalized linear models. Because it’s built on top of low level technologies like Metal and Accelerate, Core ML seamlessly takes advantage of the CPU and GPU to provide maximum performance and efficiency. You can run machine learning models on the device so data doesn’t need to leave the device to be analyzed.

Apple’s official documentation about Core ML

Core ML is a brand new machine learning framework, announed during this year’s WWDC, that comes along with iOS 11. With Core ML, you can integrate machine learning models into your app. Let’s back up a little bit. What is machine learning? Simply put, machine learning is the application of giving computers the ability to learn without being explicitly programmed. A trained model is the result of combining a machine learning algorithm with a set of training data.

trained-model

As an application developer, our main concern is how we can apply this model to our app to do some really interesting things. Luckily, with Core ML, Apple has made it so simple to integrate different machine learning models into our apps. This opens up many possibilities for developers to build features such as image recognition, natural language processing (NLP), text prediction, etc.

Now you may be wondering if it is very difficult to bring this type of AI to your app. This is the best part. Core ML is very easy to use. In this tutorial, you will see that it only takes us 10 lines of code to integrate Core ML into our apps.

Cool, right? Let’s get started.

Demo App Overview

The app we are trying to make is fairly simple. Our app lets user either take a picture of something or choose a photo from their photo library. Then, the machine learning algorithm will try to predict what the object is in the picture. The result may not be perfect, but you will get an idea how you can apply Core ML in your app.

coreml-app-demo

Getting Started

To begin, first go to Xcode 9 and create a new project. Select the single-view application template for this project, and make sure the language is set to Swift.

Creating the User Interface

Editor’s note: If you do not want to build the UI from scratch, you can download the starter project and jump to the Core ML section directly.

Let’s begin! The first thing we want to do is to head on over to Main.storyboard and add a couple of UI elements to the view. Choose the view controller in storyboard, and then go up to the Xcode menu. Click Editor-> Embed In-> Navigation Controller. Once you have done that, you should see a navigation bar appear at the top of your view. Name the navigation bar Core ML (or whatever you see fit).

Next, drag in two bar button items: one on each side of the navigation bar title. For the bar button item on the left, go to the Attributes Inspector and change the System Item to “Camera”. On the right bar button item, name it “Library”. These two buttons let users pick a photo from his/her photo library or shoot one using camera.

The final two objects you need are a UILabel and a UIImageView. Take the UIImageView and center it into the middle of the view. Change the width and height of the image view to 299x299 thus making it a square. Now for the UILabel, place it all the way to the bottom of the view and stretch it such that it is touching both ends. That completes the UI for the app.

While I am not covering how to Auto Layout these views, it is highly recommended that you try to do so to avoid any misplaced views. If you can’t accomplish this, then build the storyboard on a device which you will be using to run the app.

Implementing the Camera and Photo Library Functions

Now that we have designed the UI, let’s move onto the implementation. We will implement both the library and camera buttons in this section. In ViewController.swift, first adopt the UINavigationControllerDelegate protocol that will be required by the UIImagePickerController class.

Then add two new outlets for both the label and image view. For simplicity, I have named the UIImageView imageView and the UILabel classifier. Your code should look like this:

Next, you need to create the respective actions from clicking the bar button items. Now insert the following action methods in the ViewController class:

To summarize what we did in each of these actions, we created a constant that is a UIImagePickerController. Then we made sure that the user can’t edit the photo that is taken (either from the photo library or the camera). Then we set the delegate to its self. . Finally, we present the UIImagePickerController to the user.

Because we didn’t add the UIImagePickerControllerDelegate class method to ViewController.swift, we will receive an error. We will adopt the delegate using an extension:

The line above handles the app if the user cancels the image taken. It also assigns the class method UIImagePickerControllerDelegate to our Swift file. Your code should now look a little like this.

Make sure you go back to the storyboard and connect all the outlet variables and action methods.

To access your camera and photo library, there is still one last thing you must do. Go to your Info.plist and two entries: Privacy – Camera Usage Description and Privacy – Photo Library Usage Description. Starting from iOS 10, you will need to specify the reason why your app needs to access the camera and photo library.

Okay, that’s it. You’re now ready to move onto the core part of the tutorial. Again, if you don’t want to build the demo app from scratch, download the starter project here.

Integrating the Core ML Data Model

Now, let’s switch gears for a bit and integrate the Core ML Data Model into our app. As mentioned earlier, we need a pre-trained model to work with Core ML. You can build your own model, but for this demo, we will use the pre-trained model available on Apple’s developer website.

Go to Apple’s Developer Website on Machine Learning, and scroll all the way down to the bottom of the page. You will find 4 pre-trained Core ML models.

coreml-pretrained-model

For this tutorial, we use the Inception v3 model but feel free to try out the other three. Once you have the Inception v3 model downloaded, add it into the Xcode Project and take a look at what is displayed.

Core ML Inception v3 model
Note: Please make sure that Target Membership of the project is selected, otherwise, your app will not be able to access the file.

In the above screen, you can see the type of data model, which is neural network classifier. The other information that you have to take note is model evaluation parameters. It tells you the input the model takes in, as well as, the output the model returns. Here it takes in a 299×299 image, and returns you with the most like category, plus the probability of each category.

The other thing you will notice is the model class. This is the model class (Inceptionv3) generated from the machine learning model such that we can directly use in our code. If you click the arrow next to Inceptionv3, you can see the source code of the class.

inceptionv3-class

Now, let’s add the model in our code. Go back to ViewController.swift. First, import the CoreML framework at the very beginning:

Next, declare a model variable in the class for the Inceptionv3 model, and initialize it in the viewWillAppear() method:

I know what you’re thinking.

“Well Sai, why don’t we initialize this model earlier?”

“What’s the point of defining it in the viewWillAppear function?”

Well, dear friends, the point is that when your app will try to recognize what the object in your image is, it will be a lot faster.

Now if we go back to Inceptionv3.mlmodel, we see that the only input this model takes is an image with dimensions of 299x299. So how do we convert an image into these dimensions? Well, that is what we wil be tackling next.

Converting the Images

In the extension of ViewController.swift, update the code like below. We implement the imagePickerController(_:didFinishPickingMediaWithInfo) method to process the selected image:

What the highlighted code does:

  1. Line #7-11: In the first few lines of the method, we retrieve the selected image from the info dictionary (using UIImagePickerControllerOriginalImage key). We also dismiss the UIImagePickerController once an image is selected.
  2. Line #13-16: Since our model only accepts images with dimensions of 299x299, we convert the image into a square. We then assign the square image to another constant newImage.
  3. Line #18-23: Now, we convert the newImage into a CVPixelBuffer. For those of you not familiar with CVPixelBuffer, it’s basically an image buffer which holds the pixels in the main memory. You can find out more about CVPixelBuffers here.
  4. Line #31-32: We then take all the pixels present in the image and convert them into a device-dependent RGB color space. Then, by creating all this data into a CGContext, we can easily call it whenever we need to render (or change) some of its underlying properties. This is what we do in the next two lines of code by translating and scaling the image.
  5. Line #34-38: Finally, we make the graphics context into the current context, render the image, remove the context from the top stack, and set imageView.image to the newImage.

Now, if you do not understand most of that code, no worries. This is really some advanced Core Image code, which is out of the scope of this tutorial. All you need to know is that we converted the image taken into something which the data model can take into. I would recommend you playing around with the numbers and seeing what the results in order to have a better understanding.

Using Core ML

Anyway, let’s shift the focus back to Core ML. We use the Inceptionv3 model to perform object recognition. With Core ML, to do that, all we need is just a few lines of code. Paste the following code snippet below the imageView.image = newImage line.

That’s it! The Inceptionv3 class has a generated method called prediction(image:) that is used to predict the object in the given image. Here we pass the method with the pixelBuffer variable, which is the resized image. Once the prediction, which is of the type String, is returned, we update the classifier label to set its text to what it has been recognized.

Now it’s time to test the app! Build and run the app in the simulator or your iPhone (with iOS 11 beta installed). Pick a photo from your photo library or take a photo using camera. The app will tell you what the image is about.

coreml-successful-case

While testing out the app, you may notice that the app doesn’t correctly predict what you pointed it at. This is not a problem with your code, but rather with the trained model.

coreml-failed-case

Before We Begin…

The purpose of this tutorial is to help you learn how to convert data models in various formats into the Core ML format. However before we begin, I should give you some background about machine learning frameworks. There are many popular deep learning frameworks out there which provide developers the tools to design, build, and train their own models. The model which we are going to use is from Caffe. Caffe was developed by Bekerley Artificial Intelligence Research (BAIR) and it is one of the most commonly used framework for creating machine learning models.

Apart from Caffe, there are also plenty other frameworks such as Keras, TensorFlow, and Scikit-learn. All of these frameworks have their own advantages and disadvantages which you can learn about here.

In machine learning, everything starts with the model, the system that makes predictions or identifications. Teaching computer to learn involves a machine learning algorithm with training data to learn from. The output generated from training is usually known as machine learning models. There are different types of maching learning models that solve the same problem (e.g. object recognition) but with different algorithms. Neural Networks, Tree Ensembles, SVMs are some of these machine learning algorithms.

Editor’s note: If you’re interested in learning more about machine learning model, you can take a look at this and this article.

At the time of publication, Core ML doesn’t support the conversion of all of these models from different frameworks. The following image, provided by Apple, shows the models and third-party tools supported by Core ML.

model-supported-by-coreml-tool

To convert the data models to Core ML format, we use a software called Core ML Tools. In the next section, we will be using Python to download these tools and use them for the conversion.

Installing Python and Setting Up the Environment

Lots of researchers and engineers have made Caffe models for different tasks with all kinds of architectures and data. These models are learned and applied for problems ranging from simple regression, to large-scale visual classification, to Siamese networks for image similarity, to speech and robotics applications.

– Caffe Model Zoo

You can find different pre-trained Caffe models on GitHub. To effectively share the models, BAIR introduces the model zoo framework. And, you can find some of the available models here. In this tutorial, I use this Caffe model to show you how to convert it to Core ML format, as well as, implementing flower identification.

To begin, download the starter project here. If you open the project and look at the code, you can see that the code required to access the camera and photo library are already filled out. You might recognize this from the previous tutorial. What is missing is the Core ML model.

You should also notice 3 more files in the project bundle: oxford102.caffemodel, deploy.prototxt and class_labels.txt. This is the Caffe model and files that we will use for demo. I will discuss in details with you later.

To use the Core ML tools, the first step is to install Python on your Mac. First, download Anaconda (Choose Python 2.7 version). Anaconda is a super easy way to run Python on your Mac without causing any problems. Once you have Anaconda installed, head over to terminal and type the following:

In these two lines of code, we install the python version we want. At the time this tutorial was written, the latest version of Python 2 was 2.7.13. Just in case, once Python installed, type the second line so it updates to the latest version.

install-python-terminal

The next step is to create a virtual environment. In a virtual environment, you can write programs with different versions of Python or packages in them. To create a new virtual environment, type the following lines of code.

When Terminal prompts you,

Type “y” for yes. Congrats! Now, you have a virtual environment named flowerrec!

Lastly, type the following command to install the Core ML Tools:

Converting The Caffe Model

Open Terminal again and type the code that will take you to your virtual environment:

Then change to the directory of your starter project that contains the three files: class_labels.txt, deploy.prototxt and oxford102.caffemodel.

Once you are in the folder, it’s time to initiate python. Simply type python and you will be taken to the Python interface within Terminal. The first step is to import the Core ML tools so that is exactly what we’ll do.

The next line is really important, so please pay attention. Type the following line but don’t press enter.

Now while this is a really short line, there is a lot going on here. Let me explain what these 3 files were about.

  1. deploy.prototxt – describes the structure of the neural network.
  2. oxford102.caffemodel – the trained data model in Caffe format.
  3. class_labels.txt – contains a list of all the flowers that the model is able to recognize.

In the statement above, we define a model named coreml_model as a converter from Caffe to Core ML, which is a result of the coremltools.converters.caffe.convert function. The last two parameters of this line are:

  1. image_input_names='data'
  2. class_labels='class_labels.txt'

These two parameters define the input and output we want our Core ML model to accept. Let me put it this way: computers can only understand numbers. So if we do not add these two parameters, our Core ML Model will only accept numbers as an input and output rather than an image and string as a input and output, respectively.

Now, you can press ENTER and treat yourself to a break. Depending the computational power of your machine, it will take some time for the converter to run. When the converter finishes, you will be greeted with a simple >>>.

python-convert-ml

Now that the Caffe model is converted, you need to save it. You can do this by typing

The .mlmodel file will save in the current folder/directory.

coreml-model-ready
Advertisements
Introduction to Core ML

How To Create a Cool 3D Sidebar Animation

Download the starter project, extract it, and open it in Xcode.

Take a moment and have a poke around in the project; you’ll see it’s a master-detail app that displays a table of images. The UITableViewController subclass MenuViewController uses the custom table view cell MenuItemCell in order to set the background color of each cell. The DetailViewController displays a large image using the same background color as the selected cell, as shown below:

You could imagine this as a basic app for negotiating coffee breaks or after-work cocktails with your colleagues or friends; thumbs-up if you’re game, thumbs-down if you can’t make it – and you can even decline due to inclement weather. :]

Creating the feature in this tutorial isn’t as complicated as you might think. You’ll build it up slowly as follows:

  • First, you’ll use Auto Layout in Interface Builder to convert a basic master-detail app to a horizontal scroll view, with the master and detail views embedded in containers.
  • Next, you’ll add a button to show or hide the menu.
  • Then you’ll implement the 3D effect to acheive the neat Taasky-like folding effect!
  • As a final touch, you’ll piggy-back on the menu animation to rotate the menu button, in sync with the act of showing or hiding the menu.

Your first task is to convert the menu into a slide-out sidebar, where a scroll view contains the menu and detail views side-by-side, as shown below:

The user can scroll right or left to show or hide the menu. The purple rectangle outlines the visible content when the menu is open, and the green rectangle outlines the detail view, which is fully visible when the menu is hidden. When the menu is open, the partial detail view provides a visual cue that the menu is a sidebar.

Note: If you’re unfamiliar with scroll views then please watch Part 1 and Part 2 of the Swift Scroll View School video series to refresh your understanding of how scroll views work.

SwiftSideNav, one of the samples from the Swift Scroll View School video series, sets up the Auto Layout constraints programmatically. But in this tutorial, you’ll set them up in directly in the storyboard, embedding the menu and detail views in container views. It will look like this when you’re done:

Adding Containers to UIScrollView

You’ll need a new view controller to coordinate the existing menu and detail view controllers. You’ll add a scroll view to its view, then add a Content view to the scroll view. Then you’ll add two container views to the Content view and embed the existing menu and detail views in these container views. To reduce errors and confusion, you’ll set up the Auto Layout constraints as you go.

Create a new Cocoa Touch Class file named ContainerViewController, making sure to subclass UIViewController. Also set the Language to Swift:

Note: You can zoom out the storyboard if you need to – right-click on an unoccupied part of the canvas and select one of the zoom options. Double-click anywhere on the empty canvas to return to the standard zoom. You can also zoom in and out using pinch gestures on a trackpad, or using the scroll wheel on your mouse if it has one.

Open Main.storyboard and drag a new View Controller from the Object Library onto the canvas to the left of the existing scenes. In the Identity Inspector, set Class\Custom Class to ContainerViewController:

Select your new View and set Background to Black Color in the Attributes Inspector:

Setting Up the Scroll View

Next, you’ll add a Scroll View to the view of ContainerViewController, then add its Auto Layout constraints.

In Interface Builder, drag a Scroll View onto ContainerViewController, and let it expand to fill the space. Next uncheck Shows Horizontal Indicator and Shows Vertical Indicator in the Attributes Inspector, to turn off the scroll view’s scroll bars. Also uncheck Delays Content Touches so that the menu will respond immediately when the user makes a selection, rather than having a slight delay:

Control-drag from the scroll view to its view controller, and select delegate in-order to set ContainerViewController as the scroll view’s delegate:

In the Pin constraints pop-up – found at the bottom of the Interface Builder window – uncheck Constrain to margins. Select the leading, top, trailing, and bottom constraints, make sure they’re values are all 0, and then click Add 4 Constraints to pin the four edges of the scroll view to its superview:

With the scroll view still selected, confirm the new constraints in the Size Inspector:

  • Trailing Space to: Superview
  • Leading Space to: Superview
  • Top Space to: Superview
  • Bottom Space to: Bottom Layout Guide

Numbers like -16 means the constraints are relative to the margin; fix these by deleting the necessary constraints and then re-pin the scroll view, being sure to uncheck Constrain to Margins.

Note: When you add or modify constraints, you might need to update the frame of a view to reflect the new constraints. Select the Resolve Auto Layout Issues button at the bottom of Interface Builder and select Update Frames as required.

Setting up the Content View

Now you’ll add a content view to the scroll view and set up its Auto Layout constraints; these constraints are important as they help determine the scroll view’s content size. In the next section, you’ll layout two container views in the content view to hold the menu and detail views.

Drag a new View onto the scroll view; let it expand to the size of the scene in Interface Builder, then set Background to Default in the Attributes Inspector:

Open the Identity Inspector for the content view you just added and set Document\Label to Content View; this label appears in the document outline and will help you keep track of the views, and it’s also the name referenced in Auto Layout contraints. You’ll place the two container views into Content View later.

Note: You’ll see Auto Layout warnings when you set up Content View’s constraints, but don’t panic as you’ll fix them before the end of the section.

Pin the four edges of Content View to its superview, which in this case is the Scroll View:

In the Size Inspector, ensure that the Trailing Space constraint’s Constant is set to 0:

The Auto Layout warning appears because the storyboard requires constraints on Content View’s height and width to determine the scroll view’s content size. Making these constraints relative to the scroll view’s superview lets the display adapt to various devices and orientations.

In the document outline, control-drag from Content View to View (Scroll View’s superview), hold down the Shift key, and select Equal Widths and Equal Heights:

Then edit the Equal Width constraint’s Constant to 80:

Setting the constant to 80 means the Content View will be 80 points wider than the viewable area of the View so it can accommodate the menu. You’ll see the Auto Layout warnings have now disappeared – good work! :]

Adding Menu and Detail Container Views

The scroll view now has a Content View for your two container views. You’ll embed the existing menu and detail views in these container views to create a menu sidebar you can swipe open or closed.

First, add the Menu Container View: drag a Container View onto Content View. In the Size Inspector, set Width to 80, then use the Identity Inspector to set Document\Label to Menu Container View:

The Height should default to 600, but if it doesn’t make sure to set that as well.

Next, add the Detail Container View: drag another Container View to the right of the menu container within Content View. Open the Size Inspector and set the following values:

  • X: 80
  • Y: 0
  • Width: 600
  • Height: 600

Then open the Identity Inspector and set the Document\Label to Detail Container View so you can easily identify the view:

The width of the two containers now equal the entire width of the Content View:

When you add a container view, Interface Builder will include a contained view controller scene by default; but you’ll connect your container views to the existing menu and detail view controllers. Delete the view controllers that are currently embedded in the container views:

Next, you’ll set up the Auto Layout constraints for the container views.

Pin the edges of Menu Container View its superview, and add a Width constraint with a constant of 80. You should add 5 constraints in total, as shown below:

Pin Detail Container View’s TopBottom, and Trailing edges; don’t pin the Leading edge, as it would duplicate the sibling Menu Container View’s Trailing constraint:

For both sets of contraints, make sure Constrain to margins in unchecked.

Embedding Menu and Detail View Controllers

In this section, you’ll separate the menu and detail view controllers, then embed them in Menu Container View and Detail Container View.

First, make Container View Controller the Initial view controller: drag the start arrow – which denotes the initial view controller in the storyboard – from the Navigation Controller to Container View Controller:

Next, embed control-drag from Menu Container View to Navigation Controller, and select embed from the pop-up menu:

Once the navigation controller is embedded in Menu Container View, each of the connected view’s widths in Interface Builder automatically shrink to 80 points:

Now to make some adjustments to the menu and detail scenes: first, change the Width of the table view cell’s image view to 80:

Next, delete the push segue between the menu and detail scenes. Select Detail View Controller, then select Editor\Embed In\Navigation Controller from the Xcode menu:

The Detail View Controller should now be the initial view controller of a new navigation controller, which will provide the black navigation bar with the icon to expand the menu.

Select the navigation bar of the new navigation controller and use the Attributes Inspector to set Style to Black, uncheck Translucent, and set Bar Tint to Black Color:

This adjusts this navigation bar to match the navigation bar of the first navigation controller.

Then, set up the new navigation controller to match the first navigation controller. In its Attributes Inspector, make sure View Controller\Layout\Adjust Scroll View Insets is checked:

Note: Checking Adjust Scroll View Insets causes the view’s content to start below the navigation bar, rather then underneath it.

Finally, embed Detail View Controller in Detail Container View. Control-drag from Detail Container View to Detail View Controller’s navigation controller, and select embed from the pop-up menu:

Build and run. Swipe left and right to hide or show the menu. Did you notice that you can scroll beyond the left and right edges, and stop scrolling with only part of the menu showing?

To fix these issues, change the following attributes of the scroll view using the Attributes Inspector:

  1. Check Scrolling\Paging Enabled so the container “snaps” to it’s boundaries.
  2. Uncheck Bounce\Bounces to prevent scrolling beyond the edges.

Build and run. Check that swiping right does nothing when the menu is open, and swiping left does nothing when the menu is closed. Also check that scrolling to part of the menu snaps it open. But what happens when you attempt to hide the menu?

It keeps snapping back open! This is a paging issue related to this problem discussion on StackOverflow. You’ll fix this in just a bit, once you create an outlet for the scroll view.

But there are other problems to fix first: the detail view is blank, and selecting a menu item doesn’t change anything:

This isn’t surprising, since you haven’t yet adjusted the code to use the container views. You’ll first make the detail view’s navigation bar match the menu view’s navigation bar.

Editing the Code to Use Containers

Before doing anything else, copy viewDidLoad() from MenuViewController.swift into DetailViewController.swift as shown below:

override func viewDidLoad() {
  super.viewDidLoad()
  // Remove the drop shadow from the navigation bar
  navigationController!.navigationBar.clipsToBounds = true
}

This eliminates the hairline shadow beneath the navigation bar. A small detail, but it’s one of those things that gives your app polish. :]

When the user selects a table cell, MenuViewController must set DetailViewController’s menuItemproperty, but DetailViewController isn’t directly connected to MenuViewController anymore. Instead, the ContainerViewController will act as the mediator between the menu and the content.

Add a property for the DetailViewController to the top of ContainerViewController.swift:

private var detailViewController: DetailViewController?

Implement prepareForSegue(_:sender:) in ContainerViewController.swift with the following code:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
  if segue.identifier == "DetailViewSegue" {
    let navigationController = segue.destinationViewController as! UINavigationController
    detailViewController = navigationController.topViewController as? DetailViewController
  }
}

segue.identifier! what segue, where? Well, embedding DetailViewController in the container creates a Storyboard Embed Segue, and you must set its Identifier in the Attributes inspector.

Then declare the menuItem property at the top of the class, whose didSet observer in-turn sets DetailViewController’s menuItem property:

var menuItem: NSDictionary? {
  didSet {
    if let detailViewController = detailViewController {
      detailViewController.menuItem = menuItem
    }
  }
}

There’s no longer a segue from a table view cell to the content view, but MenuViewController needs to respond when the user selects an item.

Delete prepareForSegue(_:sender:) from MenuViewController and add the following method — just be careful not to accept tableView(_:didDeselectRowAtIndexPath:) from Xcode’s list of autosuggestions by accident! :]

// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
  tableView.deselectRowAtIndexPath(indexPath, animated: true)
  let menuItem = menuItems[indexPath.row] as! NSDictionary
  (navigationController!.parentViewController as! ContainerViewController).menuItem = menuItem
}

Here, you simply set ContainerViewController’s menuItem property based on the selected row. This triggers the property’s didSet observer, which in-turn sets DetailViewController’s menuItem property.

As a final touch, add the following line to viewDidLoad() in MenuViewController.swift:

(navigationController!.parentViewController as! ContainerViewController).menuItem = 
  (menuItems[0] as! NSDictionary)

This sets the image in the detail view when the app is first launched.

Build and run. The detail view shows the smiley image on launch, the menu view appears along the left edge of the center view, and selecting an item displays its larger image in the detail view, as shown below:

Showing and Hiding Your Menu

The menu should dismiss when the user selects an item from the menu. To do this, you need to set the scroll view content’s horizontal offset to Menu Container View’s width so the scroll view shows only Detail Container View.

You’ll first need references to the scroll view and to Menu Container View.

Create an outlet named scrollView in ContainerViewController.swift: select Scroll View in the storyboard’s document outline, open the Assistant Editor, and control-drag from Scroll View into ContainerViewController.swift. Enter scrollView for Name and click Connect:

Note: I’ve’ used View\Assistant Editor\Assistant Editors on Bottom to place the Assistant Editor at the foot of the Xcode window, so I didn’t have to drag things across the storyboard canvas.

Select and control-drag from Menu Container View into ContainerViewController.swift, and create an outlet named menuContainerView:

Next, add the hideOrShowMenu(_:animated:) method to ContainerViewController.swift:

// MARK: ContainerViewController
func hideOrShowMenu(show: Bool, animated: Bool) {
  let menuOffset = CGRectGetWidth(menuContainerView.bounds)
  scrollView.setContentOffset(show ? CGPointZero : CGPoint(x: menuOffset, y: 0), animated: animated)
}

The value of menuOffset is 80 — the width of Menu Container View. If show is true, the origin of scrollView is at 0,0 and the menu is visible. Otherwise, the origin of scrollView is at 80,0 and the menu is hidden.

Now, call hideOrShowMenu(_:animated:) from the didSet observer on menuItem:

var menuItem: NSDictionary? {
  didSet {
    hideOrShowMenu(false, animated: true)
    // ...

The value of show is set to false to hide the menu when the user selects an item.

Also call hideOrShowMenu(_:animated:) in viewDidLoad() to hide the menu when the app starts:

override func viewDidLoad() {
  super.viewDidLoad()
  hideOrShowMenu(false, animated: false)
}

Build and run. It starts with the smiley image selected and the menu hidden. Slide out the menu and select an item; the detail view slides across, hides the menu and displays the new item’s image and background color:

However, that paging issue remains. If you slide out the menu and don’t select an item, closing the menu causes it to spring back open. You’ll fix this by employing a UIScrollViewDelegate method.

Add the following protocol to the class declaration of ContainerViewController:

class ContainerViewController: UIViewController, UIScrollViewDelegate {

Next, add the following scroll view delegate method to ContainerViewController:

// MARK: - UIScrollViewDelegate
func scrollViewDidScroll(scrollView: UIScrollView) {
  /*
  Fix for the UIScrollView paging-related issue mentioned here:
  http://stackoverflow.com/questions/4480512/uiscrollview-single-tap-scrolls-it-to-top
  */
  scrollView.pagingEnabled = scrollView.contentOffset.x < (scrollView.contentSize.width - CGRectGetWidth(scrollView.frame))
}

This disables paging when the scroll view’s content offset equals the menu width; when the menu is completely hidden, it stays hidden. Once the user starts to slide out the menu it re-enables paging so the menu snaps open.

Build and run. The paging issue is now fixed:

Looking good! But there’s still something missing. The hamburger menu button in the detail view’s navigation bar that rotates as the menu moves. Tapping it should toggle the menu open or closed.

Adding the Menu Button

Note: The hamburger icon gets a lot of negative press as it hides functionality from users; see Why We Banished the Hamburger Menu From Our iPhone App, as an example. However, the original Taasky app featured it, so you get the full hamburger meal deal in this tutorial. :]

You’ll need to set up the menu button as a custom view so that it can rotate when you reveal the menu.

Create a new Swift Cocoa Touch Class file named HamburgerView.swift, making sure to subclass UIView.

Populate the class with the following code:

class HamburgerView: UIView {

  let imageView: UIImageView! = UIImageView(image: UIImage(named: “Hamburger”))

  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    configure()
  }

  required override init(frame: CGRect) {
    super.init(frame: frame)
    configure()
  }

  // MARK: Private

  private func configure() {
    imageView.contentMode = UIViewContentMode.Center
    addSubview(imageView)
  }

}

Here you set up the required initializers, both of which call through to a utility method that simply creates an image view and adds it as a subview.

In DetailViewController.swift, add the following hamburgerView property:

var hamburgerView: HamburgerView?

In viewDidLoad(), create and add an instance of hamburgerView to the navigation bar as a left bar button, including a tap gesture recognizer:

let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: “hamburgerViewTapped”)
hamburgerView = HamburgerView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
hamburgerView!.addGestureRecognizer(tapGestureRecognizer)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: hamburgerView!)

hamburgerViewTapped() will call ContainerViewController’s hideOrShowMenu(_:animated:), but what value should it pass as the show argument? You need a Bool property in ContainerViewController, to keep track of whether the menu is open or closed.

Add the folllowing property to the top of ContainerViewController.swift:

var showingMenu = false

The menu’s hidden when the app starts. Override viewDidLayoutSubviews() to hide or show the menu when the bounds change, such as when the device rotates:

override func viewDidLayoutSubviews() {
  super.viewDidLayoutSubviews()
  hideOrShowMenu(showingMenu, animated: false)
}

You no longer need viewDidLoad(), so delete it completely from ContainerViewController.swift.

Open DetailViewController.swift and add the following code:

func hamburgerViewTapped() {
  let navigationController = parentViewController as! UINavigationController
  let containerViewController = navigationController.parentViewController as! ContainerViewController
  containerViewController.hideOrShowMenu(!containerViewController.showingMenu, animated: true)
}

When the user taps the button, and the menu is hidden — if showingMenu equals false — then this method calls hideOrShowMenu(_:animated:) passing true to show the menu. Conversely, when the menu is open — showingMenu equals true — tapping the button will hide the menu.. Therefore, you must update the value of showingMenu in hideOrShowMenu(_:animated:) in ContainerViewController.swift.

Add the following line to hideOrShowMenu(_:animated:):

showingMenu = show

Build and run. Try different combinations of scrolling, selecting cells, and button-tapping to show and hide the menu:

There’s just one problem. If you slide the menu open or closed instead of using the button, it takes two taps of the button to get the menu to respond. Why?

This happens because scrolling doesn’t update the value of showingMenu. Swiping the menu open leaves the value at false. The first tap appears to do nothing as it sets the value to true, so the menu stays open. The second tap then hides the menu as it sets the value to false.

To fix this, you need to set showingMenu in one of the other UIScrollViewDelegate methods in ContainerViewController. Add the following:

func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
  let menuOffset = CGRectGetWidth(menuContainerView.bounds)
  showingMenu = !CGPointEqualToPoint(CGPoint(x: menuOffset, y: 0), scrollView.contentOffset)
  println(“didEndDecelerating showingMenu \(showingMenu)”)
}

When the scrolling stops, this delegate method sets showingMenu to false if the scroll view’s content offset equals the menu width — that is, the menu is hidden — otherwise it sets it to true.

Build and run. Swipe right and check the console to see if this method kicks in when you stop. It’s a bit hit or miss, and seems to depend on the scrolling speed. When I tested the app in the simulator, it only worked when I scrolled slowly, but on my iPhone, it only worked when I scrolled quickly. Go figure! :]

Move the above statements into scrollViewDidScroll(_:), where it’s much less efficient – this method is called continously as the user scrolls – but far more reliable:

You’ll get to the button rotation in just a bit — but first, you’ll take care of the 3D menu effect.

Adding Perspective to Your Menu

The ultra-cool animated version of your menu should look similar to a door opening and closing. As well, the menu button will rotate smoothly clockwise as the menu opens, and counter-clockwise as the menu closes.

To accomplish this, you’ll calculate the fraction of the menu view that’s visible, then use this to calculate the menu’s angle of rotation.

In ContainerViewController.swift, add the following private method to create the 3D transform, depending on the fraction of the menu shown:

func transformForFraction(fraction:CGFloat) -> CATransform3D {
  var identity = CATransform3DIdentity
  identity.m34 = -1.0 / 1000.0;
  let angle = Double(1.0 - fraction) * -M_PI_2
  let xOffset = CGRectGetWidth(menuContainerView.bounds) * 0.5
  let rotateTransform = CATransform3DRotate(identity, CGFloat(angle), 0.0, 1.0, 0.0)
  let translateTransform = CATransform3DMakeTranslation(xOffset, 0.0, 0.0)
  return CATransform3DConcat(rotateTransform, translateTransform)
}

Here’s the play-by-play of transformForFraction(_:):

  • fraction is 0 when the menu is completely hidden, and 1 when the menu is completely visible.
  • CATransform3DIdentity is the 4×4 matrix with 1s on the diagonal and 0s everywhere else.
  • CATransform3DIdentity’s m34 property is the value in row 3, column 4, which controls the amount of perspective in the transform.
  • CATransform3DRotate uses angle to determine the amount of rotation around the y-axis: -90 degrees renders the menu perpendicular to the back of the view and 0 degrees renders the menu parallel with the x-y plane.
  • rotateTransform rotates the identity transform by angle degrees around the y-axis by the amount noted in its m34 perspective parameter.
  • translateTransform moves the menu from half of its width to the correct position when rotation finishes.
  • CATransform3DConcat concatenates translateTransform and rotateTransform so that the menu appears to slide sideways while rotating.

Notem34 is usually calculated as 1 divided by a number that represents your position on the z-axis while observing the 2D x-y plane. Negative z-values indicate the viewer is in front of the plane, while positive z-values indicate the viewer is behind the plane.

Drawing lines between this viewer and the edges of objects in the plane produces the effect of 3D perspective. As the viewer moves farther away, the perspective is less pronounced. Try changing 1000 to 500 or 2000 to see how the menu’s perspective changes.

Now add the following lines to scrollViewDidScroll(_:):

let multiplier = 1.0 / CGRectGetWidth(menuContainerView.bounds)
let offset = scrollView.contentOffset.x * multiplier
let fraction = 1.0 - offset
menuContainerView.layer.transform = transformForFraction(fraction)
menuContainerView.alpha = fraction

The value of offset is between 0 and 1. When it’s 0 it means the menu is completely visible, and when it’s 1 it means the menu is completely hidden. Think of it as a measure of the menu’s hiddenness – and yes, according to my Mac’s lookup, hiddenness really is a word! :]

Consequently, fraction is the visible fraction of the menu width, ranging between 0 when the menu is completely hidden and 1 when the menu is completely visible.

You also use fraction to adjust the menu’s alpha value to darken and lighten the menu as it closes and opens respectively.

Build and run. Swipe to to see the 3D effect and…uh oh. There’s something wrong with the menu’s “hinge”, because the default anchorPoint of the view – the point at which the transform is applied – is in its centre.

To make the menu hinge around its right edge, add the following line to viewDidLayoutSubviews() in ContainerViewController.swift:

menuContainerView.layer.anchorPoint = CGPoint(x: 1.0, y: 0.5)

Setting the x value to 1.0 move it all the way to the right-edge.

Build and run. Bask in your glorious 3D folding animation!

One Last Thing: Animating the Menu Button

Now you can put the final finishing touch on your app by rotating the menu button.

When the menu is closed, you see the standard menu icon. When the menu opens, the button should rotate 90 degrees clockwise. When the menu closes, the button should rotate counter-clockwise back to 0 degrees.

Note: Technically speaking, it’s the menu button’s imageView that you rotate. But the resulting effect is that the button itself appears to rotate.

Add the following method to HamburgerView.swift:

func rotate(fraction: CGFloat) {
  let angle = Double(fraction) * M_PI_2
  imageView.transform = CGAffineTransformMakeRotation(CGFloat(angle))
}

Here you rotate the image view smoothly. You use fraction to calculate an angle between 0 and 90 degrees, and rotate the view accordingly. For the curious ones, M_PI_2 above is defined in math.h, and is the mathematical constant for pi/2.

Now add the following lines to scrollViewDidScroll(_:), to make the view rotate as you move the scroll view:

if let detailViewController = detailViewController {
  if let rotatingView = detailViewController.hamburgerView {
    rotatingView.rotate(fraction)
  }
}

Build and run. Swipe and tap to see your animations in motion, and totally in sync:

How To Create a Cool 3D Sidebar Animation

Properties In Swift

Stored Properties

Properties associate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance.
In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure.

struct Size {
 var width: Int 
 let height: Int 
}
var size1 = Size(width: 10, height: 35)
size1.width = 6

In the example above, height is initialized when the new size is created. This is a constant property, and it cannot be changed once initialized.
When creating an instance of a structure, if you assign an instance of a structure to a constant, the instance‘s properties cannot be modified, even if they were declared as variable properties.

Lazy Stored Properties

A lazy stored property’s initial value is not calculated until the first time it is used.

class DataManager {
 lazy var importer = DataImporter()
 var data = [String]()
}

Lazy properties are useful when a property’s initial value is dependent on outside factors, the values of which are not known until after an instance‘s initialization is complete; or when the initial value for a property requires complex or computationally expensive setup that should not be performed unless or until it is needed.
You must always declare a lazy property as a variable, using the var keyword, because its initial value might not be retrieved until after the completion of instance initialization. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.

Computed Properties

Rather than storing a value, a computed property provides a getter and, optionally, a setter, which indirectly retrieve and set other properties and values, respectively.

struct Point {
 var x = 0.0, y = 0.0
}
struct Shape {
 var origin = Point() 
 var center: Point {
  get {
   return Point(x: origin.x/2 , y: origin.y/2)
  }
  set(newCenter) {
   origin.x = newCenter.x/2
   origin.y = newCenter.y/2
  }
 }
}

The Shape structure defines a custom getter and setter for a computed variable called center. The center property is then accessed through dot syntax, which causes the getter for center to be called to retrieve the current property value. Rather than returning an existing value, the getter actually calculates and returns a new point that represents the center of the shape.

If a computed property’s setter does not define a name for the new value to be set, a default name of newValue is used.
Below is an alternative version of the Rect structure, which takes advantage of this shorthand notation:

struct Point {
 var x = 0.0, y = 0.0
}
struct Shape {
 var origin = Point() 
 var center: Point {
  get {
   return Point(x: origin.x/2, y: origin.y/2)
  }
  set {
   origin.x = newValue.x/2
   origin.y = newValue.y/2
  }
 }
}

A computed property with a getter but no setter is known as a read-only computed property. It always returns a value, and can be accessed through dot syntax. However, that value cannot be altered.

Property Observers

Property observers detect and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value.
Property observers can be added to any defined stored properties, with the exception of lazy stored properties.
You have the option of defining either or both of the following observers of a property:
willSet is called just before the value is stored.
didSet is called immediately after the new value is stored.

The example below defines a new class called StepCounter, which tracks the total number of steps that a person takes while walking.

class StepCounter {
 var totalSteps: Int = 0 {
  willSet(newSteps) {
   print("About to set totalSteps to \(newSteps)")
  }
  didSet {
   if totalSteps > oldValue  {
   print("Added \(totalSteps - oldValue) steps")
   }
  }
 }
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 50
// About to set totalSteps to 50
// Added 50 steps
stepCounter.totalSteps = 150
// About to set totalSteps to 150
// Added 100 steps
stepCounter.totalSteps = 420
// About to set totalSteps to 420
// Added 270 steps

The StepCounter class declares a totalSteps property of type Int, with willSet and didSet observers.
The willSet and didSet observers for totalSteps are called whenever the property is assigned a new value.
The willSet observer uses a custom parameter name of newSteps for the upcoming new value.

The didSet observer is called after the value of totalSteps is updated. It compares the new value of totalSteps against the old value. The didSet observer does not provide a custom parameter name for the old value; the default name of oldValue is used, instead.
Similarly, newValue could be used for the willSet observer, if no parameter name was defined.
If you assign a value to a property within its own didSet observer, the new assigned value will replace the one that was just set.

Type Properties

Type properties are useful when defining values that are universal to all instances of a particular type, such as a constant property used in all instances, or a variable property that stores a global value to all instances of that type. Stored type properties can be variables or constants. You define type properties with the static keyword:

class SomeClass {
 static var storedProp = "Some value."
 static var computedProp: Int {
   return 42
 }
}

Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type:

print(SomeClass.storedProp) 

Unlike stored instance properties, you must always give stored type properties a default value. This is because the type itself does not have an initializer that can assign a value to a stored type property at initialization time.

Properties In Swift

Some Additional Functionalities Of Swift – Part 3

Classes vs. Structures

Structure instances are always passed by value, and class instances are always passed by reference. This means that they are suited to different kinds of tasks.
As a general guideline, consider creating a structure instead of a class when one or more of these conditions apply:

1. The structure’s primary purpose is to encapsulate a few relatively simple data values.
2. It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure.
3. Any properties stored by the structure are themselves value types, which you would also expect to be copied, as opposed to being referenced.
4. It is not necessary for the structure to inherit properties or behavior from another existing type.

For example, the size of a geometric shape would be a good choice for a structure, with the structure perhaps encapsulating a width property and a height property, both of type Double.

In all other cases, define a class. You will find that most custom data constructs should be defined as classes rather than as structures.
Swift’s String, Array, and Dictionary types are implemented as structures.

Modifying Value Types

Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.
The mutating keyword is added to the method‘s definition so it can modify its properties.

struct Point {
 var x = 0.0, y = 0.0
 mutating func moveByX(dX: Double, dY: Double) {
   x += dX
   y += dY
 }
}

You cannot call a mutating method on a constant of structure type, because its properties cannot be changed.
Mutating methods can assign an entirely new instance to the implicit self property.

Type Methods

Instance methods are called on an instance of a particular type. A type method is called on the type itself, and is indicated by writing the keyword static before the method‘s func keyword:

class SomeClass {
 static func someTypeMethod() {
 // type method implementation goes here
 }
}
SomeClass.someTypeMethod()

As with instance methods, type methods are called with dot syntax. However, type methods are called on the type, not on an instance of that type.
Within the body of a type method, the implicit self property refers to the type itself, rather than an instance of that type.

Subscripts

Classes, structures, and enumerations can define subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence. Subscripts enable you to query instances of a type by writing one or more values in square brackets after the instance name.

Subscript definitions are written using the subscript keyword, and specify one or more input parameters and a return type, in the same way asinstance methods.
Here’s an example of a read-only subscript implementation, which defines a TimesTable structure to represent an n-times-table of integers:

struct TimesTable {
let multiplier: Int
 subscript(index: Int) -> Int {
   return multiplier * index
 }
}
let threeTimesTable = TimesTable(multiplier: 3)
print(threeTimesTable[5])
// prints "15"

Multiple subscripts can be defined for a single type. The appropriate subscript overload to use is selected according to the type of index value you pass to the subscript. Subscripts are not limited to a single dimension, and can be defined using multiple input parameters that best suit your custom type’s needs.

A Matrix is a good example how a subscript is used.
The following example defines a Matrix structure, which represents a two-dimensional matrix of Double values. The subscript takes two integer parameters:
struct Matrix {
 let rows: Int, columns: Int
 var grid: [Double]
 init(rows: Int, columns: Int) {
   self.rows = rows
   self.columns = columns
   grid = Array(count: rows * columns, repeatedValue: 0.0)
 }
 subscript(row: Int, column: Int) -> Double {
   get {
    return grid[(row * columns) + column]
   }
   set {
    grid[(row * columns) + column] = newValue
   }
 }
}

Matrix provides an initializer that takes two parameters called rows and columns to create an array large enough to store values of type Double. Each position in the matrix is given an initial value of 0.0.
Initialization is described in detail in the coming lessons.
You can construct a new Matrix instance by passing an appropriate row and column count to its initializer:

var matrix = Matrix(rows: 2, columns: 2)

This results in the following grid:


Values in the matrix can be set by passing comma-separated row and column values into the subscript.:
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2


This results in the following:

Overriding

You can prevent a method, property, or subscript override by marking it as final (such as final var, final func, final class func, and final subscript).
You can mark an entire class as final by placing the final modifier before the class keyword in its class definition (final class).

Initializers

In the case of structure types that have no defined custom initializers, Swift automatically provides a memberwise initializer, even if the structure types have stored properties that do not have default values.
The Size structure automatically receives an init(width:height:) memberwise initializer, which you can use to initialize a new Size instance:

struct Size {
   var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)

Class InitializationAll stored properties of a class – including any properties inherited from its superclassmust be assigned an initial value during initialization. In other words, assign a default value or create an initializer for the properties of the class.
The structure from the above example would have the following form as a class with an initializer:

class Size {
   var width:Double, height:Double
   init(w:Double, h:Double) {
     width = w
     height = h
   }
}
let twoByTwo = Size(w: 2.0, h: 2.0)

Required Initializers

Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer:

class SomeClass {
 required init() {
 // initializer implementation goes here
 }
}

You must also insert the required modifier before every subclass implementation of a required initializer. This indicates that the initializer requirement applies to further subclasses along the chain. Do not write the override modifier when overriding a required designated initializer:

class SomeSubclass: SomeClass {
 required init() {
 // subclass implementation goes here
 }
}

It’s not necessary to provide an explicit implementation of a required initializer if you can satisfy the requirement with an inherited initializer.

Deinitialization

A deinitializer is called immediately before a class instance is deallocated, and is useful when you work with your own resources.
For example, if you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated.
Class definitions can have at most one deinitializer per class.
Rather than providing you with the ability to call a deinitializer, Swift automatically calls it, just prior to instance deallocation. Superclass deinitializers are inherited by their subclasses, and the superclass deinitializer is called automatically at the end of a subclass deinitializer implementation. Superclass deinitializers are always called, even in cases in which subclasses do not provide their own deinitializers.

The deinit keyword is used to write a deinitializer, which is similar to writing an initializer using the init keyword. The deinitializer does not take any parameters and is written with no parentheses:

deinit {
 // perform the deinitialization
}

Deinitializers are only available on class types.

Some Additional Functionalities Of Swift – Part 3

Closures in Swift

Closures

A Closure is a self-contained block of functionality that can be passed around and used in your code.

Global and nested functions are actually special kinds of closures.

Nested functions offer a convenient way to name and define self-contained blocks of code within a larger function.
However, it is sometimes useful to have the option of writing shorter versions of function-like constructs that do not require full declarations and names. This is particularly true when working with functions that take other functions as one or more of their arguments.

Closure expressions present a way to write inline closures using brief, focused syntax. Closure expressions offer a number of syntax optimizations for use in writing closures in a shortened form, without losing clarity or intent.

Closure expression syntax takes the following general form:

{ (parameters) -> return type in
 statements
}

Closure expression syntax can use constant parameters, variable parameters, and inout parameters, but default values cannot be used. Variadic parameters can be used if you name them and make sure that it’s placed last in the parameter list.

The Sort Function

To understand how Closures are used, let’s take a look at a function called sort, which is available in Swift’s standard library. The sort function orders an array of values of a known type.

The sort method takes two arguments:
– An array of values of a known type.
– A closure that takes two arguments of the same type as the array’s contents, and returns a Bool value to say whether the first value should appear before or after the second value once the sorting is complete.

The example below shows the sorting of an array of String values. The sorting closure needs to be a function of type (String, String) -> Bool.
One way to provide the sorting closure is to write a normal function of the correct type, and to pass it in as the sort method‘s parameter:

func backwards(s1: String, s2: String) -> Bool {
   return s1 > s2
}
let names = ["Cc", "Aa", "Ee", "Bb", "Dd"]
var reversed = names.sort(backwards)

The example compares the Strings in the array names, based on the backwards function.
However, this is a long-winded way to write what is really a function that contains a single-expression (a > b).
In this situation, it would be preferable to write the sorting closure inline, using closure expression syntax:

let names = ["Cc", "Aa", "Ee", "Bb", "Dd"]
reversed = names.sort({ (s1: String, s2: String) -> Bool in
   return s1 > s2
})

For the inline closure expression, the parameters and return type are written within the curly braces, rather than outside of them.
The in keyword is used to introduce the beginning of the closure’s body, and indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin.

Inferring Type from Context

The sorting closure is passed as an argument to a function, making it possible for Swift to infer the types of its parameters and the type of the return value from the type of the sort method‘s second parameter. This parameter expects a function of type (String, String) -> Bool. This means that writing the (String, String) and Bool types as part of the closure expression’s definition is not necessary. Because all of the types can be inferred, the return arrow (->) and the parentheses around the names of the parameters can also be omitted:

reversed = names.sort( { s1, s2 in return s1 > s2 } )

The parameter types and return type can always be inferred when passing a closure to a function as an inline closure expression. As a result, it is unnecessary to write an inline closure in its fullest form when the closure is used as a function argument.
You still have the option of writing out the types. In fact, doing so is encouraged when you need to avoid ambiguity for others who might read your code.

Single-expression closures can implicitly return the result of their single expression, simply by omitting the return keyword from the declaration, as in this new version of the previous example:
reversed = names.sort( { s1, s2 in s1 > s2 } )

Here, the function type of the sort method‘s second argument makes it clear that a Bool value must be returned by the closure.
Because the closure’s body contains a single expression (s1 > s2) that returns a Bool value, there is no ambiguity, and the return keyword can be omitted.

Shorthand Argument Names

Swift automatically provides shorthand argument names for inline closures. These argument names can be used to refer to the values of the closure’s arguments, with the names $0, $1, $2, and so on.

If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, since the closure expression is entirely made up of its body:

reversed = names.sort( { $0 > $1 } )

Here, $0 and $1 refer to the closure’s first and second String arguments.

Operator Functions

There’s actually an even shorter way to write the closure expression above. Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a function that has two parameters of type String, and returns a value of type Bool. This exactly matches the function type needed for the sort method‘s second parameter. Just pass in the greater-than operator, and Swift will then infer that you want to use its string-specific implementation:

reversed = names.sort(>)
Closures in Swift

Some Additional Functionalities Of Swift – Part 2

Functions

In Swift, every function has a type that contains the function’s parameter types and return type. This type can be used like any other type in Swift, and this makes passing functions as parameters to other functions and returning functions from functions easier.
Functions can also be written within other functions to encapsulate useful functionality within a nested function scope.

Variadic Parameters

Variadic parameters indicate that the number of input values of a specified type passed to the parameter can vary. The variadic parameter can accept zero and/or more parameters of a certain type, and is indicated by adding three period characters (…) immediately following the parameter‘s type name.

The values passed to a variadic parameter appear as an array of the specified type in the function’s body.

In the example below, the function calculates the arithmetic mean, or average, for a list of numbers of any length:

func arithmeticMean(numbers: Double...) -> Double {
   var total: Double = 0
   for number in numbers {
     total += number
   }
   return (total / Double(numbers.count))
}

One variadic parameter is allowed per function. The variadic parameter must always be the last parameter in the list, to ensure clarity when calling the function with multiple parameters.
For a function with one or more parameters containing default values, as well as a variadic parameter, the variadic parameter is added at the very end of the list, following all defaulted parameters.

In-Out Parameters

A variable parameter is changeable only within the function. The in-out parameter is used as an alternative to the variable parameter in instances in which you want a change to continue after the function call ends.

The inout keyword is placed at the beginning of the parameter‘s definition. Its value is passed in to the function, where it is modified. It’s then passed back out of the function, where it replaces the original value.

This example swaps out two Integer values.

func swapInts(inout a: Int, inout b: Int) {
   let tempA = a
   a = b
   b = tempA
}

An in-out parameter cannot be assigned a default value. A variadic parameter cannot be marked as inout. A parameter that is marked as inout cannot also be marked as var or let.
An ampersand (&) that is inserted directly before a variable‘s name when it’s passed as an argument to an inout parameter, indicates that the variable can be modified by the function:

var someInt = 3
var anotherInt = 107
swapInts(&someInt, &anotherInt)

The in-out parameter presents an alternative method when a function is desired to have an effect outside of the scope of its function body.

Function Types

Every function has a specific function type that consists of the function’s parameter types and return type. Here’s an example:

func addInts(a: Int, b: Int) -> Int {
 return a + b
}
func multiplyInts(a: Int, b: Int) -> Int {
 return a * b
}

This example defines two simple mathematical functions called addInts and multiplyInts, which take two Int values, which return an Int value.
For both of these functions, the type is (Int, Int) -> Int. This can be interpreted as
“A function type that has two parameters, both of type Int; and that returns a value of type Int.”

Here’s another example. This one shows a function with no parameters or return value:

func printHelloWorld() {
   print("Hello, world")
}

The type of this function is () -> Void, which translates into “a function that has no parameters, and returns Void.”

Using Function Types

Function types are used in the same way as any other Swift types.
For example, define a constant or a variable to be of a function type. Then assign an appropriate function to that variable:

var mathFunction: (Int, Int) -> Int = addInts

You can now call the assigned function using its name, mathFunction.

print("Result: \(mathFunction(2, 3))")

A different function with the same type can be assigned to the same variable, in the same way as for non-function types.

Function Types as Parameter Types

A function type, such as (Int, Int) -> Int, can act as a parameter type for a different function, allowing for leaving some aspects of a function’s implementation for the function’s caller to provide calling the function.
The following example defines a function called printResult, which takes another function as its parameter and calls it as it’s implemented:

func printResult(mathFunc: (Int, Int) -> Int, a: Int, b: Int) {
   print("Result: \(mathFunc(a, b))")
}
printResult(addInts, 3, 5) 

It doesn’t matter what the called function’s implementation actually does – it matters only that the function is of the correct type.

Function Types as Return Types

A function type may be used as another function’s return type, by writing a complete function type immediately following the return arrow (->) in the returning function.

func plus(input: Int) -> Int {
   return input + 1
}
func minus(input: Int) -> Int {
   return input - 1
}
func chooseFunc(flag: Bool) -> (Int) -> Int {
   if(flag) {
     return plus
   }
   else {
     return minus
   }
}

In the above example, the chooseFunc function returns another function of type (Int) -> Int, based on the value of its flag parameter.

Nested Functions

You also have the option of defining functions inside the bodies of other functions. These are called nested functions.

By default, a nested function is hidden from the outside world. It can still be called and used by its enclosing function. An enclosing function can also return one of its nested functions, thus allowing the nested function to be used in another scope.

From the previous lesson, the function chooseFunc can be rewritten to use and return nested functions:

func chooseFunc(flag: Bool) -> (Int) -> Int {
   func plus(input: Int) -> Int { return input + 1 }
   func minus(input: Int) -> Int { return input - 1 }
   if(flag) {
     return plus
   }
   else {
     return minus
   }
}
Some Additional Functionalities Of Swift – Part 2

Sets & Set Operations

Sets

A set stores distinct values of the same type in a collection with no defined ordering. Sets are used as an alternative to arrays when item order is not a concern or when you need to ensure that an item appears only once.
For a Swift set, write the type as Set<T> where T is the type that the set is allowed to store. Unlike arrays, there is no equivalent shorthand for sets.
You can create an empty set of a certain type using initializer syntax:

var letters = Set<Character>()

Based on the initializer type, Swift infers the type of the letters to be Set<Character>.
An array literal will also work as shorthand when initializing a set with one or more values as a set collection.

var names: Set<String> = ["David", "Susan", "Robert"]

When initializing the type of set with an array literal that contains values of the same type, it is not necessary to write the type of set. The initialization could have been written in a shorter form:

var names: Set = ["David", "Susan", "Robert"]

Because all values in the array literal are of the same type, Swift infers that Set<String> is the correct type to use for the names variable.

Accessing and Modifying a Set

The count and isEmpty properties work the same way with a set as they do with an array.
Calling the set’s insert method adds a new item to a set.

names.insert("Paul")

You can remove an item from a set by calling the set’s remove method. The item is removed if it’s a member of the set, and the removed value is returned. It returns nil if the item is not contained in the set. Alternatively, use the set’s removeAll() method to remove all of the items in a set.

The contains method tells you whether or not a particular item is present in the set.

if names.contains("James") {
 print("James is here.")
} else {
 print("James is not with us.")
}

Iterating Over a Set

You can iterate over the values in a set with a for-in loop.

for name in names {
   print("\(name)")
}

Since Swift’s Set type does not provide defined ordering, use the sort() method to iterate over the values of a set in a specific order.

for name in names.sorted() {
   print("\(name)")
}

Set Operations

Swift allows you to efficiently perform fundamental set operations, such as combining sets, determining which values two sets have in common, or determining whether two sets contain all, some, or none of the same values.

Fundamental Set Operations

The illustration below depicts sets a and b, and shows the results of various set operations, as represented by the shaded regions:

The intersect method creates a new set, with only the values common to both sets.
The exclusiveOr method creates a new set with values in either set, but not both.
The union method creates a new set with all of the values in both sets.
The subtract method creates a new set with values not in the specified set.

For example, to combine the two sets: let oddDigits: Set = [1, 3, 5, 7, 9]

let evenDigits: Set = [0, 2, 4, 6, 8]
 
oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Set Membership and Equality

The illustration below depicts three sets: a, b, and c. The overlapping regions represent the elements that are shared among sets.
Set a is a superset of set b, because a contains all elements in b.
Conversely, set b is a subset of set a, because all elements in b are also contained by a.
Sets b and c are disjointed with one another, because they share no elements in common.
“is equal” operator (==): Determines whether two sets contain all of the same values.
isSubsetOf method: Determines whether all of the values of a set are contained in the specified set.
isSupersetOf method: Determines whether a set contains all of the values in a specified set.
isStrictSubsetOf or isStrictSupersetOf method: Determines whether a set is a subset or superset of, but not equal to, a specified set.
isDisjointWith method: determines whether two sets have any values in common.
Spend a little time playing with the methods to learn and understand their functions.


Sets & Set Operations