Quantcast
Channel: Kodeco | High quality programming tutorials: iOS, Android, Swift, Kotlin, Unity, and more
Viewing all 4373 articles
Browse latest View live

LiquidFun Tutorial with Metal and Swift – Part 1

$
0
0
Learn how to simulate water with LiquidFun and Metal!

Learn how to simulate water with LiquidFun and Metal!

Fluid dynamics and liquid simulation in games can be extremely difficult topics to digest. Without a good handle on physics and math concepts, it could take the average programmer months to accomplish what games like Where’s My Water and Sprinkle have done.

Thankfully, a group of talented engineers at Google have decided to lend us all a hand by giving us LiquidFun, an open-source multi-platform 2D physics engine. LiquidFun is built on top of Box2D, so while Box2D excels at 2D rigid body simulation, LiquidFun adds both particle-based fluid simulation and soft body simulation to the mix.

In this LiquidFun tutorial series, you’re going to learn the basics of making procedurally animated 2D water. You’ll use LiquidFun to simulate the motion of water particles, and Apple’s new GPU-accelerated 3D graphics API, called Metal, to render the water particles onscreen.

Note: Although this tutorial is designed to be as simple as possible, it’s still an intermediate-level tutorial because it combines several different technologies. By the time you complete the tutorial, you’ll have used the following programming languages: C, C++, Objective-C, Swift and the Metal shading language.

If you’re new to:

Getting Started

Note: This section is optional and covers how to integrate LiquidFun into your project. If you’d like, you can skip this section and begin with a starter project that has LiquidFun pre-integrated – just scroll down to the “Creating a LiquidFun Wrapper” section.

The first step is to create a Swift project. Launch Xcode (6 or higher), go to File\New\Project…, choose the iOS\Application\Single View Application template and click Next.

Fill out the options as follows:

  • Product Name: LiquidMetal
  • Language: Swift
  • Devices: Universal

Click Next, choose a folder for your project and click Create.

This is a portrait-only application, so open the Target Settings screen and in the General tab, make sure only Portrait is checked in the Device Orientation section:

Device orientation

To add LiquidFun to your project, download the latest stable version of LiquidFun (version 1.1.0 or later) and unarchive the package to a directory of your choice. For this example, I chose my Downloads directory.

Drag the liquidfun-1.1.0/liquidfun/Box2D/Box2D folder into your Xcode project. Make sure that Destination: Copy items if needed is checked, Added folders: Create groups is selected and Add to targets: LiquidMetal is checked, as shown below:

add_liquidfun

Because LiquidFun supports multiple platforms, it includes a lot of files that you won’t need for this tutorial. You need to remove the non-Xcode supported files so your project can build properly.

In your Xcode project directory, command-click the following unneeded files:

  1. Box2D/Box2D.vxcproj
  2. Box2D/Box2D.vcxproj.filters
  3. Box2D/Box2DConfig.cmake.in
  4. Box2D/CMakeLists.txt
  5. Box2D/UseBox2D.cmake
  6. Box2D/Documentation
  7. Box2D/Particle/b2ParticleAssembly.h
  8. Box2D/Particle/b2ParticleAssembly.neon.s
  9. Box2D/Particle/b2ParticleAssembly.cpp

Once you’ve selected them all, right-click on the group and choose Delete. Choose Remove References when prompted. Xcode will keep the files in your project directory but exclude them from your project. The GIF below demonstrates this process:

remove_liquidfun_extras

Build and run. You’ll encounter multiple “file not found” issues like the ones shown in the following image:

box2d_headerissue

You’re getting these errors because of how LiquidFun refers to its files internally. To fix them, you need to tell the compiler to look for header files inside the LiquidMetal folder you added to your project. Open the Target Settings screen, and in the Build Settings tab, add the following line to the Header Search Paths field:

$(SRCROOT)/LiquidMetal

This simply includes your project’s root directory to the header search paths – this way when you include a file with a path like Box2D/Particle/b2Particle.h it will resolve correctly.

Your target’s Header Search Paths should look like the following:

box2d_headerpath

That’s it! You’ve added LiquidFun to your Swift project. Build and run on any supported device or the iOS Simulator, and you should see the default splash screen transitioning to an empty view.

WhiteScreen

Creating a LiquidFun Wrapper

Note: If you skipped ahead to this section, download this starter project so you can jump straight into the action.

As a C++ library, LiquidFun can’t be used directly with Swift. This is because you can’t invoke C++ code from a Swift source file, nor, for that matter, can you invoke Swift code from a C++ source file. However, there’s a common link between the two languages: Objective-C.

Apple designed Swift to be interoperable with Objective-C; you can use Objective-C APIs in Swift and vice versa. Objective-C is also interoperable with C++, and you can use both languages in Objective-C++ source files.

To use LiquidFun in Swift, you have to create a wrapper class. This wrapper class will have a public interface written in Objective-C and an underlying implementation using Objective-C++.

wrapper_structure

The Objective-C layer is like a black box: Swift will only interact with Objective-C methods, without caring about how Objective-C does its business.

Let’s get started. Right-click the LiquidMetal group in the Project Navigator and select New File…, then select the iOS\Source\Cocoa Touch Class template and click Next. Call the class LiquidFun, enter NSObject into the Subclass of field and select Objective-C for the Language field. Click Next and then Create.

Select LiquidFun.m in your Project Navigator and left-click on it once more to rename the file. Change its name to LiquidFun.mm.

Changing the file’s extension to mm instructs Xcode to treat that file’s contents as Objective-C++ instead of Objective-C. If you hadn’t done that, you’d get errors later when you tried to compile this class.

With the LiquidFun class, you now have a place to mix Objective-C and C++ code together. The next step is to import this file into your Swift code. To do this, you need to create an Objective-C bridging header.

Right-click the LiquidMetal group in the Project Navigator and select New File…, then select the iOS\Source\Header File template and click Next. Name the file Bridging-Header and click Create.

Open Bridging-Header.h and add this line right below #define LiquidMetal_Bridging_Header_h:

#import "LiquidFun.h"

You can use all Objective-C headers exposed in this bridging header directly in any Swift source file in your project. In addition, you can interact with your Objective-C code using Swift syntax. Neat!

You have to tell the compiler about your Objective-C bridging header. Open the Target Settings screen, and in the Build Settings tab, add the following line to the Objective-C Bridging Header field:

LiquidMetal/Bridging-Header.h

The line you’ve added, shown in the following image, specifies the header file complete with its path from the root of the project.

bridging_header

You can now work seamlessly between C++, Objective-C and Swift. Build and run to confirm that your project is still working as expected.

WhiteScreen2

Note: From here on, I’ll refer to the Box2D-based physics engine as simply LiquidFun, while I’ll refer to LiquidFun.h/.mm, the wrapper class, as the LiquidFun wrapper class.

Creating a Physics World

To work with LiquidFun, you first need to create a world object. The world object manages and contains a collection of physics objects that interact with each other.

Note: Remember, LiquidFun is built on top of Box2D, so if you’re familiar with Box2D (or Sprite Kit’s physics engine, which is also built on top of Box2D) then you should be familiar with this concept, and many other concepts referenced in this tutorial.

Go to LiquidFun.h and add the following code above the @interface line:

#ifndef LiquidFun_Definitions
#define LiquidFun_Definitions
 
typedef struct Vector2D {
  float x;
  float y;
} Vector2D;
 
#endif

Then declare the following method inside the LiquidFun interface:

+ (void)createWorldWithGravity:(Vector2D)gravity;

You’ve declared your very first wrapper method and created a structure called Vector2D that holds x- and y-coordinates. LiquidFun has its own structure for holding the same information, called b2Vec2, but since you can’t expose any C++ code to Swift, you’ve created a new Swift-compatible structure in the wrapper’s public interface.

Note: Objective-C Cocoa has a similar structure named CGPoint. However, CGPoint contains CGFloat x- and y-coordinates instead of regular floats. A CGFloat is a regular float type in a 32-bit architecture but becomes a double type in a 64-bit architecture. LiquidFun and Swift are similar in that they both deal with float explicitly, so having this kind of auto-conversion may lead to unpredictable results.

Next, switch to LiquidFun.mm and add the following lines just above the @implementation line:

#import "Box2D.h"
 
static b2World *world;

Then add the following method to the LiquidFun class implementation:

+ (void)createWorldWithGravity:(Vector2D)gravity {
  world = new b2World(b2Vec2(gravity.x, gravity.y));
}

You import the main header of LiquidFun so you can use its classes and methods inside the wrapper. Then, you create a static b2World variable to keep a global reference to the world object you’ll create later. Since you won’t be creating any instances of the LiquidFun wrapper class, a static variable is as close as you can get to a class variable.

createWorldWithGravity: is a pass-through method to LiquidFun’s b2World constructor. This method creates a new b2World instance with the supplied gravity. Since the constructor method expects a b2Vec2 coordinate structure, you use the Vector2D type as input and create a counterpart b2Vec2 structure out of it.

All right, it’s time to create your world in Swift!

WholeNewWorld

Switch to ViewController.swift and add the following constant to the ViewController class:

let gravity: Float = 9.80665

Here you create a gravity constant to match the value of Earth’s standard gravity.

Next, add the following line to viewDidLoad:

LiquidFun.createWorldWithGravity(Vector2D(x: 0, y: -gravity))

This uses the LiquidFun wrapper class to create the world object with a negative y-gravity so that every object inside this world will fall down vertically.

Build and run to again see none of your work reflected on the screen. :]

WhiteScreen3

Simulating Water

You now have an empty world to play with, so it’s time to get to the main topic—water simulation. Ironically, water simulation is the easiest part of this tutorial due to the fact that LiquidFun makes it so simple.

Open LiquidFun.h and add the following structure after #define LiquidFun_Definitions:

typedef struct Size2D {
  float width;
  float height;
} Size2D;

Then add the following method declarations to the LiquidFun interface:

+ (void *)createParticleSystemWithRadius:(float)radius dampingStrength:(float)dampingStrength 
                            gravityScale:(float)gravityScale density:(float)density;
+ (void)createParticleBoxForSystem:(void *)particleSystem 
                          position:(Vector2D)position size:(Size2D)size;

You define another convenience structure named Size2D that contains width and height information. Next, you declare the two methods needed to create water in LiquidFun.

The foundation of LiquidFun’s water simulation is the particle system, defined by a b2ParticleSystem object. If each particle represents a water droplet, the particle system is their parent and enforces properties common to them all.

Each particle system is a subsystem within the larger simulation defined by the world object it belongs to. That is, a world object could contain multiple different particle systems, and once created, each particle system can generate particles discretely or in groups.

Switch to LiquidFun.mm and add this method:

+ (void *)createParticleSystemWithRadius:(float)radius dampingStrength:(float)dampingStrength
                            gravityScale:(float)gravityScale density:(float)density {
  b2ParticleSystemDef particleSystemDef;
  particleSystemDef.radius = radius;
  particleSystemDef.dampingStrength = dampingStrength;
  particleSystemDef.gravityScale = gravityScale;
  particleSystemDef.density = density;
 
  b2ParticleSystem *particleSystem = world->CreateParticleSystem(&particleSystemDef);
 
  return particleSystem;
}

This method creates a particle system with an initial set of properties defined by a b2ParticleSystemDef:

  • A particle is round, so you need to define a radius for each particle in the system.
  • You’ll use dampingStrength to reduce the velocity of particles over time.
  • A particle system doesn’t need to strictly follow the physics world’s gravity, so it uses gravityScale to adjust the effect of the physics world’s gravity on its particles.
  • density affects the mass of the particles, and this affects how the particles interact with other physics bodies in the simulation. However, density doesn’t change how particles interact with each other.

b2World is the overall manager of the simulation, so you use it to create a new b2ParticleSystem with the properties you defined. After the particle system is created, this method returns a reference to it so you can access the particle system again later. Note that this method returns a pointer of type void *, a generic pointer to an address in memory, because Swift doesn’t know about the b2ParticleSystem type.

Still in LiquidFun.mm, add this method:

+ (void)createParticleBoxForSystem:(void *)particleSystem 
                          position:(Vector2D)position size:(Size2D)size {
  b2PolygonShape shape;
  shape.SetAsBox(size.width * 0.5f, size.height * 0.5f);
 
  b2ParticleGroupDef particleGroupDef;
  particleGroupDef.flags = b2_waterParticle;
  particleGroupDef.position.Set(position.x, position.y);
  particleGroupDef.shape = &shape;
 
  ((b2ParticleSystem *)particleSystem)->CreateParticleGroup(particleGroupDef);
}

To create a group of particles, you first need to define a shape for it (i.e. the shape of the container for the particles). This method uses a box shape defined by a size parameter for the group – later you will pass in a 50×50 point box at the bottom of the screen for this container box.

Next, you create a b2ParticleGroupDef to define properties for the group of particles to be produced. Since you want to simulate water, you specify the b2_waterParticle flag as the type of particle and place the group in a starting position.

Note: You can specify multiple flags for the type of particle you want. Check out the b2ParticleFlag documentation to learn more about the different types of flags available.

Finally, you ask the particle system to create a group of particles with the defined properties. This method expects to be given a reference to a previously created particle system, so you must use it in conjunction with createParticleSystemWithRadius:dampingStrength:gravityScale:density:, which you defined earlier.

Open ViewController.swift and add the following properties:

let ptmRatio: Float = 32.0
let particleRadius: Float = 9
var particleSystem: UnsafeMutablePointer<Void>!

Here’s a breakdown of the properties you’ve just added:

  • ptmRatio is the points-to-meters conversion ratio. LiquidFun is optimized to work with objects sized from as small as 0.1 meters to as big as 10 meters. Since a 0.1-point sized object won’t be visible on your device, you need a ratio to convert LiquidFun’s units—meters—to screen coordinates in points. With this ratio, a 1-meter object in LiquidFun’s physics simulation would occupy 32 points onscreen.
  • particleRadius defines the radius you’ll use, in points, for your water particles.
  • particleSystem will hold a reference to the particle system you’ll create later. The UnsafeMutablePointer<Void> type is Swift’s way of representing the void * type you used in your wrapper class earlier.

Still in ViewController.swift, add the following to the end of viewDidLoad:

particleSystem = LiquidFun.createParticleSystemWithRadius(
  particleRadius / ptmRatio, dampingStrength: 0.2, gravityScale: 1, density: 1.2)
 
let screenSize: CGSize = UIScreen.mainScreen().bounds.size
let screenWidth = Float(screenSize.width)
let screenHeight = Float(screenSize.height)
 
LiquidFun.createParticleBoxForSystem(particleSystem, 
  position: Vector2D(x: screenWidth * 0.5 / ptmRatio, y: screenHeight * 0.5 / ptmRatio), 
  size: Size2D(width: 50 / ptmRatio, height: 50 / ptmRatio))

First, you create a particle system and store a reference to it. You divide the particle radius by the points-to-meters ratio you defined earlier so that LiquidFun doesn’t produce huge water particles. Your particles will still show up as 9 points onscreen, but in LiquidFun coordinates it will be 9.0 points / 32.0 points per meter = 0.28 meters.

Next, using the particleSystem you just created, you add a group of particles in a 50×50-point box at the center of the screen. To compute for the center, you get the screen bounds from UIScreen and convert the retrieved width and height values to Swift Floats from CGFloat. As before, you divide all values using ptmRatio.

Build and run to make sure everything still compiles correctly.

WhiteScreen4

Where’s My Water?

Congratulations! You’ve just added an invisible particle system to your invisible physics world.

