Refactoring

One of the core elements of clean code is having code that is consistent with identifiers. Head to the AppDelegate. Take a look at this code from the tip from last week.

I have a few problems with it. I’m not being very consistent in some of those identifiers such as the HueColorTVC and ColorTableViewController. However, these identifiers are all over my code. There’s a great way to get consistency using refactoring. 

Select the HueColorTVC, then right click.

Click refactor… and then rename.

Xcode shows you all occurrences of this identifier, which in this case is only in the app delegate.

Change to hueColorTableViewController. All the occurrences change at once. 

Select and then right-click the ColorTableViewController, and once again hit refactor.

Both cases of the class identifier, when it is instantiated in teh App delegate and the definition in HueColorTVC.swift are highlighted. Change to HueColorTableViewController

Let’s do this one more time. I’m going to change the navigationVC

to masterNavigationVC

Now I’d like my file name to match too. One way to change it is in attributes. Select HueColorTVC.swift.

Open the attributes panel. Change the name to HueColorTableViewController.swift

and the file name changes.


One caution about all this renaming. Comments don’t refactor easily. You’ll see that at the top of the code.  Select and refactor that. You can’t. Once you refactor, you might want to also search to find anything you didn’t get in your refactoring. You can replace all these cases by selecting replace, and adding the replacement in the text box. 

Refactoring is a very useful and simple tool to get your code a lot more consistent in identifiers. 

Understand ARC

One of those difficult things for even experienced developers to understand is Automatic Reference Counting, or ARC. It is how Swift manages and conserves memory automatically. 

Take a look at the Exercise file. I have a playground in this project with two classes. One is a pizza topping.

class PizzaTopping{
    let name:String
    var onPizza: Pizza!
    init(name:String){ self.name = name }
    deinit { print("Deinitializing \(name)") }
}

One is a Pizza.

class Pizza{
    let name:String
    var topping:PizzaTopping!
    init(name:String){ self.name = name }
    deinit{ print("Deinitializing \(name)") }
}

Look at the PizzaTopping class. It has two methods defined, an init to initialize name, and deinint. deinit is a method that executes just before the class is deallocated, and we’ll use it  to see things disappear. 

On the bottom, you’ll see I made a few toppings and pizzas in a do block. I use a do block here to simulate what would happen inside a class or function for a playground without using one. I’ll explain why I did that shortly.

do{
    // Initialize toppings
    let pepperoni:PizzaTopping = PizzaTopping(name: "Pepperoni")
    let mushroom:PizzaTopping = PizzaTopping(name:"Mushroom")
    
    // Initialize pizzas
    let pepperoniPizza:Pizza = Pizza(name: "Pepperoni Pizza")
    let mushroomPizza:Pizza = Pizza(name:"Mushroom Pizza")
    
    // Add toppings to pizzas
    mushroomPizza.topping = mushroom
    pepperoniPizza.topping = pepperoni
}

If you run now, you’ll see in the console the chain of deinitializing.

Deinitializing Mushroom Pizza
Deinitializing Pepperoni Pizza
Deinitializing Mushroom
Deinitializing Pepperoni

The Pizzas and then the toppings deinitialize. This is ARC in action. Each assignment is a reference to an area in memory. ARC counts the number of references. Where there are no more references, ARC assumes that the memory is unused and frees it up. We’ve got cases here where there is one reference. For example, pepperoniPizza has one reference. At the end of the do block, that value is discarded and I have zero references. When ARC finds zero references, it cleans out that memory, deallocating the space, and deinit fires.

One place that changes is global variables. I used do to keep all those variables as local. The default behavior in Playgrounds is a global variable. Let’s add a global above of the do code. 

var myPizza:Pizza! = Pizza(name: "Goat Cheese")

Run again.

Deinitializing Mushroom Pizza
Deinitializing Pepperoni Pizza
Deinitializing Mushroom
Deinitializing Pepperoni

Goat Cheese doesn’t show as deallocated. Globals are not deallocated until the app is removed from memory. 

Assign the mushroom pizza to my pizza. 

myPizza = (mushroomPizza)!

Run again.

Deinitializing Goat Cheese
Deinitializing Pepperoni Pizza
Deinitializing Pepperoni

The Goat Cheese pizza deinitializes, the mushroom doesn’t, and the mushroom topping doesn’t.  We changed the reference. Let’s go down the steps here carefully:

  1. We have a Global pizza Goat Cheese in myPizza
  2. We assign the mushroomPizza to myPizza. It has a topping of mushroom. The Goat Cheese instance has zero references and deallocates.
  3. The do block ends. PepperoniPizza and pepperoni have zero references. ARC deallocates these.
  4. The global only closes when we close the playground, so there is a lifetime reference to myPizza. mushroomPizza and the value in its property topping of mushroom are assigned there, so they do not deallocate.

ARC can be fooled into not deallocating memory through a strong reference cycle. lets suppose I track what pizza has a topping in the Topping class with the property onPizza, for example add 

pepperoni.onPizza = pepperoniPizza

Run again

Deinitializing Goat Cheese

,Pepperoni doesn’t deinitialize. It has two strong references, the Pizza in onPizzarecording the pizza it is on and the pepperoni topping in PepperonipPizza. The topping can’t deallocate until the pizza does and the pizza can’t deallocate until the topping does. When you have a lot of instances of this happening you’ll have an expansion of wasted memory known as a memory leak.  

You can break this reference cycle by changing one of the two properties to weak. I’ll change onPizza in this case,  

weak var onPizza:Pizza!

For a weak variable, Arc changes its value to nil when it tries to clean up at the end of the block and then cleans it up. That’s why `onPizza` is optional in this code.

