Swift – AVAudioFoundation

Playing sounds with Swift and AVAudioFoundation

A few notes about using AVAudioFoundation with Swift.

Be sure to add your audio files to your project. Make sure they have been “added to target”. Without this the audio files will not be bundled with your app.

Import AVAudioFoundation.

Use AVAudioPlayer() to create a new audio player instance.

Call audioPlayer.play() to play a sound and audioPlayer.stop() to stop a sound.

Sounds play from beginning to end. Calling stop() pauses the sound at the current time. Calling play() again starts the sound from the current time. To start from the beginning of the set the currentTime property to 0!

Here is a sample code block.

import AVAudioFoundation

// Get a path to your audio resource
let path = NSBundle.mainBundle().pathForResource(self.audioFileName(), ofType: nil)!

// Make a URL from the path
let url = NSURL(fileURLWithPath: path)
// Try to make an audio player with the URL
do {
    let sound = try AVAudioPlayer(contentsOfURL: url)
    sound.play() // If all is good play your sound
} catch {
    // Handle an error here
    print("unable to load sound...")
}

The Language of Segues

In iOS Segues are used to get from one content screen to another. A tranistion occurs between screens when a sgue is invoked. There are a few simple transitions that are default, and you can also make your own custom transitions.

The default transitions, simple as they are, provide a good foundation for presenting content. Used correctly they act as a language that communicates the relationships between content screens.

Show/Push Segue

When screen slides in from right to left you are moving deeper into the content. Like turning pages in a book. This is a Show Segue in iOS. When the Screen slides left to right you are moving up in content, like turning back to the previous page.

Notice that in both of these cases the current content is pushed off the left or right. This is a subtle part of the communication. Telling you that the you are moving on to new content and the old content has moved aside. It also gives the impression of content screens as a row or a timeline, and adds to the feel of content having a structure or history.

This is what you get when working with the Navigation controller. Which makes sense. Notice in most cases there will be a back button in the upper left. A UI element people universally understand.

Modal Segue

When a screen slides up from the bottom this is a Modal segue. In this case you are staying in the current content screen and showing a screen on top. A modal is a dialog box. You’ll answer any questions, set any options before it goes away and the current content revealed again. The Alert dialog box is a modal. Though in this case it is small enough to allow you to see the current content behind it.

Use a modal when you want to ask a question or get information. Like, asking for a user name and password, presenting some settings, or showing an option to buy some gems in the app store.

Notice when a screen slides up from the bottom the current screen is covered, it is not pushed out of the way. This is telling you that the current content screen is still there behind this new modal content waiting for you.

You’ll notice this is what you get when you open the camera or photo picker in an app. It slides up from the bottom, covering the current screen. You take a photo with the camera or pick a photo from your library, and the photo picker slides down revealing the previous screen. This is exactly what you expect. You don’t want the photo picker to push the current off the left, you would worry that you’d be losing that email, or text message as you moved on to a new content screen.

Non transition

Think about the tab bar controller. Notice there is no transition when switching tabs. In this case I’m guessing Apple felt they wanted to convey that each tab was it’s own separate area, almost like each tab section was an app within the app. With no motion you get the impression you have teleported to a new location. With motion you might feel you are moving to content that is connected to the current content. Instead you are leaving the current content behind, and jumping to a new area with new content. You should be able to visit the previous tab and return to that part of the app in the state you left it.

Imagine if there was a slide/push to the left or right. You might feel like you were moving deeper into the current content rather than moving on to a new content area, which would be confusing when that content belonged to an unrelated area of the app.

It’s all about Communication

You’re not using transitions as a creative tool, instead use them as a form communication. While transitions can be very creative, without thinking about communication first you can create a confusing user experience.

Swift – UIView

Here are some notes on working with UIView. I try to cover the differences between frame and bounds, and how to position elements on the screen using frame, bounds, and center. There is a video example and corresponding files on Github: https://github.com/soggybag/View-Experiements

Views

Views are the visible elements that appear in your apps. Views can look like anything. They can have color, images and text. Views can detect user touch interactions. A view is always a rectangle. The contents can have an alpha mask to allow the view to appear as any shape.

UIView