Of course, invisible particle systems, while potentially useful to create certain effects, are pretty anti-climatic. Unfortunately, you still have a ways to go before you can draw your water particles onscreen, but in the meantime you can at least print out the positions of the particles in your system to confirm they exist.

Go to LiquidFun.h and add the following method declarations:

+ (int)particleCountForSystem:(void *)particleSystem;
+ (void *)particlePositionsForSystem:(void *)particleSystem;

Quickly switch to LiquidFun.mm and add the following implementations of those methods:

+ (int)particleCountForSystem:(void *)particleSystem {
  return ((b2ParticleSystem *)particleSystem)->GetParticleCount();
}
 
+ (void *)particlePositionsForSystem:(void *)particleSystem {
  return ((b2ParticleSystem *)particleSystem)->GetPositionBuffer();
}

These are both Objective-C pass-through methods for their C++ counterparts. particleCountForSystem: returns the number of particles currently alive in a particle system, while particlePositionsForSystem: returns a pointer to the array of b2Vec2 positions of these particles. Once again, you return void * because Swift doesn’t know about the b2Vec2 type.

Now open ViewController.swift and add the following method:

func printParticleInfo() {
  let count = Int(LiquidFun.particleCountForSystem(particleSystem))
  println("There are \(count) particles present")
 
  let positions = UnsafePointer<Vector2D>(LiquidFun.particlePositionsForSystem(particleSystem))
 
  for i in 0..<count {
    let position = positions[i]
    println("particle: \(i) position: (\(position.x), \(position.y))")
  }
}

And add a call to this method at the end of viewDidLoad:

printParticleInfo()

You call printParticleInfo to log how many particles were created and their positions in your physics world. particlePositionsForSystem returns a pointer to an array of type void * (originally b2Vec2), so you typecast it to a Vector2D array pointer instead, allowing you to access each element’s properties.

Note that directly converting one structure to another like this is a dangerous thing to do, but in this case, Vector2D and b2Vec2 are similar enough that it works.

Build and run, and look at the developer console.

log_particles

Hello, particles!

Note: When creating a group of particles in a box, LiquidFun creates the particles (.75 * particle diameter) units apart from one another by default. It produces particles from the center outward, and creates any particle whose center falls within the defined shape.

Where to Go From Here?

So far, you’ve learned how to integrate LiquidFun with Swift, and in the process, you’ve created an invisible liquid particle system. Now it’s time to take a breather.

Here’s the sample project with all of the code from this LiquidFun tutorial.

From this point on, you have multiple options for how to render your LiquidFun particles onscreen. You could use a Sprite Kit particle system and manually map the positions of your LiquidFun particles to it, or you could roll your own particle system using OpenGL ES. For this tutorial series, you’ll use Apple’s Metal graphics API for the task.

When you’re ready, move on to Part 2 of this series, where you’ll render a LiquidFun particle system using Metal.

In the meantime, if you have any questions or comments about this part, please join the forum discussion below!

LiquidFun Tutorial with Metal and Swift – Part 1 is a post from: Ray Wenderlich

The post LiquidFun Tutorial with Metal and Swift – Part 1 appeared first on Ray Wenderlich.


Video Tutorial: Swift Scroll View School Part 2: Scrolling

Grand Central Dispatch Tutorial for Swift: Part 1/2

$
0
0
Learn about concurrency in this Grand Central Dispatch in-depth tutorial series.

Learn about concurrency in this Grand Central Dispatch in-depth tutorial series.

Update note: This tutorial was updated for iOS 8 and Swift by Bjørn Ruud. Original post by Tutorial Team member Derek Selander.

Although Grand Central Dispatch (or GCD for short) has been around for a while, not everyone knows how to get the most out of it. This is understandable; concurrency is tricky, and GCD’s C-based API can seem like a set of pointy corners poking into the smooth world of Swift.

In this two-part series, you’ll learn the ins and outs of GCD. This first part will explain what GCD does and showcase several of the more basic GCD functions. In the second part, you’ll learn several of the more advanced functions GCD has to offer.

Getting Started

GCD is the marketing name for libdispatch, Apple’s library that provides support for concurrent code execution on multicore hardware on iOS and OS X. It offers the following benefits:

  • GCD can improve your app’s responsiveness by helping you defer computationally expensive tasks and run them in the background.
  • GCD provides an easier concurrency model than locks and threads and helps to avoid concurrency bugs.

To understand GCD, you need to be comfortable with several concepts related to threading and concurrency. These can be both vague and subtle, so take a moment to review them briefly in the context of GCD.

Serial vs. Concurrent

These terms describe when tasks are executed with respect to each other. Tasks executed serially are always executed one at a time. Tasks executed concurrently might be executed at the same time.

Tasks

For the purposes of this tutorial you can consider a task to be a closure. In fact, you can also use GCD with function pointers, but in most cases this is substantially more tricky to use. Closures are just easier!

Don’t know what a closure is in Swift? Closures are self-contained, callable blocks of code that can be stored and passed around. When called, they behave like functions and can have parameters and return values. In addition a closure “captures” variables it uses from outside its own scope — that is, it sees the variables from the enclosing scope and remembers their value.

Swift closures are similar to Objective-C blocks and they are almost entirely interchangeable. Their only limitation is just that you cannot, from Objective-C, interact with Swift closures that expose Swift-only language features, like tuples. But interacting with Objective-C from Swift is unhindered, so whenever you read documentation that refers to an Objective-C block then you can safely substitute a Swift closure.

Synchronous vs. Asynchronous

These terms describe when a function will return control to the caller, and how much work will have been done by that point.

A synchronous function returns only after the completion of a task that it orders.

An asynchronous function, on the other hand, returns immediately, ordering the task to be done but not waiting for it. Thus, an asynchronous function does not block the current thread of execution from proceeding on to the next function.

Be careful — when you read that a synchronous function “blocks” the current thread, or that the function is a “blocking” function or blocking operation, don’t get confused! The verb blocks describes how a function affects its own thread and has no connection to the noun block, which describes an anonymous function literal in Objective-C. Also keep in mind that whenever the GCD documentation refers to Objective-C blocks it is interchangeable with Swift closures.

Critical Section

This is a piece of code that must not be executed concurrently, that is, from two threads at once. This is usually because the code manipulates a shared resource such as a variable that can become corrupt if it’s accessed by concurrent processes.

Race Condition

This is a situation where the behavior of a software system depends on a specific sequence or timing of events that execute in an uncontrolled manner, such as the exact order of execution of the program’s concurrent tasks. Race conditions can produce unpredictable behavior that aren’t immediately evident through code inspection.

Deadlock

Two (or sometimes more) items — in most cases, threads — are said to be deadlocked if they all get stuck waiting for each other to complete or perform another action. The first can’t finish because it’s waiting for the second to finish. But the second can’t finish because it’s waiting for the first to finish.

Thread Safe

Thread safe code can be safely called from multiple threads or concurrent tasks without causing any problems (data corruption, crashing, etc). Code that is not thread safe must only be run in one context at a time. An example of thread safe code is let a = ["thread-safe"]. This array is read-only and you can use it from multiple threads at the same time without issue. On the other hand, an array declared with var a = ["thread-unsafe"] is mutable and can be modified. That means it’s not thread-safe since several threads can access and modify the array at the same time with unpredictable results. Variables and data structures that are mutable and not inherently thread-safe should only be accessed from one thread at a time.

Context Switch

A context switch is the process of storing and restoring execution state when you switch between executing different threads on a single process. This process is quite common when writing multitasking apps, but comes at a cost of some additional overhead.

Concurrency vs Parallelism

Concurrency and parallelism are often mentioned together, so it’s worth a short explanation to distinguish them from each other.

Separate parts of concurrent code can be executed “simultaneously”. However, it’s up to the system to decide how this happens — or if it happens at all.

Multi-core devices execute multiple threads at the same time via parallelism; however, in order for single-cored devices to achieve this, they must run a thread, perform a context switch, then run another thread or process. This usually happens quickly enough as to give the illusion of parallel execution as shown by the diagram below:

Concurrency_vs_Parallelism

Although you may write your code to use concurrent execution under GCD, it’s up to GCD to decide how much parallelism is required. Parallelism requires concurrency, but concurrency does not guarantee parallelism.

The deeper point here is that concurrency is actually about structure. When you code with GCD in mind, you structure your code to expose the pieces of work that can run simultaneously, as well as the ones that must not be run simulataneously. If you want to delve more deeply into this subject, check out this excellent talk by Rob Pike.

Queues

GCD provides dispatch queues to handle submitted tasks; these queues manage the tasks you provide to GCD and execute those tasks in FIFO order. This guarantees that the first task added to the queue is the first task started in the queue, the second task added will be the second to start, and so on down the line.

All dispatch queues are themselves thread-safe in that you can access them from multiple threads simultaneously. The benefits of GCD are apparent when you understand how dispatch queues provide thread-safety to parts of your own code. The key to this is to choose the right kind of dispatch queue and the right dispatching function to submit your work to the queue.

Serial Queues

Tasks in serial queues execute one at a time, each task starting only after the preceding task has finished. As well, you won’t know the amount of time between one task ending and the next one beginning, as shown in the diagram below:

Serial-Queue-Swift

The execution timing of these tasks is under the control of GCD; the only thing you’re guaranteed to know is that GCD executes only one task at a time and that it executes the tasks in the order they were added to the queue.

Since no two tasks in a serial queue can ever run concurrently, there is no risk they might access the same critical section at the same time; that protects the critical section from race conditions with respect to those tasks only. So if the only way to access that critical section is via a task submitted to that dispatch queue, then you can be sure that the critical section is safe.

Concurrent Queues

Tasks in concurrent queues are guaranteed to start in the order they were added… and that’s about all you’re guaranteed! Items can finish in any order and you have no knowledge of the time it will take for the next task to start, nor the number of tasks that are running at any given time. Again, this is entirely up to GCD.

The diagram below shows a sample task execution plan of four concurrent tasks under GCD:

Concurrent-Queue-Swift

Notice how Task 1, 2, and 3 all ran quickly, one after another, while it took a while for Task 1 to start after Task 0 started. Also, Task 3 started after Task 2 but finished first.

The decision of when to start a task is entirely up to GCD. If the execution time of one task overlaps with another, it’s up to GCD to determine if it should run on a different core, if one is available, or instead to perform a context switch to a different task.

Just to make things interesting, GCD provides you with at least five particular queues to choose from within each queue type.

Queue Types

First, the system provides you with a special serial queue known as the main queue. Like any serial queue, tasks in this queue execute one at a time. However, it’s guaranteed that all tasks will execute on the main thread, which is the only thread allowed to update your UI. This queue is the one to use for sending messages to UIView objects or posting notifications.

The system also provides you with several concurrent queues. These queues are linked with their own Quality of Service (QoS) class. The QoS classes are meant to express the intent of the submitted task so that GCD can determine how to best prioritize it:

  • QOS_CLASS_USER_INTERACTIVE: The user interactive class represents tasks that need to be done immediately in order to provide a nice user experience. Use it for UI updates, event handling and small workloads that require low latency. The total amount of work done in this class during the execution of your app should be small.
  • QOS_CLASS_USER_INITIATED: The user initiated class represents tasks that are initiated from the UI and can be performed asynchronously. It should be used when the user is waiting for immediate results, and for tasks required to continue user interaction.
  • QOS_CLASS_UTILITY: The utility class represents long-running tasks, typically with a user-visible progress indicator. Use it for computations, I/O, networking, continous data feeds and similar tasks. This class is designed to be energy efficient.
  • QOS_CLASS_BACKGROUND: The background class represents tasks that the user is not directly aware of. Use it for prefetching, maintenance, and other tasks that don’t require user interaction and aren’t time-sensitive.

Be aware that Apple’s APIs also uses the global dispatch queues, so any tasks you add won’t be the only ones on these queues.

Finally, you can also create your own custom serial or concurrent queues. That means you have at least five queues at your disposal: the main queue, four global dispatch queues, plus any custom queues that you add to the mix!

And that’s the big picture of dispatch queues!

The “art” of GCD comes down to choosing the right queue dispatching function to submit your work to the queue. The best way to experience this is to work through the examples below, where we’ve provided some general recommendations along the way.

Sample Project

Since the goal of this tutorial is to optimize as well as safely call code from different threads using GCD, you’ll start with an almost-finished project named GooglyPuff.

GooglyPuff is a non-optimized, threading-unsafe app that overlays googly eyes on detected faces using Core Image’s face detection API. For the base image you can select any from the Photo Library or from a set of predefined URL images downloaded from the internet.

GooglyPuff_Swift_Start_1

Once you’ve downloaded the project, extract it to a convenient location, then open it up in Xcode and build and run. The app will look like the following:

Workflow

Notice when you choose the Le Internet option to download pictures, a UIAlertController alert view pops up prematurely. You’ll fix this in the second part of this series.

There are four classes of interest in this project:

  • PhotoCollectionViewController: This is the first view controller that starts the app. It showcases all the selected photos through their thumbnails.
  • PhotoDetailViewController: This performs the logic to add googly eyes to the image and to display the resulting image in a UIScrollView.
  • Photo: This is a protocol describing the properties of a photo. It provides an image, thumbnail and a status. Two classes are provided which implement the protocol: DownloadPhoto which instantiates photos from an instance of NSURL, and AssetPhoto which instantiates a photo from an instance of ALAsset.
  • PhotoManager: This manages all the Photo objects.

Handling Background Tasks with dispatch_sync

Head back to the app and add some photos from your Photo Library or use the Le Internet option to download a few.

Notice how long it takes for a new PhotoDetailViewController to instantiate after tapping on a UICollectionViewCell in the PhotoCollectionViewController; there’s a noticeable lag, especially when viewing large images on slower devices.

It’s easy to overload UIViewController’s viewDidLoad with too much clutter; this often results in longer waits before the view controller appears. If possible, it’s best to offload some work to be done in the background if it’s not absolutely essential at load time.

This sounds like a job for dispatch_async!

Open PhotoDetailViewController and replace viewDidLoad with the following implementation:

override func viewDidLoad() {
  super.viewDidLoad()
  assert(image != nil, "Image not set; required to use view controller")
  photoImageView.image = image
 
  // Resize if neccessary to ensure it's not pixelated
  if image.size.height <= photoImageView.bounds.size.height &&
     image.size.width <= photoImageView.bounds.size.width {
    photoImageView.contentMode = .Center
  }
 
  dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)) { // 1
    let overlayImage = self.faceOverlayImageFromImage(self.image)
    dispatch_async(dispatch_get_main_queue()) { // 2
      self.fadeInNewImage(overlayImage) // 3
    }
  }
}

Here’s what’s going on in the modified code above:

  1. You first move the work off of the main thread and onto a global queue. Because this is a dispatch_async call, the closure is submitted asynchronously meaning that execution of the calling thread continues. This lets viewDidLoad finish earlier on the main thread and makes the loading feel more snappy. Meanwhile, the face detection processing is started and will finish at some later time.
  2. At this point, the face detection processing is complete and you’ve generated a new image. Since you want to use this new image to update your UIImageView, you add a new closure to the main queue. Remember – you must always access UIKit classes on the main thread!
  3. Finally, you update the UI with fadeInNewImage which performs a fade-in transition of the new googly eyes image.

Note that you’re using Swift’s trailing closure syntax, passing closures to dispatch_async by writing them after the parentheses that contain the earlier parameter specifying the dispatch queue. That syntax can be a little cleaner looking since the closure isn’t nested inside the function’s parentheses.