The strong reference cycle is broken,  and it deallocates the memory of the weak variable.   Run now and the pepperoni deallocates. 

Deinitializing Goat Cheese
Deinitializing Pepperoni Pizza
Deinitializing Pepperoni

Of course, the best way to avoid this is to use searches of pizzas for their toppings rather than onPizza.  ARC does much of the work to keep memory clean, but in large codebases, it is too easy to create a memory leak by a strong reference cycle.  Knowing how to avoid them and how to use weak when you can’t are important skills. 

The Whole Code

Here’s the playground code for this week’s tip. You’ll also find it on GitHub here

//
//  An exercise file for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//

import UIKit

class PizzaTopping{
    let name:String
    weak var onPizza: Pizza!
    init(name:String){ self.name = name }
    deinit { print("Deinitializing \(name)") }
}

class Pizza{
    let name:String
    var topping:PizzaTopping!
    init(name:String){ self.name = name }
    deinit{ print("Deinitializing \(name)") }
}


var myPizza:Pizza = Pizza(name: "Goat Cheese")
do{
    // Initialize toppings
    let pepperoni:PizzaTopping = PizzaTopping(name: "Pepperoni")
    let mushroom:PizzaTopping = PizzaTopping(name:"Mushroom")
    
    // Initialize pizzas
    let pepperoniPizza:Pizza = Pizza(name: "Pepperoni Pizza")
    let mushroomPizza:Pizza = Pizza(name:"Mushroom Pizza")
    
    // Add toppings to pizzas
    mushroomPizza.topping = mushroom
    pepperoniPizza.topping = pepperoni
    myPizza = mushroomPizza
    pepperoni.onPizza = pepperoniPizza
}

Understand Closures

You’ll find closures throughout the API’s, but you may not know how to use them properly. Let’s take a basic tour of closures. 

Download the exercise file, and you’ll find a project with a playground. In the playground you’ll find a function  to compute a pizza volume.

func roundPizzaVolume(height:Double, diameter:Double) -> Double{
    let pi = Double.pi
    let z = diameter / 2.0
    let a = height
    let v = pi * z * z * a //My favorite pun.
    return v
}
roundPizzaVolume(height: 2, diameter: 10) 

That’s for a round pan pizza, for a rectangle it won’t work. 

But if I make a function that has a formula for the area, then I can do any area. In the anyPizzaVolume, I’ll put one at the end of the argument list. 