UIView is the base class for all visible elements that might appear on the screen. Every UI element inherits from UIView. You can think all the UI elements as UIViews with special added features. For example UILabel is a specialized version of UIView that is meant to act as a simple text display. All of the UI elements are built on top of a UIView.

Make a UIView for yourself.

let box = UIView()

In order to see the the view it needs a size, position, and to be added as a subview of a view that is in the display stack. You may also need to set the color. A white view against a white background will be hard to find!

Frames, Bounds, and Rectangles

Views are rectangular. A rectangle where a view can draw itself, and a user can interact. A rectangle or rect defines the both the size and position of a rectangular area of the screen. A rect is defined by four properties: x, y, width, and height.

CGRect(x: 0, y: 0, width: 100, height: 100)

The CGRect class is used to define a rect. UIView defines the frame property as a rect. Setting the frame of a view sets the position and size of the view.

The frame property of a view is a CGRect that defines the size and position of the view in it’s super view‘s coordinate system. Think about this as the size and position in the world in which it’s exists.

The bounds property of a view is also a CGRect. The bounds defines the size and position of a view it’s own, or local, coordinate space.

box.frame = CGRect(x: 0, y:0, width: 100, height: 100)

This should produce a box 100 by 100 points in the upper left corner. NOTE: you may not be able to see the white box against the white background! Set the background color:

box.backgroundColor = UIColor.redColor()

Center, X, and Y

 

A view can be positioned through it’s center property. The center property is a CGPoint. CGPoint contains an x and a y property.

While the x and y of the frame position a view around it’s upper left corner, the center.x and center.y position a view around it’s center!  You can check this for yourself:

let box = UIView()
box.frame = CGRect(x: 0, y:0, width: 100, height: 100)
print(box.center) // (50.0, 50.0)

You can see the center shows x and y of 50 while we set the frame x and y to 0 and 0.

Subviews

All views act as a containers for other views. You can add any view as a subview to another view. You can think of this like creating layers or groups. Or like nesting html tags.

Add a view to another view with the addSubview() method:

let box = UIView()
box.frame = CGRect(x: 0, y:0, width: 100, height: 100)
box.backgroundColor = UIColor.redColor()
view.addSubview(box)

The block of code above, added to your viewDidLoad(), would produce a red box in the upper left corner of 100 by 100 points.

Nesting Views

Views stack, front to back, in the order they are added with addSubview() since addSubview() adds the new view in front of existing views. You can use these other methods to arrange views.

 

  • addSubView()
  • insertSubview(:atIndex)
  • insertSubView(:belowSubview)
  • insertSubview(:aboveSubview)
  • exchangeSubviewAtIndex(:withSubviewAtIndex)
  • bringSubviewToFront()
  • sendSubviewToBack()

Width and Height

Setting the width and the height can be confusing. These properties show up in several places. For example:

box.frame.width // get only! 
box.frame.size.width // get and set

While both of this properties return the same value, the first (frame.width) is get only! You can’t set it. The second (frame.size.width) is get and set. The same is true for height.

box.frame.height // get only! 
box.frame.size.height //get and set

This also applies to bounds.

box.bounds.width // get only! 
box.bounds.height // get only!
box.bounds.size.width // get and set
box.bounds.size.height // get and set

CGSize

CGSize is a type with two properties: width and height.

box.frame.size = CGSize(width: 100, height: 100)

 

Frame vs Bounds and Coordinate space

Each view supports its own coordinate space. Imagine that each view defines x:0 as the position of it’s left edge, and y:0 as it’s top edge. Frame defines the position and size of a view within it’s superview, while bounds defines location and height in a views own coordinate space.

Center

A view also has a center. This is a CGPoint that locates the view on the x and y axis around it’s origin. The origin should be in the center of a view by default.

Origin

The origin is a property of bounds, and sets the x, and y position around which the rectangle is drawn.

 

Swift – UITableViewRowActions and editActionsForRowAtIndexPath

Do you like those button that display when you swipe a row in a table view to the left? You can add your own with little effort using UITableViewRowAction, and tableView(:editActionsForRowAtIndexPath).