Build and run your app; select an image and you’ll notice that the view controller loads up noticeably faster and adds the googly eyes after a short delay. This lends a nice effect to the app as you show the before and after photo for maximum impact. As well, if you tried to load an insanely huge image, the app wouldn’t hang in the process of loading the view controller, which allows the app to scale well.

As mentioned above, dispatch_async appends a task in the form of a closure onto a queue and returns immediately. The task will then be executed at some later time as decided by GCD. Use dispatch_async when you need to perform a network-based or CPU intensive task in the background and not block the current thread.

Here’s a quick guide of how and when to use the various queue types with dispatch_async:

  • Custom Serial Queue: A good choice when you want to perform background work serially and track it. This eliminates resource contention since you know only one task at a time is executing. Note that if you need the data from a method, you must inline another closure to retrieve it or consider using dispatch_sync.
  • Main Queue (Serial): This is a common choice to update the UI after completing work in a task on a concurrent queue. To do this, you’ll code one closure inside another. As well, if you’re in the main queue and call dispatch_async targeting the main queue, you can guarantee that this new task will execute sometime after the current method finishes.
  • Concurrent Queue: This is a common choice to perform non-UI work in the background.

Helper Variables for Getting Global Queues

You may have noticed that the QoS class parameter for dispatch_get_global_queue is a bit cumbersome to write. This is due to qos_class_t being defined as a struct with a value property of type UInt32, which must be typecast to Int. Add some global computed helper variables to Utils.swift, below the URL variables, to make getting a global queue a bit easier:

var GlobalMainQueue: dispatch_queue_t {
  return dispatch_get_main_queue()
}
 
var GlobalUserInteractiveQueue: dispatch_queue_t {
  return dispatch_get_global_queue(Int(QOS_CLASS_USER_INTERACTIVE.value), 0)
}
 
var GlobalUserInitiatedQueue: dispatch_queue_t {
  return dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)
}
 
var GlobalUtilityQueue: dispatch_queue_t {
  return dispatch_get_global_queue(Int(QOS_CLASS_UTILITY.value), 0)
}
 
var GlobalBackgroundQueue: dispatch_queue_t {
  return dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0)
}

Go back to viewDidLoad in PhotoDetailViewController and replace dispatch_get_global_queue and dispatch_get_main_queue with the helper variables:

dispatch_async(GlobalUserInitiatedQueue) {
  let overlayImage = self.faceOverlayImageFromImage(self.image)
  dispatch_async(GlobalMainQueue) {
    self.fadeInNewImage(overlayImage)
  }
}

This makes the dispatch calls much more readable and easy to see which queues are in use.

Delaying Work with dispatch_after

Consider the UX of your app for a moment. It’s possible that users might be confused about what to do when they open the app for the first time — were you? :]

It would be a good idea to display a prompt to the user if there aren’t any photos in the PhotoManager class. However, you also need to think about how the user’s eyes will navigate the home screen: if you display a prompt too quickly, they might miss it as their eyes lingered on other parts of the view.

A one-second delay before displaying the prompt should be enough to catch the user’s attention as they get their first look at the app.

Add the following code to the stubbed-out implementation of showOrHideNavPrompt in PhotoCollectionViewController.swift, near the bottom of the file:

func showOrHideNavPrompt() {
  let delayInSeconds = 1.0
  let popTime = dispatch_time(DISPATCH_TIME_NOW,
                              Int64(delayInSeconds * Double(NSEC_PER_SEC))) // 1
  dispatch_after(popTime, GlobalMainQueue) { // 2
    let count = PhotoManager.sharedManager.photos.count
    if count > 0 {
      self.navigationItem.prompt = nil
    } else {
      self.navigationItem.prompt = "Add photos with faces to Googlyify them!"
    }
  }
}

showOrHideNavPrompt executes in viewDidLoad and anytime your UICollectionView is reloaded. Taking each numbered comment in turn:

  1. You declare the variable that specifies the amount of time to delay.
  2. You then wait for the amount of time given in the delayInSeconds variable and then asynchronously add the closure to the main queue.

Build and run the app. There should be a slight delay, which will hopefully grab the user’s attention and show them what to do.

dispatch_after works just like a delayed dispatch_async. You still have no control over the actual time of execution nor can you cancel this once dispatch_after returns.

Wondering when it’s appropriate to use dispatch_after?

  • Custom Serial Queue: Use caution when using dispatch_after on a custom serial queue. You’re better off sticking to the main queue.
  • Main Queue (Serial): This is a good choice for dispatch_after; Xcode has a nice autocomplete template for this.
  • Concurrent Queue: Use caution when using dispatch_after on custom concurrent queues; it’s rare that you’ll do this. Stick to the main queue for these operations.

Singletons and Thread Safety

Singletons. Love them or hate them, they’re as popular in iOS as cats are on the web. :]

One frequent concern with singletons is that often they’re not thread safe. This concern is well-justified given their use: singletons are often used from multiple controllers accessing the singleton instance at the same time. The PhotoManager class is a singleton, so you will need to consider this issue.

There are two cases to consider, thread-safety during initialization of the singleton instance and during reads and writes to the instance.

Let us consider initialization first. This turns out to be the easy case, because of how Swift initializes variables at global scope. In Swift, global variables are initialized when they are first accessed, and they are guaranteed to be initialized in an atomic fashion. That is, the code performing initialization is treated as a critical section and is guaranteed to complete before any other thread gets access to the global variable. How does Swift do this for us? Behind the scenes, Swift itself is using GCD, by using the function dispatch_once, as discussed in this Swift Blog post.

dispatch_once executes a closure once and only once in a thread safe manner. If one thread is in the middle of executing the critical section — the task passed to dispatch_once — then other threads will just block until it completes. And once it does it complete, then those threads and other threads will not execute the section at all. And by defining the singleton as a global constant with let, we can further guarantee the variable will never be changed after initialization. In a sense, all Swift global constants are naturally born as singletons, with thread-safe initialization.

But we still need to consider reads and writes. While Swift uses dispatch_once to ensure that we are initializing the singleton in a thread-safe manner, it does not make the data type it represents thread safe. For example if the global variable is an instance of a class, you could still have critical sections within the class that manipulate internal data. Those would need to be made thread safe in other ways, such as by synchronizing access to the data, as you’ll see in the following sections.

Handling the Readers and Writers Problem

Thread-safe instantiation is not the only issue when dealing with singletons. If a singleton property represents a mutable object, like the photos array in PhotoManager, then you need to consider whether that object is itself thread-safe.

In Swift any variable declared with the let keyword is considered a constant and is read-only and thread-safe. Declare the variable with the var keyword however, and it becomes mutable and not thread-safe unless the data type is designed to be so. The Swift collection types like Array and Dictionary are not thread-safe when declared mutable. What about Foundation containers like NSArray? Are they thread safe? The answer is — “probably not”! Apple maintains a helpful list of the numerous Foundation classes which are not thread-safe.

Although many threads can read a mutable instance of Array simultaneously without issue, it’s not safe to let one thread modify the array while another is reading it. Your singleton doesn’t prevent this condition from happening in its current state.

To see the problem, have a look at addPhoto in PhotoManager.swift, which has been reproduced below:

func addPhoto(photo: Photo) {
  _photos.append(photo)
  dispatch_async(dispatch_get_main_queue()) {
    self.postContentAddedNotification()
  }
}

This is a write method as it modifies a mutable array object.

Now take a look at the photos property, reproduced below:

private var _photos: [Photo] = []
var photos: [Photo] {
  return _photos
}

The getter for this property is termed a read method as it’s reading the mutable array. The caller gets a copy of the array and is protected against mutating the original array inappropriately, but none of this provides any protection against one thread calling the write method addPhoto while simultaneously another thread calls the getter for the photos property.

Note: In the code above, why does the caller get a copy of the photos array? In Swift parameters and return types of functions are either passed by reference or by value. Passing by reference is the same as passing a pointer in Objective-C, which means you get access to the original object and any changes to it will be seen by any other parts of the code holding a reference to the same object. Passing by value results in a copy of the object, and changes to the copy will not affect the original. By default in Swift class instances are passed by reference and structs by value.

Swift’s built-in data types, like Array and Dictionary, are implemented as structs, and as a result there will seemingly be a lot of copying in your code when passing collections back and forth. Don’t worry about the memory usage implications of this. The Swift collection types are optimized to only make copies when necessary, for instance when an array passed by value is modified for the first time after being passed.

This is the classic software development Readers-Writers Problem. GCD provides an elegant solution of creating a read/write lock using dispatch barriers.

Dispatch barriers are a group of functions acting as a serial-style bottleneck when working with concurrent queues. Using GCD’s barrier API ensures that the submitted closure is the only item executed on the specified queue for that particular time. This means that all items submitted to the queue prior to the dispatch barrier must complete before the closure will execute.

When the closure’s turn arrives, the barrier executes the closure and ensures that the queue does not execute any other closures during that time. Once finished, the queue returns to its default implementation. GCD provides both synchronous and asynchronous barrier functions.

The diagram below illustrates the effect of barrier functions on various asynchronous tasks:

Dispatch-Barrier-Swift

Notice how in normal operation the queue acts just like a normal concurrent queue. But when the barrier is executing, it essentially acts like a serial queue. That is, the barrier is the only thing executing. After the barrier finishes, the queue goes back to being a normal concurrent queue.

Here’s when you would — and wouldn’t — use barrier functions:

  • Custom Serial Queue: A bad choice here; barriers won’t do anything helpful since a serial queue executes one operation at a time anyway.
  • Global Concurrent Queue: Use caution here; this probably isn’t the best idea since other systems might be using the queues and you don’t want to monopolize them for your own purposes.
  • Custom Concurrent Queue: This is a great choice for atomic or critical areas of code. Anything you’re setting or instantiating that needs to be thread safe is a great candidate for a barrier.

Since the only decent choice above is the custom concurrent queue, you’ll need to create one of your own to handle your barrier function and separate the read and write functions. The concurrent queue will allow multiple read operations simultaneously.

Open PhotoManager.swift and add the following private property to the class, below the photos property:

private let concurrentPhotoQueue = dispatch_queue_create(
    "com.raywenderlich.GooglyPuff.photoQueue", DISPATCH_QUEUE_CONCURRENT)

This initializes concurrentPhotoQueue as a concurrent queue using dispatch_queue_create. The first parameter is a reversed DNS style naming convention; make sure it’s descriptive since this can be helpful when debugging. The second parameter specifies whether you want your queue to be serial or concurrent.

Note: When searching for examples on the web, you’ll often see people pass 0 or NULL as the second parameter of dispatch_queue_create. This is a dated way of creating a serial dispatch queue; it’s always better to be specific with your parameters.

Find addPhoto and replace it with the following implementation:

func addPhoto(photo: Photo) {
  dispatch_barrier_async(concurrentPhotoQueue) { // 1
    self._photos.append(photo) // 2
    dispatch_async(GlobalMainQueue) { // 3
      self.postContentAddedNotification()
    }
  }
}

Here’s how your new write function works:

  1. Add the write operation using your custom queue. When the critical section executes at a later time this will be the only item in your queue to execute.
  2. This is the actual code which adds the object to the array. Since it’s a barrier closure, this closure will never run simultaneously with any other closure in concurrentPhotoQueue.
  3. Finally you post a notification that you’ve added the image. This notification should be posted from the main thread because it will do UI work, so here you dispatch another task asynchronously to the main queue for the notification.

This takes care of the write, but you also need to implement the photos read method.

To ensure thread safety with the writer side of matters, you need to perform the read on the concurrentPhotoQueue queue. You need to return from the function though, so you can’t dispatch asynchronously to the queue because that wouldn’t necessarily run before the reader function returns.

In this case, dispatch_sync would be an excellent candidate.

dispatch_sync synchronously submits work and waits for it to be completed before returning. Use dispatch_sync to keep track of your work with dispatch barriers, or when you need to wait for the operation to finish before you can use the data processed by the closure.

You need to be careful though. Imagine if you call dispatch_sync and target the current queue you’re already running on. This will result in a deadlock because the call will wait to until the closure finishes, but the closure can’t finish (it can’t even start!) until the currently executing closure is finished, which can’t! This should force you to be conscious of which queue you’re calling from — as well as which queue you’re passing in.

Here’s a quick overview of when and where to use dispatch_sync:

  • Custom Serial Queue: Be VERY careful in this situation; if you’re running in a queue and call dispatch_sync targeting the same queue, you will definitely create a deadlock.
  • Main Queue (Serial): Be VERY careful for the same reasons as above; this situation also has potential for a deadlock condition.
  • Concurrent Queue: This is a good candidate to sync work through dispatch barriers or when waiting for a task to complete so you can perform further processing.

Still working in PhotoManager.swift, replace the photos property with the following implementation:

var photos: [Photo] {
  var photosCopy: [Photo]!
  dispatch_sync(concurrentPhotoQueue) { // 1
    photosCopy = self._photos // 2
  }
  return photosCopy
}

Taking each numbered comment in turn, you’ll find the following:

  1. Dispatch synchronously onto the concurrentPhotoQueue to perform the read.
  2. Store a copy of the photo array in photosCopy and return it.

Congratulations — your PhotoManager singleton is now thread safe. No matter where or how you read or write photos, you can be confident that it will be done in a safe manner with no surprises.

A Visual Review of Queueing

Still not 100% sure on the essentials of GCD? Make sure you’re comfortable with the basics by creating simple examples yourself using GCD functions using breakpoints and NSLog statements to make sure you understand what is happening.

I’ve provided two animated GIFs below to help cement your understanding of dispatch_async and dispatch_sync. The code is included above each GIF as a visual aid; pay attention to each step of the GIF showing the breakpoint in the code on the left and the related queue state on the right.

dispatch_sync Revisited

override func viewDidLoad() {
  super.viewDidLoad()
 
  dispatch_sync(dispatch_get_global_queue(
      Int(QOS_CLASS_USER_INTERACTIVE.value), 0)) {
 
    NSLog("First Log")
 
  }
 
  NSLog("Second Log")
}

dispatch_sync_in_action_swift

Here’s your guide to the various states of the diagram:

  1. The main queue chugs along executing tasks in order — up next is a task to instantiate UIViewController which includes viewDidLoad.
  2. viewDidLoad executes on the main thread.
  3. The dispatch_sync closure is added to a global queue and will execute at a later time. Processes are halted on the main thread until the closure completes. Meanwhile, the global queue is concurrently processing tasks; recall that closures will be dequeued in FIFO order on a global queue but can be executed concurrently. The global queue processes the tasks that were already present on the queue before the dispatch_sync closure was added.
  4. Finally, the dispatch_sync closure has its turn.
  5. The closure is done so the tasks on the main thread can resume.
  6. viewDidLoad method is done, and the main queue carries on processing other tasks.

dispatch_sync adds a task to a queue and waits until that task completes. dispatch_async does the exact same thing, but the only exception is that it doesn’t wait for the task to complete before proceeding onwards from the calling thread.

dispatch_async Revisited

override func viewDidLoad() {
  super.viewDidLoad()
 
  dispatch_async(dispatch_get_global_queue(
      Int(QOS_CLASS_USER_INTERACTIVE.value), 0)) {
 
    NSLog("First Log")
 
  }
 
  NSLog("Second Log")
}

dispatch_async_in_action_swift

  1. The main queue chugs along executing tasks in order — up next is a task to instantiate UIViewController which includes viewDidLoad.
  2. viewDidLoad executes on the main thread.
  3. The dispatch_async closure is added to a global queue and will execute at a later time.
  4. viewDidLoad continues to move on after adding dispatch_async to the global queue and the main thread turns its attention to the remaining tasks. Meanwhile, the global queue is concurrently processing its outstanding tasks. Remember that closures will be dequeued in a FIFO order on a global queue but can be executed concurrently.
  5. The closure added by dispatch_async is now executing.
  6. The dispatch_async closure is done and both NSLog statements have placed their output on the console.