anyPizzaVolume(height:Double, length:Double, width:Double, area:(Double,Double)->Double)-> Double{

That declares a closure, which is not much more than a function that you pass as a parameter.

In my code I’ll multiply height by area, then return the volume.  

func anyPizzaVolume(height:Double, length:Double, width:Double, area:(Double,Double)->Double)-> Double{
    let volume = height * area(length,width)
    return volume
}

I’ll call anyPizzaVolume.In the autocomplete for anyPizzaVolume, you’ll see the closure.

anyPizzaVolume(height: , length: , width: , area:  Double>)

  Add a height of 2, a length of 10 and a width of 10. Hit tab when you get to area, and you’ll get a stubbed closure. I usually use this, but I’m going to do it manually so you get the idea. You stick the closure as the last parameter, so you can put the closure outside the function. Otherwise you need to put it inside, and that can get confusing to read. 

anyPizzaVolume(height: 2, length: 10, width: 10) {
    
}

You start a closure identifying the declared variables, then add the keyword in 

anyPizzaVolume(height: 2, length: 10, width: 10) {
    (l,w) in
}

Now you write code based on those two values. 

anyPizzaVolume(height: 2, length: 10, width: 10) {
    (l,w) in
    let r = l / 2.0
    return r * r * Double.pi
}

Run this and you get the answer you got before.  I can copy this, paste it, and change the code to a rectangle area. 

anyPizzaVolume(height: 2, length: 10, width: 10) {
    (l,w) in
    return l * w
}

Run again, and you get a different answer. There are better ways of doing this method, but I wanted to illustrate the basic use of closures. Where they get used is Asynchronous processing. That’s when you don’t control when the code will execute like completion handlers, timers,  and actions. For example, in the roundPizzaVolume I could add a completion handler that handles errors. 

completionHandler:(Bool,Double)-> Void

For this closure, I’m not returning anything to the function. Closures require a return type, so I useVoid to indicate there is noting returned. I’ll add the completionHandler`function to to the code

completionHandler(v>0,v)

The bool indicates if the area is a meaningful answer, and I pass the volume to the closure. Now I can change the roundPizzaVolume code to use the closure by adding this: 

roundPizzaVolume(height: -2, diameter: 10){
    (success,volume) in
    if !success{
        print("Invalid Volume \(volume)")
    }
}

Change the height to -2 and Run. Many closures, especially file handling, will do this and give you a success bool which you can then handle after it does it function.

Take a look at the ViewController.  You’ll find examples of  API’s using closures.   Action handlers are often closures. For example I have an alert in this code. UIAlertActions use closures to respond to the selection of the action.

let actionOne = UIAlertAction(title: “First Action”, style: .default) { (action) in
self.alertStatus.text = “First Action”
}

 Notice that as asynchronous blocks, you need self to use properties and methods of the class.  Also you can make closures optional, so if you do not want to use them, they can be set to nil, as in this action.

 let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

There’s a lot you can do with closures. As you can see here, you will find them in code frequently.  

The Whole Code

You’ll find the completed code on Github here. Below you’l find the playground and view controller for this project.

import UIKit
//
//  An exercise file for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//


func roundPizzaVolume(height:Double, diameter:Double, completionHandler:(Bool,Double)->Void) -> Double{
    let pi = Double.pi
    let z = diameter / 2.0
    let a = height
    let v = pi * z * z * a //My favorite pun.
    completionHandler(v>0,v)
    return v
}
roundPizzaVolume(height: -2, diameter: 10){
    (success,volume) in
    if !success{
        print("Invalid Volume \(volume)")
    }
}

func anyPizzaVolume(height:Double, length:Double, width:Double, area:(Double,Double)->Double)-> Double{
    let volume = height * area(length,width)
    return volume
}

anyPizzaVolume(height: 2, length: 10, width: 10) {
    (l,w) in
    let r = l / 2.0
    return r * r * Double.pi
}

anyPizzaVolume(height: 2, length: 10, width: 10) {
    (l,w) in
    return l * w
}

//
//  ViewController.swift
//  ClosureExercise
//
//  An exercise file for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var presentStatus: UILabel!
    @IBOutlet weak var alertStatus: UILabel!
    @IBOutlet weak var alertButton: UIButton!
    @IBAction func alertButton(_ sender: UIButton) {
        let alert = UIAlertController(title: "Demo Alert", message: "Some Closure examples", preferredStyle: .alert)
        //Actions for methods like alerts often use closures to do the action
        let actionOne = UIAlertAction(title: "First Action", style: .default) { (action) in
             //This is on a seperate thread so use self to access the elclosing class' methods and properties.
            self.alertStatus.text = "First Action"
            //this is on a seperate thread so use self to access the elclosing class' methods and properties.
        }
        let actionTwo = UIAlertAction(title: "Second Action", style: .default) { (action) in
            //This is on a separate thread so use self to access the enclosing class' methods and properties.
            self.alertStatus.text = "Second Action"
        }
        // Closures can be optional, and then you can set the value to nil if you don't plan to use it. Make sure you handle the nil in the method though.
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
        
        
        alert.addAction(actionOne)
        alert.addAction(actionTwo)
        alert.addAction(cancelAction)
        
        // The present function has a closure we usually leave nil, but if you have clean up​ after you launch the method, this is where you do it. Here I print a status message.
        present(alert, animated: true) {
            self.presentStatus.text = "Presented Alert"
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        alertButton.layer.cornerRadius = 20
        // Do any additional setup after loading the view, typically from a nib.
    }


}

Ducking Sound in AVAudioSession

title shot

Ducking has nothing to do with waterfowl. Sometimes you’ll want to add sound to your app, but the user will be using the music or others app along with your app.  For that, you’ll want to slightly lower the volume of the background music so you can put your sounds in the foreground. That;’s ducking, and Its not very hard to do.  

 Download the exercise file which is Speech synthesizer app from an earlier tip.  I’m running this on my iPad mini , but before I do, I’ll start a bit of music.  Now run the app.  Tap the button on the app, and the music disappears. Stop the app. 

There’s a class called AVAudioSession which controls the audio output. While part of AVFoundation, it has a default setting without AVFoundation which plays only one channel of sound. To combine channels, you have to configure the current AVAudioSession to do so. Usually, you’ll do this once in the AppDelegate. Head over there and add AVFoundation

import AVFoundation

In didFinishLaunchingWithOptions, make an identifier for AVAudioSession’s singleton sharedInstance.

let session = AVAudioSession.sharedInstance()

AVAudioSession has a category property. You set the property with a setCategory method, which throws errors, So set up a do…try…catch

do{
    try
} catch {
    print ("Unable to set audio category")
}

After the try, add the setCategory method. For the category, use a AVAudioSession.Category.playback

try session.setCategory(AVAudioSession.Category.playback 

The second parameter is mode. I’ll set this to default.

try session.setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, 

The with is an array of options. I’ll add two options. The first is a bit redundant, but doesn’t hurt to add. mixWiithOthers assures that the foreground and background channels mix. Alone you’ll have them at the same volume.  The second one duckOthers,  softens the background sound` a bit.

try session.setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, options: [.mixWithOthers,.duckOthers])

Our last step is to activate the session directly under the setCategory. Setting the category supposedly activates it, but in some circumstances, it won’t. If you need it, it’s here, but I’ll comment it out this time.

//try session.setActive(true, options: [])

        Build and run the project.  I’ll start the music again, and then I’ll start the speech synthesizer. The music ducks under the speech synthesizer.

You can use this in a lot of places where you want your sound effects and you’re user might want their own music or media. 

The Whole Code

Here’s the code in the app delegate for ducking. See the GitHub download for the ducking and speech synthesizer.

//
//  AppDelegate.swift
//  SpeechSynthesizer
//
//  An exercise file for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//

import UIKit
import AVFoundation
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        let session = AVAudioSession.sharedInstance()
        do {
            try session.setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, options: [.mixWithOthers,.duckOthers])
            //try session.setActive(true, options: [])
        } catch {
            print ("Unable to set audio category")
        }
        return true
    }
}

Actions in Table Views

Sometimes table views could use a few buttons. There’s two delegates which create swipe buttons on table view cells. Let’s learn how you can implement these buttons and an interesting hidden feature you can do with them. 

There is two delegate methods, one for the leading swipe configuration and one for the trailing Swipe configuration. They work identically, so I’ll start with the trailing one. 

In the TableViewController.swift code, under the titleForHeaderInsection delegate method,  add the following which you can find in the auto complete: 

override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
}

}

This method returns  a UISwipeActionsConfiguration, and I’ll add the returned object to my code: 

return UISwipeActionsConfiguration(actions: [greenAction,blueAction])

You’ll see the initializer takes an array of actions of type UIContextualAction. That’s the core of this method.  It sets the title on the cell for your action and handles the code when tapped. I’ll add an action called greenAction