tableView editActionsForRowAtIndexPath is a UITableViewDelegate method. This method returns an array of UITableViewRowAction’s. Each of these row actions includes a style, title, and action. The action receives the index path of the row where the action was executed.

Here is a sample gist:

 

Swift – Singletons

Singleton and the TodoManager

The goal of the current project is to create a Todo App. This app will work with Todo items that need to be shared across more than one view controller. One approach is to create a single instance of a class that can be shared across the entire app. This is called a Singleton.

What is an instance?

A class file describes a type of object that can be created from that class. Each Object created from a class is called an Instance. For example our app will store Todo items. These are defined in the Todo class.

class Todo {

}

A class will define the properties, and methods of an object, and include an initializer.

class Todo {
var name: String
var completed = false
init(name: String) {
self.name = name
}
}

Create an instance of a class by using the name of the class like this.

var somethingTodo = Todo(name: “Eat Breakfast”)

In this case somethingTodo is an object with properties of name, and completed.

Each time you use Todo(name: “”) you are creating a new instance of Todo. Each instance stores it’s own unique values for name and completed.

This method works well for Todo items since we want to create a new and unique entry each time we create a Todo.

TodoManager
If our app contains a list of todos, we need to make these available across multiple View Controllers. If the Todos are stored in an array that belongs to (is a property of) One View Controller it’s very awkward to make todos available to other view controllers.

A better approach is to create a separate class to manage the list of todos. This class will be responsible for holding the list of Todos, relaying the count of todos, adding new todos, deleting todos, etc.

Keeping all of the code that manages Todos in one class helps keep our code organized. All of the methods and properties that manage our list of todo items will be in one place. Imagine the TodoManage class looks something like this:

class TodoManager {
var todos = [Todo]()
var count: Int {
get {
return todos.count
}
}
func addNewTodo(name: String) {

}
func getTodoAtIndex(index: Int) -> Todo {

}
}

There is one problem. Imagine we have three view controllers:

ListTodoViewController
AddNewTodoViewController
TodoDetailsViewController

Now imagine that each of these creates a new instance of TodoManager:

Here each view controller has it’s own instance of a TodoManager. That’s three unique managers. This won’t work for our app. Imagine that the app adds a new Todo to the manager owned by AddNewTodoManager. The todos array in List, and Details would not be updated to match.

What we need to create is something that looks like this:

Imagine in this arrangement that each ViewController has a manager property that points to the same instance. Now List View controller is displaying the same list of todos that Add new and details are working with.

Really what we will create is something that will look more like this:

Imagine here that TodoManager owns an instance of itself, and other classes can access that instance.

Singletons and Shared instance
Singleton is the name of a software design pattern. A design pattern is a standard solution for common programming problems. Our todo app is trying to solve a standard software problem: we need single instance of a class that can be shared.

Static/Class properties
Normally classes will only use instance properties. In the case of the Todo class, name and completed are instance properties. Instance properties belong to each instance, and each instance stores it’s own unique values for these properties.

Classes can also define static properties. These properties belong to the class, not to each instance! here’s an example class:

class Test {
static var name = “Hello World”
var number = 10
}

The first property is static, and belongs to the class, while the second property is an instance property, which each instance will have.

Test.name // “Hello World”
var instanceOfTest = Test()
instanceOfTest.number // 10

Working with a singleton
The singleton pattern works like this, we’ll use the TodoManager as an example. This class wants to manager a list of Todos that it can share with other classes in our app.

The TodoManager class starts like this:

class TodoManager {
static let sharedInstance = TodoManager()

private init() {

}
}

Notice the property sharedInstance is static. This makes it a class property. You’ll access it with:

TodoManager.sharedInstance

This property is also a constant, let. This means it can only have one value. You can’t set change its value once set.

To complete the pattern we mark the initializer: init() with private. This means that this method is only accessible within this class. You won’t be able to access the initializer from outside of the class.

 

Swift – NSNumberFormatter

At some point you will find yourself in need of formatting numbers. This could be for time, temperature, currency, or just wanting to control the number of decimal places. You might even want to convert numerals to words. The NSNumberFormatter does all of this.

Figure this is a very common task so, someone will have made a library of code to handle it. The Cocoa Touch framework provides the end all in number formatting  in NSNumberFormatter.