In this particular instance, the second NSLog statement executes, followed by the first NSLog statement. This isn’t always the case — it’s dependent on what the hardware is doing at that given time, and you have no control nor knowledge as to which statement will execute first. The “first” NSLog could be the first log to execute in some invocations.

Where to Go From Here?

In this tutorial, you learned how to make your code thread safe and how to maintain the responsiveness of the main thread while performing CPU intensive tasks.

You can download the GooglyPuff Project which contains all the improvements made in this tutorial so far. In the second part of this tutorial you’ll continue to improve upon this project.

If you plan on optimizing your own apps, you really should be profiling your work with the Time Profile template in Instruments. Using this utility is outside the scope of this tutorial, so check out How to Use Instruments for a excellent overview.

Also make sure that you profile with an actual device, since testing on the Simulator can give very different results that are different from what your users will experience.

In the next part of this tutorial you’ll dive even deeper into GCD’s API to do even more cool stuff.

If you have any questions or comments, feel free to join the discussion below!

Grand Central Dispatch Tutorial for Swift: Part 1/2 is a post from: Ray Wenderlich

The post Grand Central Dispatch Tutorial for Swift: Part 1/2 appeared first on Ray Wenderlich.

Grand Central Dispatch Tutorial for Swift: Part 2/2

$
0
0
Learn about concurrency in this Grand Central Dispatch in-depth tutorial series.

Learn about concurrency in this Grand Central Dispatch in-depth tutorial series.

Update note: This tutorial was updated for iOS 8 and Swift by Bjørn Ruud. Original post by Tutorial Team member Derek Selander.

Welcome to the second and final part of this Grand Central Dispatch tutorial series!

In the first part of this series, you learned about concurrency, threading, and how GCD works. You made the PhotoManager singleton thread safe for reading and writing of photos using a combination of dispatch_barrier_async and dispatch_sync. In addition to all that, you enhanced the UX of the app through the timing of a prompt with dispatch_after, and offloaded the work from the instantiation of a view controller to perform a CPU intensive task with dispatch_async.

If you have been following along, you can pick up where you left off with the sample project form Part 1. If you haven’t completed Part 1 or don’t want to reuse your project you can download the finished project from the first part of this tutorial here.

It’s time to explore some more GCD!

Correcting the Premature Popup

You may have noticed that when you try to add photos with the Le Internet option, an alert view pops up well before the images have finished downloading, as shown in the screenshot below:

Premature Completion Block

The fault lies with PhotoManager’s downloadPhotosWithCompletion which has been reproduced below:

func downloadPhotosWithCompletion(completion: BatchPhotoDownloadingCompletionClosure?) {
  var storedError: NSError!
  for address in [OverlyAttachedGirlfriendURLString,
                  SuccessKidURLString,
                  LotsOfFacesURLString] {
    let url = NSURL(string: address)
    let photo = DownloadPhoto(url: url!) {
      image, error in
      if error != nil {
        storedError = error
      }
    }
    PhotoManager.sharedManager.addPhoto(photo)
  }
 
  if let completion = completion {
    completion(error: storedError)
  }
}

Here you call the completion closure at the end of the method — you’re assuming all of the photo downloads have completed. But unfortunately, there’s no guarantee that all the downloads have finished by this point.

The DownloadPhoto class’s instantiation method starts downloading a file from a URL and returns immediately before the download completes. In other words, downloadPhotosWithCompletion calls its own completion closure at the end, as if its own method body were all straight-line synchronous code and every method call that completed had finished its work.

However, DownloadPhoto(url:) is asynchronous and returns immediately — so this approach won’t work.

Instead, downloadPhotosWithCompletion should call its own completion closure only after all the image download tasks have called their own completion closures. The question is: how do you monitor concurrent asynchronous events? You don’t know when they will complete, and they can finish in any order.

Perhaps you could write some hacky code that uses multiple Bool values to keep track of each download, but that doesn’t scale well, and frankly, it makes for pretty ugly code.

Fortunately, this type of multiple asynchronous completion monitoring is exactly what dispatch groups were designed for.

Dispatch Groups

Dispatch groups notify you when an entire group of tasks completes. These tasks can be either asynchronous or synchronous and can even be tracked from different queues. Dispatch groups also notify you in synchronous or asynchronous fashion when all of the group’s events are complete. Since items are being tracked on different queues, an instance of dispatch_group_t keeps track of the different tasks in the queues.

The GCD API provides two ways to be notified when all events in the group have completed.

The first one, dispatch_group_wait, is a function that blocks your current thread and waits until either all the tasks in the group have completed, or until a timeout occurs. This is exactly what you want in this case.

Open PhotoManager.swift and replace downloadPhotosWithCompletion with the following implementation:

func downloadPhotosWithCompletion(completion: BatchPhotoDownloadingCompletionClosure?) {
  dispatch_async(GlobalUserInitiatedQueue) { // 1
    var storedError: NSError!
    var downloadGroup = dispatch_group_create() // 2
 
    for address in [OverlyAttachedGirlfriendURLString,
                    SuccessKidURLString,
                    LotsOfFacesURLString]
    {
      let url = NSURL(string: address)
      dispatch_group_enter(downloadGroup) // 3
      let photo = DownloadPhoto(url: url!) {
        image, error in
        if let error = error {
          storedError = error
        }
        dispatch_group_leave(downloadGroup) // 4
      }
      PhotoManager.sharedManager.addPhoto(photo)
    }
 
    dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER) // 5
    dispatch_async(GlobalMainQueue) { // 6
      if let completion = completion { // 7
        completion(error: storedError)
      }
    }
  }
}

Taking each numbered comment in turn, you’ll see the following:

  1. Since you’re using the synchronous dispatch_group_wait which blocks the current thread, you use dispatch_async to place the entire method into a background queue to ensure you don’t block the main thread.
  2. This creates a new dispatch group which behaves somewhat like a counter of the number of uncompleted tasks.
  3. dispatch_group_enter manually notifies a group that a task has started. You must balance out the number of dispatch_group_enter calls with the number of dispatch_group_leave calls or else your app will crash.
  4. Here you manually notify the group that this work is done. Again, you’re balancing all group enters with an equal amount of group leaves.
  5. dispatch_group_wait waits until either all of the tasks are complete or until the time expires. If the time expires before all events complete, the function will return a non-zero result. You could put this into a conditional closure to check if the waiting period expired; however, in this case you specified for it to wait forever by supplying DISPATCH_TIME_FOREVER. This means, unsurprisingly, it’ll wait forever! That’s fine, because the completion of the photos creation will always complete.
  6. At this point, you are guaranteed that all image tasks have either completed or timed out. You then make a call back to the main queue to run your completion closure. This will append work onto the main thread to be executed at some later time.
  7. Finally, run the completion closure if one was supplied.

Build and run your app, attempt to download multiple images and notice how your app behaves with the completion closure in place.

Note: If the network activities occur too quickly to discern when the completion closure should be called and you’re running the app on a device, you can make sure this really works by toggling some network settings in the Developer Section of the Settings app. Just go to the Network Link Conditioner section, enable it, and select a profile. “Very Bad Network” is a good choice.

If you are running on the Simulator, you can use the Network Link Conditioner included in the Hardware IO Tools for Xcode to change your network speed. This is a good tool to have in your arsenal because it forces you to be conscious of what happens to your apps when connection speeds are less than optimal.

This solution is good so far, but in general it’s best to avoid blocking threads if at all possible. Your next task is to rewrite the same method to notify you asynchronously when all the downloads have completed.

Before we head on to another use of dispatch groups, here’s a brief guide on when and how to use dispatch groups with the various queue types:

  • Custom Serial Queue: This is a good candidate for notifications when a group of tasks completes.
  • Main Queue (Serial): This is a good candidate as well in this scenario. You should be wary of using this on the main queue if you are waiting synchronously for the completion of all work since you don’t want to hold up the main thread. However, the asynchronous model is an attractive way to update the UI once several long-running tasks finish, such as network calls.
  • Concurrent Queue: This as well is a good candidate for dispatch groups and completion notifications.

Dispatch Groups, Take Two

That’s all well and good, but it’s a bit clumsy to have to dispatch asynchronously onto another queue and then block using dispatch_group_wait. There’s another way…

Find downloadPhotosWithCompletion in PhotoManager.swift and replace it with this implementation:

func downloadPhotosWithCompletion(completion: BatchPhotoDownloadingCompletionClosure?) {
  // 1
  var storedError: NSError!
  var downloadGroup = dispatch_group_create()
 
  for address in [OverlyAttachedGirlfriendURLString,
                  SuccessKidURLString,
                  LotsOfFacesURLString]
  {
    let url = NSURL(string: address)
    dispatch_group_enter(downloadGroup)
    let photo = DownloadPhoto(url: url!) {
      image, error in
      if let error = error {
        storedError = error
      }
      dispatch_group_leave(downloadGroup)
    }
    PhotoManager.sharedManager.addPhoto(photo)
  }
 
  dispatch_group_notify(downloadGroup, GlobalMainQueue) { // 2
    if let completion = completion {
      completion(error: storedError)
    }
  }
}

Here’s how your new asynchronous method works:

  1. In this new implementation you don’t need to surround the method in a dispatch_async call since you’re not blocking the main thread.
  2. dispatch_group_notify serves as the asynchronous completion closure. This code executes when there are no more items left in the dispatch group and it’s the completion closure’s turn to run. You also specify on which queue to run your completion code. Here, the main queue is the one you want.

This is a much cleaner way to handle this particular job and doesn’t block any threads.

The Perils of Too Much Concurrency

With all of these new tools at your disposal, you should probably thread everything, right!?

Thread_All_The_Code_Meme

Take a look at downloadPhotosWithCompletion in PhotoManager. You might notice that there’s a for loop in there that cycles through three iterations and downloads three separate images. Your job is to see if you can run this for loop concurrently to try and speed it up.

This is a job for dispatch_apply.

dispatch_apply acts like a for loop which executes different iterations concurrently. This function is sychronous, so just like a normal for loop, dispatch_apply returns only when all of the work is done.

Care must be taken when figuring out the optimal amount of iterations for any given amount of work inside the closure, since many iterations and a small amount of work per iteration can create so much overhead that it negates any gains from making the calls concurrent. The technique known as striding helps you out here. This is where for each iteration you do multiple pieces of work.

When is it appropriate to use dispatch_apply?

  • Custom Serial Queue: A serial queue would completely negate the use of dispatch_apply; you might as well just use a normal for loop.
  • Main Queue (Serial): Just as above, using this on a serial queue is a bad idea. Just use a normal for loop.
  • Concurrent Queue: This is a good choice for concurrent looping, especially if you need to track the progress of your tasks.

Head back to downloadPhotosWithCompletion and replace it with the following implementation:

func downloadPhotosWithCompletion(completion: BatchPhotoDownloadingCompletionClosure?) {
  var storedError: NSError!
  var downloadGroup = dispatch_group_create()
  let addresses = [OverlyAttachedGirlfriendURLString,
                   SuccessKidURLString,
                   LotsOfFacesURLString]
 
  dispatch_apply(UInt(addresses.count), GlobalUserInitiatedQueue) {
    i in
    let index = Int(i)
    let address = addresses[index]
    let url = NSURL(string: address)
    dispatch_group_enter(downloadGroup)
    let photo = DownloadPhoto(url: url!) {
      image, error in
      if let error = error {
        storedError = error
      }
      dispatch_group_leave(downloadGroup)
    }
    PhotoManager.sharedManager.addPhoto(photo)
  }
 
  dispatch_group_notify(downloadGroup, GlobalMainQueue) {
    if let completion = completion {
      completion(error: storedError)
    }
  }
}

Your loop is now running concurrently; in the code above, in the call to dispatch_apply, you supply the amount of iterations with the first parameter, the queue to perform the tasks on in the second parameter and the closure action in the third parameter.

Be aware that although you have code that will add the photos in a thread safe manner, the ordering of the images could be different depending on which thread finishes first.

Build and run, then add some photos from Le Internet. Notice anything different?

Running this new code on the device will occasionally produce marginally faster results. But was all this work worth it?

Actually, it’s not worth it in this case. Here’s why:

  • You’ve probably created more overhead running the threads in parallel than just running the for loop in the first place. You should use dispatch_apply for iterating over very large sets along with the appropriate stride length.
  • Your time to create an app is limited — don’t waste time pre-optimizing code that you don’t know is broken. If you’re going to optimize something, optimize something that is noticeable and worth your time. Find the methods with the longest execution times by profiling your app in Instruments. Check out How to Use Instruments in Xcode to learn more.
  • Typically, optimizing code makes your code more complicated for yourself and for other developers coming after you. Make sure the added complication is worth the benefit.

Remember, don’t go crazy with optimizations. You’ll only make it harder on yourself and others who have to wade through your code.

Cancelling Dispatch Blocks

New in iOS 8 and OS X Yosemite is the introduction of dispatch block objects. These are implemented as a wrapper around ordinary closures and behave just like them. Dispatch block objects can do a number of things, like set a Quality of Service class per object for internal prioritization in a queue, but most notably is the ability to cancel the execution of block objects. Be aware that a block object can only be cancelled before it reaches the head of a queue and start executing.

Let’s demonstrate this by starting download tasks for several copies of images from Le Internet, and then cancelling some of them. Select PhotoManager.swift and replace downloadPhotosWithCompletion with the following:

func downloadPhotosWithCompletion(completion: BatchPhotoDownloadingCompletionClosure?) {
  var storedError: NSError!
  let downloadGroup = dispatch_group_create()
  var addresses = [OverlyAttachedGirlfriendURLString,
                   SuccessKidURLString,
                   LotsOfFacesURLString]
  addresses += addresses + addresses // 1
  var blocks: [dispatch_block_t] = [] // 2
 
  for i in 0 ..< addresses.count {
    dispatch_group_enter(downloadGroup)
    let block = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS) { // 3
      let index = Int(i)
      let address = addresses[index]
      let url = NSURL(string: address)
      let photo = DownloadPhoto(url: url!) {
        image, error in
        if let error = error {
          storedError = error
        }
        dispatch_group_leave(downloadGroup)
      }
      PhotoManager.sharedManager.addPhoto(photo)
    }
    blocks.append(block)
    dispatch_async(GlobalMainQueue, block) // 4
  }
 
  for block in blocks[3 ..< blocks.count] { // 5
    let cancel = arc4random_uniform(2) // 6
    if cancel == 1 {
      dispatch_block_cancel(block) // 7
      dispatch_group_leave(downloadGroup) // 8
    }
  }
 
  dispatch_group_notify(downloadGroup, GlobalMainQueue) {
    if let completion = completion {
      completion(error: storedError)
    }
  }
}
  1. The addresses array is expanded to hold three of each address.
  2. This array will hold the created block objects for later use.
  3. dispatch_block_create creates a new block object. The first parameter is a flag defining various block traits. The flag used here makes the block inherit its QoS class from the queue it is dispatched to. The second parameter is the block definition in the form of a closure.
  4. Here the block is dispatched asynchronously to the global main queue. For this example using the main queue makes it easier to cancel select blocks since it’s a serial queue. The code that sets up the dispatch blocks is already executing on the main queue so you are guaranteed that the download blocks will execute at some later time.
  5. The first three downloads are left alone, and the array is sliced to get the rest.
  6. arc4random_uniform provides an integer between 0 and an upper bound (not inclusive). By using 2 for the upper bound you get either a 0 or a 1, like a coin toss.
  7. If the random number is 1 the block is cancelled. That is, if the block is still in a queue and has not begun executing. Blocks can not be cancelled in the middle of execution.
  8. Since all blocks are added to the dispatch group, remember to remove the cancelled ones.