let greenAction = UIContextualAction(style: .normal, title: "Green") { (action, view, actionPerformed) in
         
        }

You’ve got normal and destructive styles for the buttons since you can place code to delete the cell here. I’m just going to leave it .normal then set the title to Green and then add the handler.  

The handler has three parameters: the action itself if you want to change the action, the view in which the action is displayed, and a bool indicating if the action was performed or not.

I made a method for use within the action to change the cell:

//A simple example of what you can do in the cell
    func setCell(color:UIColor, at indexPath: IndexPath){
        
        // I can change external things
        self.view.backgroundColor = color
        // Or more likely change something related to this cell specifically.
        let cell = tableView.cellForRow(at: indexPath )
        cell?.backgroundColor = color
    }

Inside the closure for the action,  I’ll add the setCell method to change the background and cell color. 

let greenAction = UIContextualAction(style: .normal, title: "Green") { (action, view, actionPerformed) in
            self.setCell(color: .green, at: indexPath)
        }

I can change properties of the action as well, including its title and background color. I’ll change the background color to green. 

greenAction.backgroundColor = .green

I’ll copy then paste all this. to make another button, changing all the greens to blues. 

 let blueAction = UIContextualAction(style: .normal, title: "Blue") { (action, view, actionPerformed) in
            self.setCell(color: .blue, at: indexPath)
        }
        blueAction.backgroundColor = .blue

I can take both these actions and place them in the actions array of UISwipeActionsConfiguration

return UISwipeActionsConfiguration(actions: [greenAction,blueAction])

Since the leading version is identical to the trailing version, I’ll copy all of this then  paste it below the first. Change trailing to leading.

override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let greenAction = UIContextualAction(style: .normal, title: "Green") { (action, view, actionPerformed) in
            self.setCell(color: .green, at: indexPath)
        }
        greenAction.backgroundColor = .green
        
        let blueAction = UIContextualAction(style: .normal, title: "Blue") { (action, view, actionPerformed) in
            self.setCell(color: .blue, at: indexPath)
        }
        blueAction.backgroundColor = .blue
        
        return UISwipeActionsConfiguration(actions: [greenAction,blueAction])
    }

Build and run using an iPhone XR simulator. If you swipe a cell slowly about 1/4 to 1/2 across right to left, you’ll get the blue and the green trailing button. 

If you swipe gently on another row left to right, you get the green and blue button. 

The first button is the one closest to the leading or trailing edge. Click the green button and the background turns green,  tap the blue button and the background turns blue. 

Now swipe from right to left across the entire button.

The background goes green. The first action of the UISwipeActionsConfiguration will fire on a big swipe. So If I want blue on the leading swipe and green on the trailing ‘Ill change my leading array to have the blue as th first element of the array: 

return UISwipeActionsConfiguration(actions: [blueAction,greenAction])

Run again, and you get the long swipe of blue from the leading and green from the trailing.

This is a powerful, simple,  and useful way to get actions into individual table view cells.  

The Whole Code

Here’s the code for this lesson. You can also download it from Github Here.

//
//  TableViewController.swift
//  SwipeActions
//
//  An exercise file for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//

import UIKit

class TableViewController: UITableViewController {

    let rowCount = 12
    
    override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let greenAction = UIContextualAction(style: .normal, title: "Green") { (action, view, actionPerformed) in
            self.setCell(color: .green, at: indexPath)
        }
        greenAction.backgroundColor = .green
        
        let blueAction = UIContextualAction(style: .normal, title: "Blue") { (action, view, actionPerformed) in
            self.setCell(color: .blue, at: indexPath)
        }
        blueAction.backgroundColor = .blue
        
        return UISwipeActionsConfiguration(actions: [greenAction,blueAction])
    }
    
    override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let greenAction = UIContextualAction(style: .normal, title: "Green") { (action, view, actionPerformed) in
            self.setCell(color: .green, at: indexPath)
        }
        greenAction.backgroundColor = .green
        
        let blueAction = UIContextualAction(style: .normal, title: "Blue") { (action, view, actionPerformed) in
            self.setCell(color: .blue, at: indexPath)
        }
        blueAction.backgroundColor = .blue
        
        return UISwipeActionsConfiguration(actions: [blueAction,greenAction])
    }
    
    //A simple example of what you can do in the cell
    func setCell(color:UIColor, at indexPath: IndexPath){
        
        // I can change external things
        self.view.backgroundColor = color
        // Or more likely change something related to this cell specifically.
        let cell = tableView.cellForRow(at: indexPath )
        cell?.backgroundColor = color
    }
    
    
    //Your standard Table Delegate and Data Source methods
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return rowCount
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = String(format:"Row #%i",indexPath.row + 1)
        cell.textLabel?.font = UIFont(name: "GillSans-Bold", size: 26)
        return cell
    }
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "Sample Action Table"
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
}


Thrown Errors

There’s many ways to handle errors in Swift. For some errors, using throws is a great way to handle errors without crashing the system.

Download the exercise file. You’ll find a project with an embedded playground. 

let coffees = ["Sumatra","Colombia","Dark Energy","Sarabanda Dark","Kona"]
let ratings = [2,2,-1,5]

func coffee(_ name:String) -> String{
    let index = coffees.firstIndex{ (coffee) -> Bool in
        coffee == name
    }
    let ratingIndex  = index!
    let rating = ratings[ratingIndex]
    return String(repeating:"☕️", count: rating)
}

var myCoffee = "Colombia"
print(myCoffee + ":" + coffee(myCoffee))

While there’s a lot better ways to do this, I’ll use an example of a function coffee(name:) that finds the rating of a type of coffee using the two arrays coffees and ratings. You’ll notice there’s a nil error and some index out of range errors possible here in the rating and the search. 