Using the NSNumberFormatter is easy though, maybe, not intuitive until you work with it a few times.

The steps are easy:

  1. Make an instance of the NSNumberFormatter.
  2. Set options…
  3. Call the formatter.stringFromNumber() method.

A use case might look like this:

 

 

The example above creates a number formatter that converts a value into a currency style. NSNumberFormatter, in this case, should convert “cost” into currency formatted number for the current locale.

This is very sophisticated, and powerful, for very little work on our part.

The second step is where things get hazy. There are many options you can choose from. We can break these down into styles, and options.

You can think of styles as predetermined, standardized ways of expressing numbers, and options as the details that might make up a style.

For example a style might be currency style. This might include options for rounding to two decimal places, and adding a comma every third significant digit, while preceding everything with the correct currency symbol.

Options on the other hand, would things like setting the number of digits before the decimal point, and the number of digits after the decimal point. Setting the character used for the separator, like the “.”, or “,”.

Here are a few examples:

 

Swift – Simple Animations

Need to create simple animation? Use UIView.animateWithDuration() or one of the other similar methods. While this is fairly easy to use, it is bit cumbersome. Why not make a helper method to simplify your work?

  1. Imagine a method that takes a UIView as a an argument. Since all UI elements are sub classes of UIView you can pass any UI element.
  2. For convenience imagine all of the elements were created at the location where they will end their motion. This means our method will offset the element in the x and or y, then move it back to it’s starting point.
  3. To make the motion interesting and give us some controller we need to pass in the duration.
  4. If everything is moving at the same time things are dull, and some things are not possible. We need a delay.

Our method looks like this:

func animateThing(thing: UIView, offsetY: CGFloat, offsetX: CGFloat, time: NSTimeInterval, delay: NSTimeInterval) {
// some code here 
}

The parameters are

  • thing – a UIView or subclass of UIView, which is the thing to animate
  • offsetY – CGFloat the amount to offset in the y axis. This sets the starting point on the y axis, thing will move back to original position!
  • offsetX – CGFloat the amount to offset on the x axis.
  • time – NSTimeInterval, this can be a Double (0.5 for example), it sets the length of the animation in seconds
  • delay – NSTimeInterval, this sets the time to wait before beginning the motion.

A few points

  1. The offsetX, and offsetY can use positive or negative numbers. Negative values move the object left or up. Positive numbers move down, or right. These determine an offset, that places the object at a new position before the motion begins, the object will end its motion at it’s starting point.
  2. Time is set in seconds. Delay determines how long to wait before the motion begins. The total time of the animation will be time + delay.
  3. It’s probably best to call this function in viewWillAppear. This way the objects get positioned before we see the view, and the motion will be applied each time the view is shown.

Using an Extension

An extension allows you to add functions to existing classes. Rather than adding this function to each custom view controller we create, using an extension we can add an extension to the UIViewController class, and all ViewControllers will have the new function.

Add the first code example to your project in a file named extensions.swift. You’re done! The second code example shows some usage examples and is not required.

Swift – Camera and UIImagePickerController

Take pictures with the UIImagePickerController. This is a ViewController subclass, that creates a view that allows you to take a picture with the camera.

The UIImagePickerController works with a Delegate to handle working with an image after it has been taken.

Try it for yourself. Create a ViewController with a UIImageView, add an IBOutlet for this. We will use this to display the image, so we need a reference.

Add a UIButton, and add an IBAction. Use this to open the Image Picker controller.

In the button action add:

 

Parse Swift with Cocoapods

  1. Xcode new project
  2. Terminal CD to project directory
  3. Open your Podfile with: open -a Xcode Podfile
  4. Uncomment Frameworks, and add Parse, and ParseUI to do. Should look something like this:
  5. # Uncomment this line to define a global platform for your project
    # platform :ios, '8.0'
    # Uncomment this line if you're using Swift
    use_frameworks!
    target 'SpringShowApp' do
    pod 'Parse'
    pod 'ParseUI'
    end
  6. Quit Xcode
  7. In terminal: pod install
  8. When Terminal is finished, open your project from the ProjectName.xcworkspace. From this point on, you will need to open the project from this file!