Build and run, and add images from Le Internet. You’ll see that the app now downloads three of each image and a random extra amount. The rest have been cancelled after being dispatched to a queue. This is a pretty contrived example but it illustrates how dispatch block objects are used and cancelled nicely.

Dispatch block objects can do a lot more, so be sure to check out the documentation.

Miscellaneous GCD Fun

But wait! There’s more! Here are some extra functions that are a little farther off the beaten path. Although you won’t use these tools nearly as frequently, they can be tremendously helpful in the right situations.

Testing Asynchronous Code

This might sound like a crazy idea, but did you know that Xcode has testing functionality? :] I know, sometimes I like to pretend it’s not there, but writing and running tests is important when building complex relationships in code.

Testing in Xcode is performed on subclasses of XCTestCase and runs any method in its method signature that begins with test. Testing is measured on the main thread, so you can assume that every test happens in a serial manner.

As soon as a given test method completes, XCTest methods will consider a test to be finished and move onto the next test. That means that any asynchronous code from the previous test will continue to run while the next test is running.

Networking code is usually asynchronous, since you don’t want to block the main thread while performing a network fetch. That, coupled with the fact that tests finish when the test method finishes, can make it hard to test networking code.

Let’s take a brief look at two common techniques for testing asynchronous code: one using semaphores and one using expectations.

Semaphores

Semaphores are an old-school threading concept introduced to the world by the ever-so-humble Edsger W. Dijkstra. Semaphores are a complex topic because they build upon the intricacies of operating system functions.

If you want to learn more about semaphores, check out this link which discusses semaphore theory in more detail. If you’re the academic type, a classic software development problem that uses semaphores is the Dining Philosophers Problem.

Semaphores lets you control the access of multiple consumers into a finite amount of resources. For example, if you created a semaphore with a pool of two resources, at most only two threads could access the critical section at the same time. Other items that want to use the resource must wait in a FIFO queue.

Open GooglyPuffTests.swift and replace downloadImageURLWithString with the following implementation:

func downloadImageURLWithString(urlString: String) {
  let url = NSURL(string: urlString)
  let semaphore = dispatch_semaphore_create(0) // 1
  let photo = DownloadPhoto(url: url!) {
    image, error in
    if let error = error {
      XCTFail("\(urlString) failed. \(error.localizedDescription)")
    }
    dispatch_semaphore_signal(semaphore) // 2
  }
 
  let timeout = dispatch_time(DISPATCH_TIME_NOW, DefaultTimeoutLengthInNanoSeconds)
  if dispatch_semaphore_wait(semaphore, timeout) != 0 { // 3
    XCTFail("\(urlString) timed out")
  }
}

Here’s how the semaphore works in the code above:

  1. Create the semaphore. The parameter indicates the value the semaphore starts with. This number is the number of things that can access the semaphore without having to have something increment it first (note that incrementing a semaphore is known as signalling it).
  2. In the completion closure you tell the semaphore that you no longer need the resource. This increments the semaphore count and signals that the semaphore is available to other resources that want it.
  3. This waits on the semaphore, with a given timeout. This call blocks the current thread until the semaphore has been signalled. A non-zero return code from this function means that the timeout was reached. In this case, the test is failed because it is deemed that the network should not take more than 10 seconds to return — a fair point!

Run your tests by selecting Product / Test from the menu or use ⌘+U if you have the default key bindings. They should all succeed in a timely manner.

Disable your connection and run the tests again; if you are running on a device, put it in airplane mode. If you’re running on the simulator then simply turn off your connection. The tests complete with a fail result, after 10 seconds. Great, it worked!

These are rather trivial tests, but if you are working with a server team then these basic tests can prevent a wholesome round of finger-pointing of who is to blame for the latest network issue.

Expectations

The XCTest framework provides another solution to the asynchronous code testing problem in the form of expectations. This feature lets you set up an expectation – something you expect will happen – and then start an asynchronous task. Then you can have the test runner wait until the asynchronous task marks the expectation as fulfilled.

Navigate to GooglyPuffTests.swift and replace downloadImageURLWithString with the following code:

func downloadImageURLWithString(urlString: String) {
  let url = NSURL(string: urlString)
  let downloadExpectation = expectationWithDescription("Image downloaded from \(urlString)") // 1
  let photo = DownloadPhoto(url: url!) {
    image, error in
    if let error = error {
      XCTFail("\(urlString) failed. \(error.localizedDescription)")
    }
    downloadExpectation.fulfill() // 2
  }
 
  waitForExpectationsWithTimeout(10) { // 3
    error in
    if let error = error {
      XCTFail(error.localizedDescription)
    }
  }
}

Here is how it works:

  1. Create the expectation with expectationWithDescription. The test runner will display the string parameter here in the test log upon failure, so describe what you expect to happen.
  2. Call fulfill in the closure that executes asynchronously to mark it as fulfilled.
  3. The calling thread waits for expectations to be fulfilled by calling waitForExpectationsWithTimeout. If the wait times out, that’s treated as an error.

Build and run the tests. The end result is not very different from using a semaphore, but leveraging the XCTest framework is a cleaner and more readable solution.

Working With Dispatch Sources

A particularly interesting feature of GCD is Dispatch Sources, which are basically a grab-bag of low-level functionality helping you to respond to or monitor Unix signals, file descriptors, Mach ports, VFS Nodes, and other obscure stuff. All of this is far beyond the scope of this tutorial, but you’ll get a small taste of it by implementing a dispatch source object and using it in a rather peculiar way.

First-time users of dispatch sources can get quite lost on how to use a source, so the first thing you need to understand how dispatch_source_create works. This is the function prototype for creating a source:

func dispatch_source_create(
  type: dispatch_source_type_t,
  handle: UInt,
  mask: UInt,
  queue: dispatch_queue_t!) -> dispatch_source_t!

The first parameter, type: dispatch_source_type_t, is the most important parameter as it dictates what the handle and mask parameters will be. You’ll need to refer to the Xcode documentation to see what options are available for each dispatch_source_type_t parameter.

Here you’ll be monitoring for DISPATCH_SOURCE_TYPE_SIGNAL. As the documentation says:

A dispatch source that monitors the current process for signals. The handle is a signal number (int). The mask is unused (pass zero for now).

A list of these Unix signals can found in the header file signal.h. At the top there are a bunch of #defines. From that list of signals, you will be monitoring the SIGSTOP signal. This signal is sent when a process receives an unavoidable suspend instruction. This is the same signal that’s sent when you debug your application using the LLDB debugger.

Go to PhotoCollectionViewController.swift and add the following code near viewDidLoad. You’ll want to add these two private properties to the class, and this new block of code at the beginning of viewDidLoad, after the call to the superclass but before the existing line that gets the ALAssetLibrary:

#if DEBUG
private var signalSource: dispatch_source_t!
private var signalOnceToken = dispatch_once_t()
#endif
 
override func viewDidLoad() {
  super.viewDidLoad()
 
  #if DEBUG // 1
  dispatch_once(&signalOnceToken) { // 2
    let queue = dispatch_get_main_queue()
    self.signalSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL,
                                               UInt(SIGSTOP), 0, queue) // 3
    if let source = self.signalSource { // 4
      dispatch_source_set_event_handler(source) { // 5
        NSLog("Hi, I am: \(self.description)")
      }
      dispatch_resume(source) // 6
    }
  }
  #endif
 
  // The other stuff
}

The code is a little involved, so step through the code one comment at a time to see what’s going on:

  1. It’s best to only compile this code while in DEBUG mode since this could give “interested parties” a lot of insight into your app. :] DEBUG is defined by adding -D DEBUG under Project Settings -> Build Settings -> Swift Compiler – Custom Flags -> Other Swift Flags -> Debug.
  2. Use dispatch_once to perform the dispatch source’s one-time setup.
  3. Here you instantiate the signalSource variable. You indicate that you’re interested in signal monitoring and provide the SIGSTOP signal as the second parameter. Additionally, you use the main queue for handling received events — you’ll discover why shortly.
  4. A dispatch source object won’t be created if you provide malformed parameters. As a result, you should make sure you have a valid dispatch source object before working on it.
  5. dispatch_source_set_event_handler registers an event handler closure that is invoked when you receive the signal you’re monitoring for.
  6. By default, all sources start in the suspended state. You must tell the source object to resume when you want to start monitoring for the events.

Build and run your app; pause in the debugger and resume the app immediately. Check out the console, and you’ll see something like this in the debugger:

2014-08-12 12:24:00.514 GooglyPuff[24985:5481978] Hi, I am: <GooglyPuff.PhotoCollectionViewController: 0x7b765ee0>

You app is now debugging-aware! That’s pretty awesome, but how would you use this in real life?

You could use this to debug an object and display data whenever you resume the app; you could also give your app custom security logic to protect itself (or the user’s data) when malicious attackers attach a debugger to your application.

An interesting idea is to use this approach as a stack trace tool to find the object you want to manipulate in the debugger.

What_Meme

Think about that situation for a second. When you stop the debugger out of the blue, you’re almost never on the desired stack frame. Now you can stop the debugger at anytime and have code execute at your desired location. This is very useful if you want to execute code at a point in your app that’s tedious to access from the debugger. Try it out!

Put a breakpoint on the NSLog statement in viewDidLoad in the event handler you just added. Pause in the debugger, then start again; the app will then hit the breakpoint you added. You’re now deep in the depths of your PhotoCollectionViewController method. Now you can access the instance of PhotoCollectionViewController to your heart’s content. Pretty handy!

Note: If you haven’t already noticed which threads are which in the debugger, take a look at them now. The main thread will always be the first thread followed by libdispatch, the coordinator for GCD, as the second thread. After that, the thread count and remaining threads depend on what the hardware was doing when the app hit the breakpoint.

In the debugger, type the following:

po self.navigationItem.prompt = "WOOT!"

Then resume execution of the app. You’ll see the following:

GooglyPuff_Swift_signal_break
GooglyPuff_Swift_woot

With this method, you can make updates to the UI, inquire about the properties of a class, and even execute methods — all while not having to restart the app to get into that special workflow state. Pretty neat.

Where to Go From Here?

You can download the final project here.

I hate to bang on this subject again, but you really should check out the How to Use Instruments tutorial. You’ll definitely need this if you plan on doing any optimization of your apps. Be aware that Instruments is good for profiling relative execution: comparing which areas of code takes longer in relation to other areas. If you’re trying to figure out the actual execution time of a method, you might need to come up with a more home-brewed solution.

Also check out How to Use NSOperations and NSOperationQueue Tutorial in Swift, a concurrency technology that is built on top of GCD. In general, it’s best practice to use GCD if you are using simple fire-and-forget tasks. NSOperations offers better control, an implementation for handling maximum concurrent operations, and a more object-oriented paradigm at the cost of speed.

Remember, unless you have a specific reason to go lower, always try and stick with a higher level API. Only venture into the dark arts of Apple if you want to learn more or to do something really, really “interesting”. :]

Good luck and have fun! Post any questions or feedback in the discussion below!

Grand Central Dispatch Tutorial for Swift: Part 2/2 is a post from: Ray Wenderlich

The post Grand Central Dispatch Tutorial for Swift: Part 2/2 appeared first on Ray Wenderlich.

Video Tutorial: Swift Scroll View School Part 3: Zooming

Video Tutorial: Swift Scroll View School Part 4: Centering

LiquidFun Tutorial with Metal and Swift – Part 2

$
0
0
Learn how to simulate water with LiquidFun and Metal!

Learn how to simulate water with LiquidFun and Metal!

Welcome back to our 2-part tutorial series that teaches you how to use LiquidFun with Metal and Swift!

In the first part of the series, you learned how to integrate LiquidFun with Swift and used that knowledge to create an invisible liquid particle system.

In this second part of the series, you’ll learn how to render your LiquidFun particles onscreen using projection transformations, uniform data and shaders in Metal. You’ll also get to move them around in a simulated physics world for some water-splashing fun.

After all, you didn’t name your project LiquidMetal for nothing.

Getting Started

First, make sure you have a copy of the project from Part 1, either by going through the first tutorial or by downloading the finished project.

Before proceeding with Metal, I recommend going through the Introduction to Metal Tutorial if you haven’t already. To keep this part short, I’ll breeze through the basic setup of Metal and focus only on new concepts that aren’t in the other Metal tutorials on our site.

Note: Metal apps don’t run on the iOS Simulator—they require a device with an Apple A7 chip or later. So to go through this tutorial, you’ll need an A7 device, which at the time of writing means an iPhone 5S, iPad Air or iPad mini (2nd generation), or an A8 device, which at the time of writing means an iPhone 6 or iPhone 6 Plus.

Create a Metal Layer

You first need to create a CAMetalLayer, which acts as the canvas upon which Metal renders content.

Inside ViewController.swift, add the following properties and new method:

var device: MTLDevice! = nil
var metalLayer: CAMetalLayer! = nil
 
func createMetalLayer() {
  device = MTLCreateSystemDefaultDevice()
 
  metalLayer = CAMetalLayer()
  metalLayer.device = device
  metalLayer.pixelFormat = .BGRA8Unorm
  metalLayer.framebufferOnly = true
  metalLayer.frame = view.layer.frame
  view.layer.addSublayer(metalLayer)
}
Note: If you get a compiler error at this point, make sure you set the app to target your Metal-compatible iOS device. As mentioned earlier, the iOS Simulator does not support Metal at the time of writing this tutorial, and Xcode won’t even let you compile Metal code without a valid target.

Now replace printParticleInfo() in viewDidLoad with a call to this new method:

createMetalLayer()

Inside createMetalLayer, you store a reference to an MTLDevice, which you’ll use later to create the other Metal objects that you’ll need. Next, you create a CAMetalLayer with default properties and add it as a sublayer to your current view’s main layer. You call createMetalLayer from viewDidLoad to ensure your Metal layer is set up along with the view.

Create a Vertex Buffer

The next step is to prepare a buffer that contains the positions of each particle in your LiquidFun world. Metal needs this information to know where to render your particles on the screen.

Still in ViewController.swift, add the following properties and new method:

var particleCount: Int = 0
var vertexBuffer: MTLBuffer! = nil
 
func refreshVertexBuffer () {
  particleCount = Int(LiquidFun.particleCountForSystem(particleSystem))
  let positions = LiquidFun.particlePositionsForSystem(particleSystem)
  let bufferSize = sizeof(Float) * particleCount * 2
  vertexBuffer = device.newBufferWithBytes(positions, length: bufferSize, options: nil)
}

Here you add two new properties, particleCount to keep track of how many particles you have, and vertexBuffer to store the MTLBuffer Metal requires to access the vertex positions.

Inside refreshVertexBuffer, you call LiquidFun.particleCountForSystem to get the number of particles in the system, and store the result in particleCount. Next, you use the MTLDevice to create a vertex buffer, passing in the position array directly from LiquidFun.particlePositionsForSystem. Since each position has an x- and y-coordinate pair as float types, you multiply the size in bytes of two Floats by the number of particles in the system to get the size needed to create the buffer.

Call this method at the end of viewDidLoad:

refreshVertexBuffer()

Now that you’ve given Metal access to your particles, it’s time to create the vertex shader that will work with this data.

Create a Vertex Shader

