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:

Advertisements
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

Some Additional Functionalities Of Swift – Part 1

Variable/Constant Declare & Assignment

let a,b,c : String //Can also take var
a = "T" // T
b = "T" // T
c = "T" // T

let d = "T" // T
d = "E" // Cannot assign to value: 'd' is a 'let' constant

let e,f,g : String
e="T";f="T";g="T" // Use Of SemiColon In Swift
print(e) // T
print(f) // T
print(g) // T

 

Comparison Operators

let a : AnyObject = "T" as NSString //Refrence Type Object
let b = a // Refrence Passed
let c = a // Refrence Passed

print(b === a) // True - Pointing Same Refrence
print(c !== a) // False - Pointing Same Refrence

 

Conditional Statements

let myPoint = (1, -1)
switch myPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}

The three switch cases declare placeholder constants x and y, which temporarily take on the two values from myPoint, creating a dynamic filter as part of a where clause. The switch case matches the current value of point only if the where clause’s condition evaluates to true for that value.

The final case matches all possible remaining values; a default case is not necessary to have an exhaustive switch statement.

Repeat-While

// Swift's repeat-while loop is similar to a do-while loop in other languages.
repeat {
x -= 1
} while x>0

Fallthrough

In Swift, switch statements do not fall through the bottom of each case into the next. Instead, the entire switch statement completes its execution when the first matching case is completed.
By contrast, C requires insertion of an explicit break statement at the end of every switch case to prevent fallthrough. By eliminating default fallthrough, Swift allows for more concise and predictable switch statements in comparison with C, and thus avoids inadvertently executing multiple switch cases.

In cases that require C-style fallthrough behavior, use the fallthrough keyword on a case-by-case basis. The example below uses fallthrough to create a number’s textual description.

let myInt = 5
var desc = "The number \(myInt) is"
switch myInt {
case 2, 3, 5, 7, 11, 13, 17, 19:
desc += " a prime number, and also"
 fallthrough
case 4:
desc += " add this without mathch and"
default:
desc += " an integer."
}
print(desc)

This prints “The number 5 is a prime number, and also add this without mathch and an integer.”

If myInt‘s value is one of the prime numbers in the list, text noting that the number is prime is appended to the end of the description. The fallthrough keyword then causes it to “fall into” the default case.
The fallthrough keyword does not check case conditions in the switch case into which execution falls. As with C’s standard switch statement behavior, the fallthrough keyword moves code execution directly to the statements inside the next (or default) case block.

Modifying an Array

Add an array of one or more compatible items using the addition assignment operator (+=):

 

shoppingList += ["Juice"]
shoppingList += ["Chocolate", "Cheese"]

 

Subscript syntax also changes a range of values all at once. This will even work with a replacement set of values with a length that is different from the original range.
In the following example, the elements with index 4, 5, 6 are replaced with two new values.

shoppingList[4...6] = ["Bananas", "Oranges"]

Don’t use subscript syntax to append a new item to an array.

Use the enumerate() method to iterate over an array when you need the integer index for each item in addition to its value. This returns a tuple for each item in the array that indicates that item’s index and value. You can decompose the tuple into temporary constants or variables as part of the iteration:

for (index, value) in shoppingList.enumerate() {
    print("Item \(index + 1): \(value)")
}

This will print the index and the value of the elements in the array.

Some Additional Functionalities Of Swift – Part 1