I can run for Sumatra as it is set for and it gives me a two cup rating. Try Kona and it crashes since I have four instead of five ratings, so I have an array out fo bounds error. It also crashes on Java, whihc is not one of my coffees, so index is nil and can’t be force unwrapped.

For internal fatal errors of a function, we can use throws. To use throws, add it to the function name before the return type

func coffee(_ name:String) throws -> String{

You’ll need to identify the error when you throw it. You use an enum that adopts the Error protocol to do that. I’ll add three errors 

enum CoffeeError: Error{


I’ll add three errors. The first case will be a coffee not found

case coffeeNotFound

For the second, I can add an argument, which I can later use to give more information about the error in my code

case ratingNotFound(coffee:String)

    The last will be for an invalid rating, since I will only use ratings between one and five cups.

case badRating
}

Going back to my code, I’ll throw those errors in my method. The first error is an nil index, which I will use a guard for.Inside the guard’s else statement I’ll throw the error and send the enumeration’s value, in this case coffee not found. 

//let ratingIndex  = index!
guard let ratingIndex = index else{
    throw CoffeeError.coffeeNotFound
}

For my other two errors, where the rating index is out of range, I’ll use an if statement and throw the appropriate error. For the rating not found, I’ll.include in the parameter the name of the coffee

if ratingIndex >= ratings.count{
   throw CoffeeError.ratingNotFound(coffee: name)
}

If my rating is a nagative one, I’ll throw an error

if rating < 0 {
     throw CoffeeError.badRating
 }

If you make your own thrown errors, that’s how you would set them up. This is great way to detect errors you’ll get from situation beyond your control.

More likely, you will be handling the error. You might set up your own, but there are a lot of factory methods that throw errors. The standard way of handling thrown errors is the do…try…catch construct. It starts with  a do and a code block

do{
print(myCoffee + ":" + coffee(myCoffee))
}

Inside the code block, you try the thrown method, usually before the method. In a print method, it goes outside the print.

do{
    try print(myCoffee + ":" + coffee(myCoffee))
}

   

Add catch to handle any error.  In its simplest form, you can do this to catch and handle all errors. 

do{
    try print(myCoffee + ":" + coffee(myCoffee))
} catch {
    print("Error")
}

The real power of do…try…catch however is in specifying the error form your specified errors, so you can handle it properly.  I’ll set up a specific error handler for a coffee not found. I’ll place this above the gnereal catch. You can think of catch a lot like switch, where the catch without any errors is the default, and should go last.

catch CoffeeError.coffeeNotFound{
    print("Coffee not found")
}

The ratingNotFound error had a parameter, I can set the error parameter with a let in the parameter to silence a warning from string interpolation.

catch CoffeeError.ratingNotFound(let coffee){
    print ("Coffee \(coffee) does not have a rating" )
}

Try a few different cases of errors.  Set the coffee to Dark Energy, run, and you get a simple error from the -1 rating

Change the name to Dark Matter, which isn’t one of our coffees

Try Kona for the out of bounds error:

If yo dont need to hadle errors differently, an alternative is making the error a nil value using try?  and use an if Let construct. 

if let coffeeRating = try? coffee(myCoffee){
    print (myCoffee + " " + coffeeRating )
} else {
    print("Error on coffee")
}

There’s one other option: Disable the error thrown with try!. Use this only if you know this will work, such as 

myCoffee = "Sumatra"
try! print(myCoffee + ":" + coffee(myCoffee))

The best way to handle an error is not to make one. However, when creating methods and classes, you will find places that there are errors you can’t control. Throwing errors will notify any other classes and methods that there is trouble.

The Whole Code

You can find the completed project below, You can also download it from GitHub.

//
//  A Demo for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//
import UIKit

let coffees = ["Sumatra","Colombia","Dark Energy","Sarabanda Dark","Kona"]
let ratings = [2,2,-1,5]

enum CoffeeError: Error{
    case coffeeNotFound
    case ratingNotFound(coffee:String)
    case badRating
}

func coffee(_ name:String) throws -> String{
    let index = coffees.firstIndex{ (coffee) -> Bool in
        coffee == name
    }
    //let ratingIndex  = index!
    guard let ratingIndex = index else{
        throw CoffeeError.coffeeNotFound
    }
    if ratingIndex >= ratings.count{
        throw CoffeeError.ratingNotFound(coffee: name)
    }
    let rating = ratings[ratingIndex]
    if rating < 0 {
        throw CoffeeError.badRating
    }
    return String(repeating:"☕️", count: rating)
}

var myCoffee = "Sumatra"
do{
    try print(myCoffee + ":" + coffee(myCoffee))
} catch CoffeeError.coffeeNotFound{
    print("Coffee not found")
} catch CoffeeError.ratingNotFound(let coffee){
    print ("Coffee \(coffee) does not have a rating" )
} catch {
    print("Error")
}


if let coffeeRating = try? coffee(myCoffee){
    print (myCoffee + " " + coffeeRating )
} else {
    print("Error on coffee")
}

myCoffee = "Sumatra"
try! print(myCoffee + ":" + coffee(myCoffee))

Swift Strings Are Not C Strings or NSStrings

In many popular programming languages strings are little more than an array of characters, often referred to as C strings since C was one of the first languages to take this approach to strings. As we learned in the last post, with Swift’s use of Unicode characters in extentended grapheme clusters, this gets messed up, and you have a bit more work when working in Swift with the String and NSString Types.

Download the exercise file, and you’ll find a copy of the completed exercise file from the Unicode character tip. Run the app on an iPhone Simulator.

The app is supposed to count the characters in the string. It accurately counts 9 characters, but to do so it counts extended grapheme clusters, so the arrows don’t count in the character count. This makes sense if you are counting full characters, but it runs into a few problems.

Converting between String and NSString is one of those problems. I’ll Add an NSString above the label assignment:

let nsYummy = NSString(string: yummy)


NSString does not have a count but a length, I’ll add that to the label text with a new line to make it easier to read.

print (String(format:"\n %i %i",yummy.count,nsYummy.length))

Run this. The NSString‘s length reads all the Unicode characters separately, we get 12 instead of 9.

I’d expect 11, since I add the two arrows to the number of characters. I’ll come back to where that missing character is.

Neither of these are arrays of Character. You can’t do this:

let yummyChar = yummy[4]

Or this:

let nsYummyChar = nsYummy[4]

You’ll get an error.

That’s to keep track of all those clusters. NSString has a method character:at: which gives you the character as a 16-bit integer. I’ll chnge the assignment to

let nsYummyChar = nsYummy.character(at: 4)

Since I’ve been working in hex I’ll print to the console our label and the character

print(String(format:"%X %C",nsYummyChar, nsYummyChar))

Comment out yummy for now, Run and we get 67, which is the g.

For String, I have to use a relative index from the beginning or end of a string. There’s an internal type to String called String.Index that I can use with a subscript. It has a few properties that are useful. For the index of the first characte r there is the property startIndex. For the last index, endIndex. Remove the comment and change the subscript to

let yummyChar = yummy[yummy.startIndex]

That will get me the first character. For the fourth character, I can use the method index:offsetBy: I’ll just print that character to the console.

let yummyChar = yummy[yummy.index(yummy.startIndex,offsetBy:4)]
print(yummyChar)

Run this. In the console,

We get the h with the arrow because this is an offset from the index. It is the number of characters away from the starting character D. I subtract 1 to get 3 to get the fourth character.

let yummyChar = yummy[yummy.index(yummy.startIndex,offsetBy:3)]
print(yummyChar)

Iterations through characters are different too. For an NSString, you’ll have to iterate through an index and use character: At:

 
for index in 0..<nsYummy.length{
     let nsYummyChar = nsYummy.character(at: index)
    print(String(format:"%C",nsYummyChar) }
 

Swift Strings are sequenceable, so you can use for directly on the string. char here is of type character, and for comparison, I cast it to string for printing.

for char in yummy{
    print(String(char))
}

Run this. In the console you’ll find the results. First there is the NSString iteration, which iterates over all the characters, splitting up the grapheme clusters, and converting the doughnut emoji to question marks.

Then the Swift string returns grapheme clusters, with the doughnut intact.

If you noticed earlier, there were 12 characters in the NSString while ,String had 9. We expected that the arrows were another character for a total of 11. But looking at the console we can see that the emoji, here represented by those two question marks, is two characters. On the other hand, the char just prints 9 grapheme clusters for the Swift String and Character.

When working with strings, and especially when converting between String and NSString, be careful. Due to Unicode clusters, they might not be as simple as they look.

Some Common Functions for String

For most, that’s great theory, but how does it apply to strings, not characters? If you’re familiar with many languages that use strings as c-strings or character arrays, you’re familiar with a few simple string manipulation functions. In BASIC I knew them as right$, left$, and mid$. I’ve created a simple extension to String that will let you use three more common String functions to better understand strings.

First make the extension

extension String{

}

Since index is odd about numbering. I like keeping consistent with arrays, so I’ll write a function to return a valid position. This makes sure we are in range. I also set overflows to startIndex and endIndex. I did this for speed in coding the rest of this. This would be better returning Int! and checking for nil.

private func pos(position:Int)->Int{
    var pos = position
    if pos > 0 {pos -= 1} else {pos = 0}
    if pos >= count {pos = count - 1}
    return pos
}

I’ll need the position of the character I’m interested in. I made another function for that, using the offsetBy we already used. Since this is an extension of String, I use self for the object.

private func index(_ position:Int)->String.Index{
    return self.index(startIndex, offsetBy: pos(position:position))
}

All the characters to the left of the position I make an open range based on position to get a left string function.

func leftString(from position:Int)-> String{
     return  self[...index(position)]
}

In the extension, I use self to refer to my string. I get a substring on self by using a range for the subscripts on indices.

You’ll notice we get a weird error.

Substrings are not strings. Cast it to a string and the error disappears. .

return String(self[...index(position)])

For midString, a string starting at one character position and going for a length, I use a closed range of a start and end position. I calculate the end by adding the length, but still have to take 1 off.

func midString(from position:Int, length:Int)-> String{
    let endPosition = position + length - 1
    return String(self[index(position)...index(endPosition)])
}

Getting the rightmost characters is a little bit more difficult. rightIndex has to be from the trailing side. So I’ll find the position by subtracting position from endIndex

func rightString(from position:Int)-> String{
    let rightIndex = self.index(endIndex, offsetBy: -pos(position:position + 1))

}

Now to test all this, I’ll add print statements to viewDidLoad in the class I’ve been working in.

print(yummy)
print(yummy.leftString(from: 3))
print(yummy.midString(from: 3, length: 3))
print(yummy.rightString(from: 3))

Run this and you get in the console:

I printed the full string first for comparison. The third from the left character is u. For the leftString, I print the first, second and third characters. For midString I print the third character and the next two characters for a total of three characters. The u happens to be the third from the right character too, so the rightString prints from the second u to the beginning of the string.

You can tweak this to your preferences. I just wanted to show you how to manipulate the string using indices. These three functions I added in the extension are not in Swift because there are a lot more powerful things you can do with Swift strings. I’ll be covering those in upcoming tips.

The Whole Code

You’ll find the code below for cut and paste. You can also find it on GitHub here, but in a slightly differnt format. The extension is in a playground file.

//
//  A Demo for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//🍩

import UIKit

class ViewController: UIViewController {
    var yummy = "D\u{1f369}ugh\u{20d7}n\u{20ed}uts"
    
    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //yummy = "\u{1f369}"
        //yummy = "Bun\u{0303}elos"
        let nsYummy = NSString(string: yummy)
        
        let yummyChar = yummy[yummy.index(yummy.startIndex,offsetBy: 3)]
        print(yummyChar)
        
        let nsYummyChar = nsYummy.character(at: 4)
        
        for index in 0..Int{
        var pos = position
        if pos > 0 {pos -= 1} else {pos = 0}
        if pos >= count {pos = count - 1}
        return pos
    }
    
    private func index(_ position:Int)->String.Index{
        return self.index(startIndex, offsetBy: pos(position:position))
    }
    
    func leftString(from position:Int)-> String{
        return String(self[...index(position)])
    }
    func midString(from position:Int, length:Int)-> String{
        let endPosition = position + length - 1
        return String(self[index(position)...index(endPosition)])
    }
    func rightString(from position:Int)-> String{
        let rightIndex = self.index(endIndex, offsetBy: -pos(position:position + 1))
        return String(self[...rightIndex])
    }
}


Unicode Characters in Strings

Special characters like emoji, accents, and symbols in your strings are easier to get than you think. This week, we’ll talk about how using Unicode characters in Swift Strings. Open the exercise file and you’ll find a project which we’ll use for this. I just hooked up a label to make a big display of what I want to show.

Hit Control-Command-Spacebar to get the character viewer. If you get a compact one like this, click the upper right corner icon to expand it.

When expanded, Click the settings gear in the corner . Select customize list.


There a big list of items. 

You can select languages, I’ll select the Enclosed Characters for example.

Go down to the bottom and open Code tables then add Unicode. Click Done.

Select Unicode in the character viewer.

The Unicode set gives you the power to add a lot to your strings. This table lists all the Unicode symbols, and activates Unicode labeling of symbols in the character viewer. In the search bar of the character viewer, find a doughnut. You see a Unicode identifier after it.

You can use these Unicode characters in your app. You’ll see the doughnut is U+1f369.

I can add the doughnut to my code as an escape sequence in the string of  \u{} 

yummy = "\u{1f369}"

run my app, And I get a doughnut. 

If I need an accented character, I can use a Unicode character. In the search window, I’ll search for n. In the related characters, I’ll find an ñ.

Click that

It has a unicode of U+00f1, so I can do this:

var yummy = "Bu\u{00f1}elos"

That’s not very flexible for multiple accent combinations. Instead of using the single character, you can use extended grapheme clusters, which combines two characters. 

Head to the Unicode section of the Character viewer. Find the n. which has a value of U+006e

There a special set for combining characters with diacritical marks starting at U+0300.

The combining tilde is at U+0303. I can change my string to this:

yummy = "Bu\u{006e}\u{0303}elos"

Run this.

The combining Unicode doesn’t need the Unicode base by the way, You can do this with an n too:

yummy = "Bun\u{0303}elos"

Also gets

Diacritical marks can be anywhere in the character space. I’ll head over to the Combining Diacritical Marks for Symbols.Click a few and you’ll see in the preview their location referenced by some guidelines.

Some are above, some below and some in the middle.  Comment out the yummy assignments  we have. I’ll demonstrate the positions with this string:

var yummy = "D\u{1f369}ugh\u{20d7}n\u{20ed}uts"

Run this and see all the fun. .  

There’s one thing you have to be careful of here. Extended grapheme clusters are counted as a single character in a character count. Change the code to 

label.text = yummy + String(format:" %i",yummy.count)

and run

Yields 9, ignoring the arrows. This makes sense if you are counting full characters, but it runs into problems for memory allocation. If you are bridging between NSString and Swift’s String type, the allocation is different due to the extended grapheme clusters. This is why Swift strings aren’t true arrays with an integer index like C-strings. The clusters make counts impossible. I can’t do this to get the third character.

let char = yummy[3] 

I’ll get an error

I can’t just use an integer subscript. Next week, I’ll show you how to handle character access and manipulation in strings. 

The Whole Code

Here’s teh code for this project. You can also download it here from GitHub

//
//  A Demo for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//🍩

import UIKit

// an extra not found in the video:
// it doesn't hurt to make the characters constants or enums for more readable code.
    let upperArrow = "\u{20d7}"
    let lowerArrow = "\u{20ed}"
    let doughnut = "\u{1f369}"

class ViewController: UIViewController {
    var yummy = "D\u{1f369}ugh\u{20d7}n\u{20ed}uts"
    
    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        yummy = "\u{1f369}"
        yummy = "Bun\u{0303}elos"
        yummy = "D" + doughnut + "ugh" + upperArrow + "n" + lowerArrow + "uts"
        label.text = yummy + String(format:" %i",yummy.count)
    }

}



Ranges in Swift

You’ve probably used ranges in loops, without knowing it, but ranges are really a type in Swift. Have you ever thought about ranges and all their power? I’ll show you a few things you might want to know about Swift ranges. I’ve put a playground into a Project for an exercise file. I added there an array to play with

Here’s the one place I’m sure you’ve seen a range: in a for loop. Commonly you’ll see them as a closed range using the ... operator, which include all values in the range. This code

Adds 0+1+2+3+4+5 to get 15

A half-open range takes one less than the number, by changing the last dot for a less than symbol(..<). This half-open example goes from 0 to 4. Which gives us a total of 10.

Open and close ranges are their own type Range, not to be confused with NSRange. I can assign a range like any other type. Note here the upper bound is outside the range. .

Then use that value as the range in my for loop.

You can also use a range directly in an array’s subscript. I can make a subarray of elements like this.

which makes a small array of the second, third, and fourth elements of the array.

You can use an half open range here too.   

You can stick a count for the array in the range, but there is a faster way. You can use fully open range. Open ranges don’t specify one bound of the range. For example to the end of the array like this: 

Or the beginning to iterate from the beginning to an end. 

You also can test for membership with the contains property. To see if my range contains 5 I’d use

Since I set range= 0..<5 this returns false as 5 is outside the range. If I look for 2

that returns true because 2 is between 1 and 4

the contains method become handy because you can use it to test if an index is within a range. For a simple example, I’ll write a snippet of code to check if an index is in a given array. I’ll check for element 4 and get Ice cream.

I check for 42, I’ll get nothing

I’ve stuck to Integers here, but ranges can be other types as well. Four example, you can add a range of Double, then check if a valur exists inthat range quickly.


One important caution I mentioned earlier: Unlike other Swift types, Range and NSRange is not the same thing.

NSRange is a location and a length , Range is upper and lower bounds. Closed ranges might be a bit easier to convert between the two, but open ranges make it very difficult to convert from one to another. Some API use Range and some NSRange. Make sure you know which one you are using.  

The Whole Code

You can also download this from Github here: If you copy and paste this into a Swift playground in iPad, the copy below will format itself.

import UIKit
//:# Range Demo
//
//:  A Demo for iOS Development Tips Weekly
//:  by Steven Lipton (C)2018, All rights reserved
//:  For videos go to http://bit.ly/TipsLinkedInLearning
//:  For code go to http://bit.ly/AppPieGithub
//:

//: A swift playground formatted for iPad playgrounds

let myDesserts = ["Cannoli","Mochi","Bunelos","Pecan Pie","Ice Cream"]

//:## Basic Ranges
//: Closed range
var total = 0
for number in 0...5{
    total += number
}
total


//: Half Open range
total = 0
for number in 0..<5{
    total += number
}
total


var doubleRange = 0.1...6.7
doubleRange.contains(Double.pi)




//: Assigning ranges
var range = 0..<5
//:Range is not NSRange
var nsRange = NSRange(location: 0, length: 4)






total = 0
for number in range{
    total += number
}
total




//: Use as array subscripts
var eating  = myDesserts[2...4]
eating = myDesserts[2..<4]
eating = myDesserts[2...]
eating = myDesserts[...3]
//: Membership
range.contains(5)
range.contains(2)


let a = 42
range = 0..<myDesserts.count
var eat = ""
if range.contains(a){
    eat = myDesserts[a]
} else {
    eat = "nothing"
}
eat


Replace Segmented Controls with Button Arrays

You’ve probably used the Segmented control before like this one

It’s great for some simple uses but lacks flexibility. Besides using only text or single color icon, it doesn’t work in vertical or other arrangements. Let’s look at another solution: Using Button arrays. 

In the exercise files, I’ve set up for you a vertical stack view of buttons, though I could have placed these anywhere with Autolayout.

Open up the assistant editor. I’ve hooked up everything for you but the buttons.  Control-drag from the pizza button to the assistant editor.

While you could use the stack view’s arrangedSubviews array, a more flexible option is a collection of outlets with the outlet collection selection. Instaed of picking an outlet for the connection, select Outlet Collection

I’ll name the collection dessertSelection.

I’ll manually control drag the other buttons to this collection to keep the order correct.  

Control-drag again from the story board.  Make a action didSelectDessert with a sender of UIButton. Drag from the connector to the button so all buttons use the same action. 

Close up the assistant editor and head to ViewController. Each button now will have two states: selected and deselected. We’ll need to deselect everything, and then select the one the user tapped. 

@IBAction func didSelectDessert(_ sender: UIButton) {
     allDeselected()
     selectDessert(button: sender)
}

The power of that array shows up when deselecting the button. You can iterate through the buttons to shut them all off, which in this case is adding a drop shadow I made for you in the shadowOn method: 

func allDeselected(){
        for button in dessertSelection{
           shadowOn(button: button)
        }
    }

Selecting a dessert is doing the opposite to the selected button:

func selectDessert(button:UIButton){
        shadowOff(button: button)    
 }

This gives the selected button a pressed-down look. 

To finish the display, add an allDeselected to viewDidLoad to start fresh. 

override func viewDidLoad() {
        super.viewDidLoad()
        allDeselected()
    }

Run this, which I’ll do on a iPhone XR and you’ll  get buttons that select. For example select mochi

then select Napolean. Mochi pops back up and Napolean depresses.

Of course, you want it to select something.  To do that, make a selectedIndex function.  It will look for a selected condition in the array, which I’ll use the shadow radius, then return the index. 

func selectedIndex()->Int?{
        return dessertSelection.index(where: {(button)-> Bool in
               button.layer.shadowRadius == 1.0})
    }

Back in didSelectDessert, I’ll change the label’s text.  I’ll start by unwrapping the button’s title and the selected index. 

if let selection = selectedIndex() , let text = sender.titleLabel?.text {

}

I’ll set the text, adding 1 since users don’t think to start at zero.  

selectionLabel.text = "#\(selection + 1) " + text

 And finish with an else in case our index or title are missing. 

} else {
            selectionLabel.text = "No Selection"
        }

Run that, and try the buttons.

They now give the selection and the title of the button. This was a simple version of what you can do with an array of buttons. Unlike a segmented control you can arrange and format  them like buttons, which leads to a lot of flexibility in choice controls.