The vertex shader is the program that takes in the vertex buffer you just created and determines the final position of each vertex onscreen. Since LiquidFun’s physics simulation calculates the particle positions for you, your vertex shader only needs to translate LiquidFun particle positions to Metal coordinates.

Right-click the LiquidMetal group in the Project Navigator and select New File…, then select the iOS\Source\Metal File template and click Next. Enter Shaders.metal for the filename and click Create.

First, add the following structs to Shaders.metal:

struct VertexOut {
  float4 position [[position]];
  float pointSize [[point_size]];
};
 
struct Uniforms {
  float4x4 ndcMatrix;
  float ptmRatio;
  float pointSize;
};

You’ve defined two structs:

  1. VertexOut contains data needed to render each vertex. The [[position]] qualifier indicates that float4 position contains the position of the vertex onscreen, while the [[point_size]] qualifier indicates that float pointSize contains the size of each vertex. Both of these are special keywords that Metal recognizes, so it knows exactly what each property is for.
  2. Uniforms contains properties common to all vertices. This includes the points-to-meters ratio you used for LiquidFun (ptmRatio), the radius of each particle in the particle system (pointSize) and the matrix that translates positions from screen points to normalized device coordinates (ndcMatrix). More on this later.

Next is the shader program itself. Still in Shaders.metal, add this function:

vertex VertexOut particle_vertex(const device packed_float2* vertex_array [[buffer(0)]],
                                 const device Uniforms& uniforms [[buffer(1)]],
                                 unsigned int vid [[vertex_id]]) {
  VertexOut vertexOut;
  float2 position = vertex_array[vid];
  vertexOut.position = 
    uniforms.ndcMatrix * float4(position.x * uniforms.ptmRatio, position.y * uniforms.ptmRatio, 0, 1);
  vertexOut.pointSize = uniforms.pointSize;
  return vertexOut;
}

The shader’s first parameter is a pointer to an array of packed_float2 data types—a packed vector of two floats, commonly containing x and y position coordinates. Packed vectors don’t contain the extra bytes commonly used to align data elements in a computer’s memory. You’ll read more about that a bit later.

The [[buffer(0)]] qualifier indicates that vertex_array will be populated by the first buffer of data that you send to your vertex shader.

The second parameter is a handle to the Uniforms structure. Similarly, the [[buffer(1)]] qualifier indicates that the second parameter is populated by the second buffer of data sent to the vertex shader.

The third parameter is the index of the current vertex inside the vertex array, and you use it to retrieve that particular vertex from the array. Remember, the GPU calls the vertex shader many times, once for each vertex to render. For this app, the vertex shader will be called once per water particle to render.

Inside the shader, you get the vertex’s position in LiquidFun’s coordinate system, then convert it to Metal’s coordinate system and output it via vertexOut.

To understand how the final position is computed, you have to be aware of the different coordinate systems with which you’re working. Between LiquidFun and Metal, there are three different coordinate systems:

  • the physics world’s coordinate system;
  • the regular screen coordinate system; and
  • the normalized screen coordinate system.

Given a regular iPhone 5s screen (320 points wide by 568 points high), these translate to the following coordinate systems:

liquidmetal_coordinate_systems

  1. The screen coordinate system (red) is the easiest to understand and is what you normally use when positioning objects onscreen. It starts from (0, 0) at the bottom-left corner and goes up to the screen’s width and height in points at the upper-right corner.
  2. The physics world coordinate system (blue) is how LiquidFun sees things. Since LiquidFun operates in smaller numbers, you use ptmRatio to convert screen coordinates to physics world coordinates and back.
  3. The normalized device coordinate system (green) is Metal’s default coordinate system and is the trickiest to work with. While the previous two coordinate systems both agree that the origin (0, 0) is at the lower-left corner, Metal’s coordinate system places it at the center of the screen. The coordinates are device agnostic, so no matter the size of the screen, (-1,-1) is the lower-left corner and (1, 1) is the upper-right corner.

Since the vertex buffer contains vertices in LiquidFun’s coordinate system, you need to convert it to normalized device coordinates so it comes out at the right spot on the screen. This conversion happens in a single line:

vertexOut.position = 
  uniforms.ndcMatrix * float4(position.x * uniforms.ptmRatio, position.y * uniforms.ptmRatio, 0, 1);

You first convert the vertex to regular screen coordinates by multiplying the x- and y-positions by the points-to-meters ratio. You use these new values to create a float4 to represent XYZW coordinates. Finally, you multiply the XYZW coordinates by a “mathemagical” matrix that translates your coordinates to normalized screen coordinates using an orthographic projection. You’ll get acquainted with this matrix very soon.

Note: I won’t explain in depth what the z- and w-components are for. As far as this tutorial goes, you need these components to do 3D matrix math.

The z-component specifies how far or near the object is from the camera, but this doesn’t matter much when dealing with a 2D coordinate space. You need the w-component because matrix multiplication formulas work on 4×4 matrices. Long story short, the x-, y-, and z-components are divided by the w-component to get the final 3D coordinates. In this case, w is 1 so that the x-, y-, and z-components don’t change.

If you wish to learn more, you can read about homogeneous coordinates on Wikipedia for more information.

The NDC Projection Matrix

How you perceive and see objects on the screen depends on the type of projection transformation used to convert points to the normalized device coordinate system that Metal expects.

There are two general types of projection: perspective and orthographic.

Perspective projection gives you a realistic view of your objects because it scales them relative to their distance from a point of view. With this type of projection, the farther an object is from the viewer, the smaller it will appear.

As an example, take this perspective projection of four cubes and a square:

perspective

In the above graphic, you can tell that the two cubes at the top are farther away than the two cubes at the bottom, because they appear smaller. If these objects were rendered with an orthographic projection, you would get the following result:

orthographic

The four cubes look identical to the flat square. This is because orthographic projection discards depth of view, defined by the z-component of the coordinate system, and gives you a flat view of the world.

An object in orthographic projection only moves along the x- and y-axes, and you only see it according to its true size. This is perfect for 2D, so the next step is to create an orthographic projection matrix for your device.

Open ViewController.swift and add this method:

func makeOrthographicMatrix(#left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) -> [Float] {
  let ral = right + left
  let rsl = right - left
  let tab = top + bottom
  let tsb = top - bottom
  let fan = far + near
  let fsn = far - near
 
  return [2.0 / rsl, 0.0, 0.0, 0.0,
    0.0, 2.0 / tsb, 0.0, 0.0,
    0.0, 0.0, -2.0 / fsn, 0.0,
    -ral / rsl, -tab / tsb, -fan / fsn, 1.0]
}

This function is OpenGL’s way of creating an orthographic projection matrix. I simply copied this function out of the OpenGL library and converted it to Swift.

You don’t need to understand the math for this tutorial, just how to use it. This function takes as parameters the screen’s bounds in points and returns the corresponding orthographic projection matrix.

You plug in the following parameters:

  • left and right: The left- and right-most x-coordinates of the screen. As you saw in the earlier diagram, these values will be 0 for left and the screen’s width in points for right.
  • bottom and top: The bottom-most and top-most y-coordinates of the screen. Here bottom will be 0 and top will be the screen height in points.
  • near and far: The nearest and farthest z-coordinates. These values affect which z-coordinates are visible on the screen. In OpenGL, this means any z-coordinate between near and far is visible, but it’s a slightly different case with Metal. OpenGL’s normalized z-coordinate system ranges from -1 to 1, while Metal’s is only 0 to 1. Therefore, for Metal, you can compute the range of visible z-coordinates using this formula: -(far+near)/2 to -far. You’ll pass in near and far values of -1 to 1 in order to create the 0-to-1 range of visible z-coordinates that Metal expects.

Using these parameters, you generate a one-dimensional array that Metal will later use as a 4×4 matrix. That is, Metal will treat the array as values arranged in four rows of four columns each.

It’s important to note that when creating matrices, Metal populates each row of a column before moving on to the next column. The array you create in makeOrthographicMatrix is arranged in the following way in matrix form:

ortho_matrix_mapping

Starting from the top-most row of the left-most column, Metal populates each row of each column first before moving on to the next column.

Note: The math behind the deriving this matrix is beyond the scope of this tutorial. If you wish to learn more, this site on OpenGL Projection Matrices explains it thoroughly.

Create a Uniform Buffer

You’re all set to create the uniform buffer that the vertex shader needs. It’s the third and last component that controls the fate of your particles onscreen.

Still in ViewController.swift, add the following property and new method:

var uniformBuffer: MTLBuffer! = nil
 
func refreshUniformBuffer () {
  // 1
  let screenSize: CGSize = UIScreen.mainScreen().bounds.size
  let screenWidth = Float(screenSize.width)
  let screenHeight = Float(screenSize.height)
  let ndcMatrix = makeOrthographicMatrix(left: 0, right: screenWidth,
    bottom: 0, top: screenHeight,
    near: -1, far: 1)
  var radius = particleRadius
  var ratio = ptmRatio
 
  // 2
  let floatSize = sizeof(Float)
  let float4x4ByteAlignment = floatSize * 4
  let float4x4Size = floatSize * 16
  let paddingBytesSize = float4x4ByteAlignment - floatSize * 2
  let uniformsStructSize = float4x4Size + floatSize * 2 + paddingBytesSize
 
  // 3
  uniformBuffer = device.newBufferWithLength(uniformsStructSize, options: nil)
  let bufferPointer = uniformBuffer.contents()
  memcpy(bufferPointer, ndcMatrix, UInt(float4x4Size))
  memcpy(bufferPointer + float4x4Size, &ratio, UInt(floatSize))
  memcpy(bufferPointer + float4x4Size + floatSize, &radius, UInt(floatSize))
}

Creating the uniform buffer is tricky, because your Swift code isn’t aware of the Uniforms structure that you created in your Metal shader code. What’s more, Swift doesn’t have a native equivalent for the float4x4 type that Metal uses. So the approach you take is to populate this structure, without knowing what the structure is, by copying the values into memory yourself.

  1. First, you create the orthographic projection matrix, ndcMatrix, by supplying the screen’s dimensions to makeOrthographicMatrix. You also copy the constants particleRadius and ptmRatio as local variables for use later.
  2. Next, you compute for the size of the Uniforms struct in memory. As a refresher, take a second look at the structure’s definition:
    struct Uniforms {
      float4x4 ndcMatrix;
      float ptmRatio;
      float pointSize;
    };

    Since float4x4 consists of 16 floats, you may think that the size of Uniforms is equal to the total size of 18 floats, but that isn’t the case. Because of structure alignment, the compiler inserts extra bytes as padding to optimally align data members in memory. The amount of padding inserted depends on the byte alignment of its data members. With Uniforms as an example, you get the following byte alignments and sizes:

    uniforms_alignment

    With structure alignment, the total size of the structure must be a multiple of the largest byte alignment, which in this case is 16 bytes. An easy way to get the amount of padding needed is to subtract the smaller byte alignments from the largest byte alignment. By doing so, you get:

    uniforms_total

    With a padding of 8 bytes, you get a total of 80 bytes, and that’s what’s happening in this section of the code:

    let floatSize = sizeof(Float)
    let float4x4ByteAlignment = floatSize * 4
    let float4x4Size = floatSize * 16
    let paddingBytesSize = float4x4byteAlignment - floatSize * 2
    let uniformsStructSize = float4x4Size + floatSize * 2 + paddingBytesSize

    You get the sizes of each data member and compute for the padding size to get the total size of the struct.

  3. Finally, you create an appropriately sized empty buffer named uniformBuffer, and copy the contents of each data member one by one using memcpy.

motherofmath

Note: Have a look at the official Metal Shading Language documentation to learn more about the alignment and sizes of each data type.

Before moving on, add a call to refreshVertexBuffer at the end of viewDidLoad:

refreshUniformBuffer()

With the vertex shader in place, Metal will know where your particles are, but you still need a fragment shader to draw them.

Create a Fragment Shader

While the vertex shader determines the position of each vertex, the fragment shader determines the color of each visible fragment on the screen. You don’t need any fancy colors yet for this tutorial, so you’ll use a very simple fragment shader.

Add the following code to the bottom of Shaders.metal:

fragment half4 basic_fragment() {
  return half4(1.0);
}

You create a fragment shader that simply returns the color white using RGBA values of (1, 1, 1, 1). Expect to see white particles soon—but it will behave like water, not snow!

Build a Render Pipeline

You’re almost there! The rest of the steps should be familiar to you from the Metal Tutorial for Beginners.

Open ViewController.swift and add the following properties and new method:

var pipelineState: MTLRenderPipelineState! = nil
var commandQueue: MTLCommandQueue! = nil
 
func buildRenderPipeline() {
  // 1
  let defaultLibrary = device.newDefaultLibrary()
  let fragmentProgram = defaultLibrary?.newFunctionWithName("basic_fragment")
  let vertexProgram = defaultLibrary?.newFunctionWithName("particle_vertex")
 
  // 2
  let pipelineDescriptor = MTLRenderPipelineDescriptor()
  pipelineDescriptor.vertexFunction = vertexProgram
  pipelineDescriptor.fragmentFunction = fragmentProgram
  pipelineDescriptor.colorAttachments[0].pixelFormat = .BGRA8Unorm
 
  var pipelineError : NSError?
  pipelineState = device.newRenderPipelineStateWithDescriptor(pipelineDescriptor, error: &pipelineError)
 
  if (pipelineState == nil) {
    println("Error occurred when creating render pipeline state: \(pipelineError)");
  }
 
  // 3
  commandQueue = device.newCommandQueue()
}

And just like you did with the other setup methods, add a call to this new method at the end of viewDidLoad:

buildRenderPipeline()

Inside buildRenderPipeline, you do the following:

  1. You use the MTLDevice object you created earlier to access your shader programs. Notice you access them using their names as strings.
  2. You initialize a MTLRenderPipelineDescriptor with your shaders and a pixel format. Then you use that descriptor to initialize pipelineState.
  3. Finally, you create an MTLCommandQueue for use later. The command queue is the channel you’ll use to submit work to the GPU.

Render the Particles

The final step is to draw your particles onscreen.

Still in ViewController.swift, add the following method:

func render() {
  var drawable = metalLayer.nextDrawable()
 
  let renderPassDescriptor = MTLRenderPassDescriptor()
  renderPassDescriptor.colorAttachments[0].texture = drawable.texture
  renderPassDescriptor.colorAttachments[0].loadAction = .Clear
  renderPassDescriptor.colorAttachments[0].storeAction = .Store
  renderPassDescriptor.colorAttachments[0].clearColor =
    MTLClearColor(red: 0.0, green: 104.0/255.0, blue: 5.0/255.0, alpha: 1.0)
 
  let commandBuffer = commandQueue.commandBuffer()
 
  if let renderEncoder = commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor) {
    renderEncoder.setRenderPipelineState(pipelineState)
    renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, atIndex: 0)
    renderEncoder.setVertexBuffer(uniformBuffer, offset: 0, atIndex: 1)
 
    renderEncoder.drawPrimitives(.Point, vertexStart: 0, vertexCount: particleCount, instanceCount: 1)
    renderEncoder.endEncoding()
  }
 
  commandBuffer.presentDrawable(drawable)
  commandBuffer.commit()
}

Here, you create a render pass descriptor to clear the screen and give it a fresh tint of green. Next, you create a render command encoder that tells the GPU to draw a set of points, set up using the pipeline state and vertex and uniform buffers you created previously. Finally, you use a command buffer to commit the transaction to send the task to the GPU.

Now call render at the end of viewDidLoad:

render()

Build and run the app on your device to see your particles onscreen for the first time:

particles_first

Moving Water

Now is when most of your work from this tutorial and the last will pay off—getting to see the liquid simulation in action. Currently, you have nine water particles onscreen, but they’re not moving. To get them to move, you need to trigger the following events repeatedly:

  1. LiquidFun needs to update the physics simulation.
  2. Metal needs to update the screen.

Open LiquidFun.h and add this method declaration:

+ (void)worldStep:(CFTimeInterval)timeStep velocityIterations:(int)velocityIterations 
  positionIterations:(int)positionIterations;

Switch to LiquidFun.mm and add this method definition:

+ (void)worldStep:(CFTimeInterval)timeStep velocityIterations:(int)velocityIterations
  positionIterations:(int)positionIterations {
  world->Step(timeStep, velocityIterations, positionIterations);
}

You’re adding another Objective-C pass-through method for your wrapper class, this time for the world object’s Step method. This method advances the physics simulation forward by a measure of time called the timeStep.

velocityIterations and positionIterations affect the accuracy and performance of the simulation. Higher values mean greater accuracy, but at a greater performance cost.

Open ViewController.swift and add the following new method:

func update(displayLink:CADisplayLink) {
  autoreleasepool {
    LiquidFun.worldStep(displayLink.duration, velocityIterations: 8, positionIterations: 3)
    self.refreshVertexBuffer()
    self.render()
  }
}

Next, add the following code at the end of viewDidLoad:

let displayLink = CADisplayLink(target: self, selector: Selector("update:"))
displayLink.frameInterval = 1
displayLink.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

You’re creating a CADisplayLink that calls your new update method every time the screen refreshes. Then in update, you do the following:

  1. You ask LiquidFun to step through the physics simulation using the time interval between the last execution of update and the current execution, as represented by displayLink.duration.
  2. You tell the physics simulation to do eight iterations of velocity and three iterations of position. You are free to change these values to how accurate you want the simulation of your particles to be at every time step.
  3. After LiquidFun steps through the physics simulation, you expect all your particles to have a different position than before. You call refreshVertexBuffer() to repopulate the vertex buffer with the new positions.
  4. You send this updated buffer to the render command encoder to show the new positions onscreen.

Build and run, and watch your particles fall off the bottom of the screen:

particles_fall

That’s not quite the effect you’re looking for. You can prevent the particles from falling off by adding walls to your physics world, and to keep things interesting, you’ll also move the particles using the device accelerometer.

Open LiquidFun.h and add these method declarations:

+ (void *)createEdgeBoxWithOrigin:(Vector2D)origin size:(Size2D)size;
+ (void)setGravity:(Vector2D)gravity;

Switch to LiquidFun.mm and add these methods:

+ (void *)createEdgeBoxWithOrigin:(Vector2D)origin size:(Size2D)size {
  // create the body
  b2BodyDef bodyDef;
  bodyDef.position.Set(origin.x, origin.y);
  b2Body *body = world->CreateBody(&bodyDef);
 
  // create the edges of the box
  b2EdgeShape shape;
 
  // bottom
  shape.Set(b2Vec2(0, 0), b2Vec2(size.width, 0));
  body->CreateFixture(&shape, 0);
 
  // top
  shape.Set(b2Vec2(0, size.height), b2Vec2(size.width, size.height));
  body->CreateFixture(&shape, 0);
 
  // left
  shape.Set(b2Vec2(0, size.height), b2Vec2(0, 0));
  body->CreateFixture(&shape, 0);
 
  // right
  shape.Set(b2Vec2(size.width, size.height), b2Vec2(size.width, 0));
  body->CreateFixture(&shape, 0);
 
  return body;
}
 
+ (void)setGravity:(Vector2D)gravity {
  world->SetGravity(b2Vec2(gravity.x, gravity.y));
}

createEdgeBoxWithOrigin creates a bounding box shape, given an origin (located at the lower-left corner) and size. It creates a b2EdgeShape, defines the four corners of the shape’s rectangle and attaches it to a new b2Body.

setGravity is another pass-through method for the world object’s SetGravity method. You use it to change the current world’s horizontal and vertical gravities.

Switch to ViewController.swift and add the following import:

import CoreMotion

You’re importing the CoreMotion framework because you need it to work with the accelerometer. Now add the following property:

let motionManager: CMMotionManager = CMMotionManager()

Here you create a CMMotionManager to report on the accelerometer’s state.

Now, create the world boundary by adding the following line inside viewDidLoad, before the call to createMetalLayer:

LiquidFun.createEdgeBoxWithOrigin(Vector2D(x: 0, y: 0), 
  size: Size2D(width: screenWidth / ptmRatio, height: screenHeight / ptmRatio))

This should prevent particles from falling off the screen.

Finally, add the following code at the end of viewDidLoad:

motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue(), 
  withHandler: { (accelerometerData, error) -> Void in
  let acceleration = accelerometerData.acceleration
  let gravityX = self.gravity * Float(acceleration.x)
  let gravityY = self.gravity * Float(acceleration.y)
  LiquidFun.setGravity(Vector2D(x: gravityX, y: gravityY))
})

Here, you create a closure that receives updates from CMMotionManager whenever there are changes to the accelerometer. The accelerometer contains 3D data on the current device’s orientation. Since you’re only concerned with 2D space, you set the world’s gravity to the x- and y-values of the accelerometer.

Build and run, and tilt your device to move the particles:

moving_particles

The particles will slide around, and with a bit of imagination you can see them as water droplets!

Producing More Water

Now you can go crazy by adding more particles. But with a bounding box constraining your particles to the screen, you don’t want to add too many, or you’ll risk having an unstable simulation.

Open LiquidFun.h and declare the following method:

+ (void)setParticleLimitForSystem:(void *)particleSystem maxParticles:(int)maxParticles;

Switch to LiquidFun.mm and add the method’s implementation:

+ (void)setParticleLimitForSystem:(void *)particleSystem maxParticles:(int)maxParticles {
  ((b2ParticleSystem *)particleSystem)->SetDestructionByAge(true);
  ((b2ParticleSystem *)particleSystem)->SetMaxParticleCount(maxParticles);
}

This method sets a maximum particle limit for a particle system. You enable SetDestructionByAge so that the oldest particles get destroyed first when you exceed the amount of allowable particles in SetMaxParticleCount.

Next, switch to ViewController.swift and add the following line in viewDidLoad, right after the call to LiquidFun.createParticleSystemWithRadius:

LiquidFun.setParticleLimitForSystem(particleSystem, maxParticles: 1500)

This line sets a limit for the particle system you created so that you won’t be able to create more than 1500 particles at any given time.

Now add this method to handle touches:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
  for touch in touches {
    let touchLocation = touch.locationInView(view)
    let position =
      Vector2D(x: Float(touchLocation.x) / ptmRatio, y: Float(view.bounds.height - touchLocation.y) / ptmRatio)
    let size = Size2D(width: 100 / ptmRatio, height: 100 / ptmRatio)
    LiquidFun.createParticleBoxForSystem(particleSystem, position: position, size: size)
  }
}

Here you implement touchesBegan, the method that gets called when the user taps the screen. When called, the method creates a particle box that is 100 points wide by 100 points high at the location of the touch.

Build and run, and tap the screen repeatedly to produce more particles:

more_particles

Have fun!

Cleaning up After Yourself

Since LiquidFun runs on C++ and isn’t covered by Swift’s automatic reference counting, you have to make sure to clean up your world object after you’re done with it. This can be done in a few easy steps. As usual, you start with some LiquidFun wrapper methods.

Open LiquidFun.h and declare this method:

+ (void)destroyWorld;

Quickly switch to LiquidFun.mm and add the following code:

+ (void)destroyWorld {
  delete world;
  world = NULL;
}

You’re adding a method that deletes the world object you create in createWorldWithGravity. All accompanying particle systems and physics bodies inside the world will be deleted along with it.

You need to call this method the moment you no longer need your physics simulation to run. For now, since the whole simulation is running in ViewController, you’ll delete it only when ViewController ceases to exist.

Open ViewController.swift and add this method:

deinit {
  LiquidFun.destroyWorld()
}

Swift automatically deallocates the ViewController instance when it’s no longer needed. When this happens, Swift calls its deinitializer method, deinit. This is the perfect place to do some additional clean up yourself, so you clean up the physics world using the wrapper method you just added.

Where to Go From Here?

Here is the final sample project from this tutorial series.

Congratulations! You’ve just learned how to simulate water using LiquidFun. Not only that—you’ve learned how to render your own particle system using Metal and Swift. I’m not sure if you feel the same way, but I’m left with a thirst (pun intended) for more learning!

From here, you can work on improving your simulation further by implementing more of LiquidFun’s features. Here are some of the fun things you can still do:

  1. Implement and show particle colors and multiple particle systems.
  2. Mix the colors of particles that collide, similar to the behavior in LiquidSketch.
  3. Map textures to your particle system.
  4. Add advanced shader effects for better-looking water.

Do let me know if you’d like to see more tutorials in this series covering the advanced topics above. In the meantime, you can head over to the LiquidFun Programmer’s Guide to learn more.

If you have questions, comments or suggestions on the tutorial, please join the forum discussion below!

LiquidFun Tutorial with Metal and Swift – Part 2 is a post from: Ray Wenderlich

The post LiquidFun Tutorial with Metal and Swift – Part 2 appeared first on Ray Wenderlich.

Video Tutorial: Swift Scroll View School Part 5: Storyboards and Auto Layout


Video Tutorial: Swift Scroll View School Part 6: Nested Scroll Views

Video Tutorial: Swift Scroll View School Part 7: Content Insets I

Video Tutorial: Swift Scroll View School Part 8: Content Insets II

Video Tutorial: Swift Scroll View School Part 9: Keyboard Insets

Video Tutorial: Swift Scroll View School Part 10: Paging Scroll Views I

Video Tutorial: Swift Scroll View School Part 11: Paging Scroll Views II

Reminder: Free Live Tech Talk (WatchKit) Tomorrow (Tuesday)!

$
0
0
Free live tech talk (WatchKit) tomorrow!

Free live tech talk (WatchKit) tomorrow!

This is a reminder that we are having a free live tech talk on WatchKit tomorrow (Tuesday Jan 13, and you’re all invited! Here are the details:

  • When: Tuesday, Jan 13 at 2:00 PM EST – 3:00 PM EST
  • What: WatchKit Tech Talk/Demo followed by live Q&A (come w/ questions!)
  • Who: Ben Morrow (Tutorial Team member and WatchKit by Tutorials author)
  • Where: Google Hangouts Event Page
  • Why: For learning and fun!
  • How: Visit the event page and a video URL should be posted. Follow the instructions there to submit your Q&A (via text) as the talk runs.

We hope to see some of you at the tech talk, and we hope you enjoy!

Reminder: Free Live Tech Talk (WatchKit) Tomorrow (Tuesday)! is a post from: Ray Wenderlich

The post Reminder: Free Live Tech Talk (WatchKit) Tomorrow (Tuesday)! appeared first on Ray Wenderlich.


Video Tutorial: Swift Scroll View School Part 12: UIPageViewController

Secure Your App’s Passwords with Safari AutoFill in iOS 8

$
0
0

title_img

Safari AutoFill in iOS 8 is a brilliant new feature, but before we get into what it does, do any of the following scenarios sound familiar?

  • An app requires you to create a new password, and you proceed to type in your cat’s name, as you’ve done with every single site and app you’ve ever used.
  • You already have an account with a website when you download their app. You’d like to keep your account consistent, but you can’t remember which email address you used to create it, or what the password is.
  • An app requires that new passwords contain at least 99 characters, with at least one letter, five non-sequential numbers and a prime number of punctuation symbols, excluding ! and *.

Those scenarios are incredibly annoying for any user, and that’s crucial to consider as an app developer. Every insecure password is a liability, and every outlandish password requirement is motivation for a user to simply uninstall your amazing app.

Decreasing friction around passwords is not optional in regards to user-retention, yet, I would argue that you have a responsibility as a developer to help your users stay secure. Hackers and abusers are constantly staging attacks on activists, celebrities and John Q. Public. But fear not, Safari AutoFill in iOS 8 to the rescue!

In iOS 8, you can easily allow your users to:

  • Save app passwords using Safari AutoFill
  • Share and synchronize passwords between your website and your app
  • Generate secure passwords

This article will show you how to implement these capabilities in your app, and you can follow along using a sample project that contains Swift, HTML and Python code.

Note: There are two important security-related prerequisites for linking a website to an app:

  1. You must own a domain with an SSL certificate. The price varies based from web host to web host, so check with your preferred choice for their pricing.
  2. An iOS Developer Program membership ($99 per year)

Getting Started

For this exercise, you’ll use a very simple website and corresponding iOS app called Ultra Motivator that provides an authenticated user with a motivational quote. Sadly, unauthenticated users will not find on demand inspiration through this app.

Note: This article is written in such a way that you can read through it without using the sample project if you’d prefer. The sample code is simply there as a reference :]

Clone or download the sample project from GitHub.

First, you’ll notice the code is divided into 3 directories:

  • web: contains 3 simple webpages that use Python to access a MySQL database, plus a very short CSS file. These pages allow users to sign up, sign in and update a password.
  • api: contains 3 API endpoints, again in Python, to expose the same database functionality to the app in JSON format.
  • ios: contains a Swift project for iOS that accesses the API endpoints and makes use of Safari AutoFill features.

Once you’ve finished poking around in the sample project, the next step is to tell iOS to link the passwords from the website to the app!

The Website: Permissions

Since this whole concept is about being more secure, you must take specific steps to tell iOS to allow a specific domain and a certain app to share passwords.

On the website, you use an SSL-signed file populated with a simple JSON list of valid Bundle IDs that you want to allow AutoFill to access.

Ultra Motivator’s JSON looks like this:

{"webcredentials":{"apps":["F47X5999MK.com.upDownInteractive.UltraMotivator"]}}

You could put several Bundle IDs in the apps array if you like:

{"webcredentials":{"apps":["F47X5999MK.com.upDownInteractive.UltraMotivator","F47X5999MK.com.upDownInteractive.AnotherApp"]}}

Note that each Bundle ID includes the Team ID prefix, which is provided and enforced by Apple when you enter the iOS Developer Program. You can find your prefix in the Member Center, by selecting Certificates, Identifiers & Profiles, then Identifiers, and then selecting an App ID, as shown here:

team_id

Once your Bundle ID is ready, create a file that contains only the JSON. You can do this in the Terminal by entering the following command:

echo '{"webcredentials":{"apps":["F47X5999MK.com.upDownInteractive.UltraMotivator"]}}' > json.txt

Next, you need to sign this file with your website’s SSL Certificate. Once you’ve purchased one, you can either install it yourself or ask your host to do it on your behalf.

Note: SSL Certificates are all the rage in security, and it looks like they will continue to be a big deal for some time. If you’re not already, get up to speed on how they work. Some suggested places to start are: Wikipedia, Mozilla Developer Network, the OpenSSL project, and Namecheap.

To sign your JSON file, prepare the following resources:

  • Your correctly-formatted JSON in a file (Ex: json.txt)
  • Your private key (Ex: mattluedke.com.key). If your web host installed your SSL certificate, check your domain’s dashboard for this key. Your private key is secret to you (don’t share it!), and ensures your identity as the domain owner. It should look something like this:
  • -----BEGIN RSA PRIVATE KEY-----
    XXXXXXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXXXXXXXXXX
    -----END RSA PRIVATE KEY-----
  • Signing certificate in PEM format (Ex: mattluedke.com.pem) If your web host installed your SSL certificate, you will also find this in your domain’s dashboard. It is the public counterpart to your private key, and clients use this key to verify that a signed file came from your domain. It should look like this:
  • -----BEGIN CERTIFICATE-----
    XXXXXXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXXXXXXXXXX
    -----END CERTIFICATE-----
  • Additional keys in PEM format (Ex: intermediate.pem)

Note: At its core, the SSL signing command relies on trust. You need to provide keys that create a chain of trust linking your domain to the trusted Certificate Authority (CA) that issued your SSL certificate. Use your CA’s publicly available certificate (Ex: GeoTrust_Global_CA.pem) to signify the source of your certificate.

When ready, open up your Terminal and execute the following command (substituting your own domain name, of course):

cat json.txt | openssl smime -sign -inkey mattluedke.com.key
                              -signer mattluedke.com.pem
                              -certfile intermediate.pem
                              -noattr -nodetach
                              -outform DER > apple-app-site-association

This command ensures that this file has definitely come from you and isn’t corrupted by a “man in the middle” attack. Any Bundle IDs that the client sees listed in that JSON will be allowed to share passwords with your domain.

Note: It’s important that you use the exact filename apple-app-site-association as this is the file that iOS will be looking for.

Once you have the output, upload it directly to your domain’s root directory. For example, the associations file for my domain is located at:

https://mattluedke.com/apple-app-site-association

And that concludes the first half of the password-sharing scheme. Now onto the app itself.

iOS: Permissions

With your Bundle IDs uploaded to your domain, the whole world can now see your Team ID and any apps that can share passwords. So how do you prevent someone from creating an app with one of those Bundle IDs and obtaining access?

Well, you’re going to use a provisioning process and code signature for your app to prevent such meddling.

You’ll certify who you are, via Apple, when you create your app, to prove the following:

  1. That your app will be using the Associated Domains capability.
  2. That your Team ID is, in fact, valid.

Sign into Apple’s Developer Portal.

In Member Center, select Certificates, Identifiers & Profiles

certs_and_profiles

From that screen, click on Identifiers\App IDs. If you’ve already created an App ID for this app, select the correct App ID from the list and click the Edit button, or create a new one with the Add button.

If creating a new App ID, check the box for Associated Domains under App Services like this:

app_services

If you are editing an existing App ID, the interface looks like this:

editing_associated_domains

When you’re done, you’ll see Associated Domains activated for your App ID:

associated_domains_enabled

Then, click Provisioning Profiles, and create, download and install a new profile for that App ID (for a refresher on your way around Provisioning Profiles, check out the tutorial How to Submit Your App to Apple: From No Account to App Store, Part 1).

Once you’ve created, downloaded and installed a valid provisioning profile, you’ll tell Xcode to use the Associated Domain capability in your Swift project.

Open your Swift project in Xcode and navigate to your Target. Then click Capabilities and scroll down until you see the option for Associated Domains.

Turn the switch ON to activate the capability, and then click the + to add your domain to the list. The listing must be in the following format:

webcredentials:mattluedke.com

Once this is done, you’ll see the domain listed and the capability all ready to go, like this:

xcode_capabilities

It’s very important that your App ID, as specified in your Xcode project, matches perfectly with the App ID in the Member Center. Otherwise, you’ll see an error like this:

Screen Shot 2014-12-21 at 1.49.28 PM

You may also notice a new file has been created in your project with the .entitlements extension. Inside the file is the data you just entered, but in a slightly different form:

entitlements_file

This is the Entitlements File that iOS uses as a checklist against your code signing identity and provisioning profile.

And with that, you’re all ready to move on to coding the rest in Swift.

AutoFill your UITextFields

First, you’ll address the case where the user already has an account on your website. Imagine how thrilled they’ll be when the app magically knows their account, even when they open it for the very first time.

ragecomic

In Ultra Motivator, this is accomplished in SafariKeychainManager. It contains the following class method that you can use in your own project:

class func checkSafariCredentialsWithCompletion(completion: ((username: String?, password: String?) 
    -> Void)) {
 
  let domain: CFString = "mattluedke.com"
 
  SecRequestSharedWebCredential(domain, .None, {
      (credentials: CFArray!, error: CFError?) -> Void in
 
    if let error = error {
      println("error: \(error)")
      completion(username: nil, password: nil)
    } else if CFArrayGetCount(credentials) > 0 {
      let unsafeCred = CFArrayGetValueAtIndex(credentials, 0)
      let credential: CFDictionaryRef = unsafeBitCast(unsafeCred, CFDictionaryRef.self)
      let dict: Dictionary<String, String> = credential as Dictionary<String, String>
      let username = dict[kSecAttrAccount as String]
      let password = dict[kSecSharedPassword.takeRetainedValue() as String]
      dispatch_async(dispatch_get_main_queue()) {
        completion(username: username, password: password)
      }
    } else {
      dispatch_async(dispatch_get_main_queue()) {
        completion(username: nil, password: nil)
      }
    }
  });
}

This method centers around SecRequestSharedWebCredential, which asks the device’s store of saved passwords for any relevant credentials it might be allowed to use. It has this signature:

func SecRequestSharedWebCredential(fqdn: CFString!, account: CFString!, completionHandler: ((CFArray!, CFError!) -> Void)!)

As you can see, this method takes three parameters:

  1. (Optional) fqdn: A fully qualified domain name for which you’d like to request credentials. If you pass .None here, the app simply checks all the domains listed in your entitlements file. Being explicit is not necessary here, but may help if you have different domains for development and production versions of an app.
  2. (Optional) account: If there is a specific account for which you’d like to request credentials, put it in here. You can also pass .None to make the app check for any valid credentials.
  3. completionHandler: A block that will deliver either a CFArray! or a CFError! after the request for credentials is done.

Here are the CFError possibilities you may receive in the completion block:

  • No domain provided — you don’t have to provide a domain, but if you do and there are no domains in the entitlements file, you’ll receive this.
  • not found in com.apple.developer.associated-domains entitlement — if you provide a domain, but it’s not in the entitlements file, you’ll get this.
  • no matching items found — if the device’s saved passwords don’t contain any credentials that match both the optional domain and account, or the user chooses not to use any of them, you will receive this.
  • no matching items found — you’ll also see this if you’re trying to access a domain that has not been properly associated with the app.

Note: These errors are described in the WWDC ’14 session Your App, Your Website, and Safari, but in practice they don’t always match up with original specifications. To be safe, check the entire domain association process when you receive an error, until Apple stabilizes the API.

But if you do receive some credentials, they will come in the form of either CFArrayRef or CFDictionaryRef objects. Unfortunately, the API won’t return credential objects, so you’ll have to extract the information you need with the CFDictionaryRef keys:

  • kSecAttrServer: value is a CFStringRef that contains the website.
  • kSecAttrAccount: value is a CFStringRef that contains the account.
  • kSecSharedPassword: value is a CFStringRef that contains the password.

Note: The keys kSecAttrServer and kSecAttrAccount are both instances of CFStringRef, but kSecSharedPassword but is a CFTypeRef.

Now that you have this information, you can call your completion block and include the username and password, wrapping the call in dispatch_async(dispatch_get_main_queue()) {} so it’s guaranteed to be called on the main thread.

This way, the AutoFill-related code stays in SafariKeychainManager, and some other class, say a view controller, will handle what comes next.

For example, in Ultra Motivator checkSafariCredentialsWithCompletion is called in LoginViewController:

SafariKeychainManager.checkSafariCredentialsWithCompletion({
  (username: String?, password: String?) -> Void in
  switch(username, password) {
  case let (.Some(username), .Some(password)):
    self.userNameField.text = username
    self.passwordField.text = password
    self.makeSignInRequest(false)
  default:
    break
  }
})

This block calls checkSafariCredentialsWithCompletion to check for credentials. If you receive something valid for username and password, you fill in the relevant text fields and proceed with a sign-in request — all without the user having to type a single thing.

Time to try it out! In the case where you’ve already navigated to the correct website in Safari, created an account and save the password, the credentials will show up on your device in Settings\Safari\Passwords & AutoFill\Saved Passwords, as shown here:

saved_password

Then, you’ll see a prompt to sign in with your credentials even if you’ve never opened the app before — provided you associated the app and website as outlined earlier in this article.

Note that SecRequestSharedWebCredential constructs the alert and handles the user input for you (and your user).

autofilled_signin

For many of your lucky future users, tapping OK is the only action they’ll ever need to take in-order to authenticate. Pretty amazing stuff!

Inserting, Updating and Deleting Credentials

Now that you’ve added the capability to read saved credentials, it’s time to complete the suite of CRUD operations. This will be especially valuable if a user starts with your app, but then later decides to use the website, or vice-versa.

In this case, you’ll offer AutoFill in reverse. That is, they’ll be able to sign right in, even if they’ve never visited before.

In Ultra Motivator, this is again accomplished in SafariKeychainManager:

class func updateSafariCredentials(username: String, password: String) {
 
  let domain: CFString = "mattluedke.com"
 
  SecAddSharedWebCredential(domain,
      username as CFString,
      countElements(password) > 0 ? password as CFString : .None,
      {(error: CFError!) -> Void in
        println("error: \(error)")
      }
  );
}

Credential creating, updating and deleting all take place in SecAddSharedWebCredential:

func SecAddSharedWebCredential(fqdn: CFString!, account: CFString!, password: CFString!, 
    completionHandler: ((CFError!) -> Void)!)

A break down of the parameters:

  • fqdn: The fully qualified domain name for which you’d like to perform the operation.
  • account: Account name.
  • password: Password to be inserted or updated. Warning: passing .None here deletes the credential.
  • completionHandler: A completion block that passes back a CFError if anything goes wrong.

Conveniently, SecAddSharedWebCredential supplies the necessary alert based on the context, and it also handles the user input. All you need to include in your view controller is a call to updateSafariCredentials, like so:

SafariKeychainManager.updateSafariCredentials(username, password: password)

For example, when inserting a credential for the first time, as in SignupViewController, the operation simply executes without alerting the user.

When updating an existing credential, as in UpdateViewController, you’ll see the following confirmation alert:

update_password

And when removing an existing credential, as in HomeViewController, you’ll see the following confirmation:

delete_password

With your SafariKeychainManager complete, your users will have a fully synchronized and secure experience when authenticating with both your app and your website!

Bonus Points: Auto-generating Secure Passwords

Instead of demanding that users perform keyboard acrobatics on what is such a small keyboard, you can generate a secure password for them with a single line by using: SecCreateSharedWebCredentialPassword.

The password generated will be 12 (uppercase or lowercase) letters and numbers, delimited with dashes, similar to this: 7nD-ft4-RCm-4M8.

Ultra Motivator offers to generate a password for the user when they create a new account in SignupViewController or update their password in UpdateViewController.

SecCreateSharedWebCredentialPassword returns an Unmanaged<CFString>!, and an example implementation would look something akin to this:

@IBAction private func promptForPassword(sender: AnyObject) {
  showPasswordGenerationDialog({
    let password = SecCreateSharedWebCredentialPassword().takeUnretainedValue()
    self.passwordField.text = password
    self.confirmPasswordField.text = password
    self.makeSignUpRequest()
  })
}

generate_password

If the user chooses OK from the dialog, then they get a shiny new password. It’s then placed in the relevant text fields and a sign-up request is fired-off.

Since you already arranged for AutoFill to remember this password, it’s not a problem that most humans would grapple with memorizing it. That’s right, there’ll be no hassle for you or your users!

Optional: Autocomplete Values For Safari AutoFill

Time to shift gears back to the web side of things. There are a few tiny, optional updates to your HTML that make it a little easier for Safari AutoFill to determine when to save your users’ passwords.

Use these three values for the autocomplete attribute to signal your intent to Safari:

<input type="text" autocomplete="username">
<input type="password" autocomplete="current-password">
<input type="password" autocomplete="new-password">

You can see the autocomplete="username" attribute in action on all three pages of Ultra Motivator: the Signup, Signin and Update pages. It directs Safari AutoFill to save that input field’s info as the username.

Ultra Motivator uses the autocomplete="current-password" attribute on the Signin and Update pages. Safari AutoFill will now always attempt to fill this field.

Finally, the Signup and the Update pages use the autocomplete="new-password" attribute. Safari AutoFill should offer to save the contents of these fields. You can use the value more than once if you want the user to confirm their password.

Note: At the time of this writing, the new-password value in particular does not work as described in the WWDC ’14 session video.

Presumably, the Safari development team is still tweaking its functionality. In the meantime, the username and current-password values work, and you should implement the new-password value now so your page will be ready the moment Safari is.

Try It Out

You can test out the web interface right now on an iOS device or the simulator. Use these Ultra Motivator pages as examples:

Notice how Safari offers to save your password after you sign in. Who made that a reality? Oh, yeah, YOU did that.

safari_offer

Save a new set of credentials for your own pages, and then try to open your associated app and signing in for the first time. As if there was a wizard inside your computer conjuring up a password spell, the credentials are waiting for you on the app.

Now try going the other direction. Create a new account in your app, and then visit your website’s sign in page. AutoFill already knows your new credentials there too.

fill_password

If you used an auto-generated password, then the only typing you’ll have to do is to create a username. From there, you can generate a secure password and sign into your app and website in but a few taps.

It’s a good idea to test out both of these scenarios, as well as the password update scenario, and look for any edge cases. Things to look out for:

  1. The domains expected by AutoFill in both web and app contexts need to precisely match. Even a small difference can cause credentials to get lost or become out-of-sync across platforms.
  2. If you’re in the middle of developing your app and make changes to entitlements or AutoFill-related code, you may have to remove the app from your device and re-install.

Note: When the user enables iCloud Keychain, the entire AutoFill process is even powerful as it enables password synchronization across all of you iCloud-enabled devices.

Where To Go From Here?

Feel free to use the sample code available in the Ultra Motivator repository.

If you’d like more information about sign-on services and password management on iOS, be sure to check out this WWDC 2014 session:

Also, the Ultra Motivator Swift project uses Alamofire, a popular open-source networking library. For more information on how to use it effectively, see our Beginning Alamofire Tutorial.

As always, but especially since this is a new feature and Apple’s Swift documentation for it is lacking, please make use of the comments below and our forums if you have any questions, comments or interesting new ways to use AutoFill.

Thank you for reading through this article. With your new skills, you can make using your brilliant apps easier to use and more secure than ever, and that’ll in turn lead to happier users, better reviews, and a uncanny feeling of technical awesomeness.

Secure Your App’s Passwords with Safari AutoFill in iOS 8 is a post from: Ray Wenderlich

The post Secure Your App’s Passwords with Safari AutoFill in iOS 8 appeared first on Ray Wenderlich.

WatchKit Tech Talk Video

$
0
0

Each month, one of the members of the team gives a Tech Talk, and by popular request we also stream these live.

Today in our January Tech Talk, tutorial team member Ben Morrow gave an excellent talk and Q&A on WatchKit.

Here’s the video for anyone who didn’t get a chance to attend live!

Helpful Links

Here are some handy links related to the talk:

Want to Join Us Next Month?

Thanks again to Ben for giving a great talk and Q&A, having the guts to present to a live audience :] And thank you to everyone who attended – we hope you enjoyed it!

Next month’s tech talk will be announced soon – we’ll post it on the sidebar of the site later, so be sure to check for it later.

Hope to see some of you there! :]

WatchKit Tech Talk Video is a post from: Ray Wenderlich

The post WatchKit Tech Talk Video appeared first on Ray Wenderlich.

Video Tutorial: Swift Scroll View School Part 13: Slide-out Sidebar I

Video Tutorial: Swift Scroll View School Part 14: Slide-out Sidebar II

Viewing all 4373 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>