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

Swift Tutorial: Initialization In Depth, Part 1/2

$
0
0

initialization-feature

Some things are inherently awesome: rockets, missions to Mars, initialization in Swift. This tutorial combines all three for a combo-platter of awesomeness in which you’ll get to learn about the power of initialization!

Initialization in Swift is about what happens when you create a new instance of a named type:

let number = Float()

Initialization is the time to manage the inital values of stored properties for named types: classes, structures, and enumerations. Because of the safety features built into Swift, initialization can be tricky. There are a lot of rules, some of which are not obvious.

By following this two-part tutorial, you will learn the ins and outs to designing initializers for your Swift types. In Part 1, you’ll begin with the basics including structure initialization, and in Part 2 you’ll move on to learning about class initialization.

Before getting started, you should be familiar with the basics of initialization in Swift and be comfortable with concepts such as optional types, throwing and handling errors, and declaring default stored property values. Also, make sure you have Xcode 7.2 or later installed.

If you need a refresher on the basics, or if you are just starting to learn Swift, check out our book Swift Apprentice or our many Swift intro tutorials.

Getting Started

Let’s set the scene: it’s your first day on your new job as a launch software engineer at NASA (go you!). You’ve been tasked with designing the data model that will drive the launch sequence for the first manned mission to Mars, Mars Unum. Of course, the first thing you do is convince the team to use Swift. Then …

Open Xcode and create a new playground named BlastOff. You can select any platform, since the code in this tutorial is platform-agnostic and depends only on Foundation.

Throughout the tutorial, remember this one golden rule: You cannot use an instance until it is fully initialized. “Use” of an instance includes accessing properties, setting properties and calling methods. Everything in Part 1 applies specifically to structures unless otherwise specified.

Banking on the Default Initializer

To start modeling the launch sequence, declare a new structure named RocketConfiguration in your playground:

struct RocketConfiguration {
 
}

Below the closing curly brace of the definition for RocketConfiguration, initialize a constant instance named athena9Heavy:

let athena9Heavy = RocketConfiguration()

This uses a default initializer to instantiate athena9Heavy. In the default initializer, the name of the type is followed by empty parentheses. You can use default initializers when your types either don’t have any stored properties, or all of the type’s stored properties have default values. This holds true for both structures and classes.

Add the following three stored properties inside the struct definition:

let name: String = "Athena 9 Heavy"
let numberOfFirstStageCores: Int = 3
let numberOfSecondStageCores: Int = 1

Notice how the default initializer still works. The code continues to run because all the stored properties have default values. That means the default initializer doesn’t have very much work to do since you’ve provided defaults!

What about optional types? Add a variable stored property named numberOfStageReuseLandingLegs to the struct definition:

var numberOfStageReuseLandingLegs: Int?

In our NASA scenario, some of the rockets are reusable, while others are not. That’s why numberOfStageReuseLandingLegs is an optional Int. The default initializer continues to run fine because optional stored property variables are initialized to nil by default. However, that’s not the case with constants.

Change numberOfStageReuseLandingLegs from a variable to a constant:

let numberOfStageReuseLandingLegs: Int?

Notice how the playground reports a compiler error:

You won’t run into this often, since constant optionals are rarely needed. To fix the compiler error, assign a default value of nil to numberOfStageReuseLandingLegs:

let numberOfStageReuseLandingLegs: Int? = nil

Hooray! The compiler is happy again, and initialization succeeds. With this setup, numberOfStageReuseLandingLegs will never have a non-nil value. You cannot change it after initialization, since it is declared as a constant.

Banking on the Memberwise Initializer

Rockets are usually made up of several stages, which is the next thing to model. Declare a new struct named RocketStageConfiguration at the bottom of the playground:

struct RocketStageConfiguration {
  let propellantMass: Double
  let liquidOxygenMass: Double
  let nominalBurnTime: Int
}

This time, you have three stored properties propellantMass, liquidOxygenMass and nominalBurnTime with no default values.

Create an instance of RocketStageConfiguration for the rocket’s first stage:

let stageOneConfiguration = RocketStageConfiguration(propellantMass: 119.1,
  liquidOxygenMass: 276.0, nominalBurnTime: 180)

None of RocketStageConfiguration‘s stored properties have default values. Also, there is no initializer implemented for RocketStageConfiguration. Why isn’t there a compiler error? Swift structures (and only structures) automatically generate a memberwise initializer. This means you get a ready-made initializer for all the stored properties that don’t have default values. This is super handy, but there are several gotchas.

Imagine you submit this snippet for code review and your developer team lead tells you all properties should be ordered alphabetically.

Update the RocketStageConfiguration to re-order the stored properties:

struct RocketStageConfiguration {
  let liquidOxygenMass: Double
  let nominalBurnTime: Int
  let propellantMass: Double
}

What happened? The stageOneConfiguaration initializer call is no longer valid, because the automatic memberwise initializer argument list’s order mirrors that of the stored property list. Be careful, because when re-ordering structure properties, you might break instance initialization. Thankfully the compiler should catch the error, but it is definitely something to watch out for.

Undo the stored property re-order change to get the playground compiling and running again:

struct RocketStageConfiguration {
  let propellantMass: Double
  let liquidOxygenMass: Double
  let nominalBurnTime: Int
}

All your rockets burn for 180 seconds, so it’s not useful to pass the nominal burn time every time you instantiate a stage configuration. Set nominalBurnTime‘s default property value to 180:

let nominalBurnTime: Int = 180

Now there’s another compiler error:

Compilation fails because memberwise initializers only provide parameters for stored properties without default values. In this case, the memberwise initializer only takes in propellant mass and liquid oxygen mass, since there is already a default value for burn time.

Remove nominalBurnTime‘s default value so that there is no compiler error.

let nominalBurnTime: Int

Next, add a custom initializer to the struct definition that provides a default value for burn time:

init(propellantMass: Double, liquidOxygenMass: Double) {
  self.propellantMass = propellantMass
  self.liquidOxygenMass = liquidOxygenMass
  self.nominalBurnTime = 180
}

Notice that the same compiler error is back on stageOneConfiguration!

Wait, shouldn’t this work? All you did was provide an alternative initializer, but the original stageOneConfiguration initialization should work because it’s using the automatic memberwise initializer. This is where it gets tricky: you only get a memberwise initializer if a structure does not define any initializers. As soon as you define an initializer, you lose the automatic memberwise initializer.

In other words, Swift will help you out to start. But as soon as you add your own initializer, it assumes you want it to get out of the way.

Remove the nominalBurnTime argument from stageOneConfiguration‘s initialization:

let stageOneConfiguration = RocketStageConfiguration(propellantMass: 119.1,
  liquidOxygenMass: 276.0)

All is good again! :]

But what if you still need the automatic memberwise initializer? You can certainly write the equivalent initializer, but that’s a lot of work. Instead, move the custom initializer into an extension before you instantiate an instance.

Your struct will now be in two parts: the main definition, and an extension with your two-parameter initializer:

struct RocketStageConfiguration {
  let propellantMass: Double
  let liquidOxygenMass: Double
  let nominalBurnTime: Int
}
 
extension RocketStageConfiguration {
  init(propellantMass: Double, liquidOxygenMass: Double) {
    self.propellantMass = propellantMass
    self.liquidOxygenMass = liquidOxygenMass
    self.nominalBurnTime = 180
  }
}

Notice how stageOneConfiguration continues to initialize successfully with two parameters. Now re-add the nominalBurnTime parameter to stageOneConfiguration‘s initialization:

let stageOneConfiguration = RocketStageConfiguration(propellantMass: 119.1,
  liquidOxygenMass: 276.0, nominalBurnTime: 180)

That works too! If the main struct definition doesn’t include any initializers, Swift will still automatically generate the default memberwise initializer. Then you can add your custom ones via extensions to get the best of both worlds.

Implementing a Custom Initializer

Weather plays a key role in launching rockets, so you’ll need to address that in the data model. Declare a new struct named Weather as follows:

struct Weather {
  let temperatureCelsius: Double
  let windSpeedKilometersPerHour: Double
}

The struct has stored properties for temperature in degrees Celsius and wind speed in kilometers per hour.

Implement a custom initializer for Weather that takes in temperature in degrees Fahrenheit and wind speed in miles per hour. Add this code below the stored properties:

init(temperatureFahrenheit: Double, windSpeedMilesPerHour: Double) {
  self.temperatureCelsius = (temperatureFahrenheit - 32) / 1.8
  self.windSpeedKilometersPerHour = windSpeedMilesPerHour * 1.609344
}

Defining a custom initializer is very similar to defining a method, because an initializer’s argument list behaves exactly the same as a method’s. For example, you can define a default argument value for any of the initializer parameters.

Change the definition of the initializer to:

init(temperatureFahrenheit: Double = 72, windSpeedMilesPerHour: Double = 5) {
...

Now if you call the initializer with no parameters, you’ll get some sensible defaults. At the end of your playground file, create an instance of Weather and check its values:

let currentWeather = Weather()
currentWeather.temperatureCelsius
currentWeather.windSpeedKilometersPerHour

Cool, right? The default initializer uses the default values provided by the custom initializer. The implementation of the custom initializer converts the values into metric system equivalents and stores the values. When you check the values of the stored properties in the playground sidebar, you’ll get the correct values in degrees Celsius (22.2222) and kilometers per hour (8.047).

An initializer must assign a value to every single stored property that does not have a default value, or else you’ll get a compiler error. Remember that optional variables automatically have a default value of nil.

Next, change currentWeather to use your custom initializer with new values:

let currentWeather = Weather(temperatureFahrenheit: 87, windSpeedMilesPerHour: 2)

As you can see, custom values work just as well in the initializer as default values. The playground sidebar should now show 30.556 degrees and 3.219 km/h.

That’s how you implement and call a custom initializer. Your weather struct is ready to contribute to your mission to launch humans to Mars. Good work!

Mars: not just for Matt Damon

Mars: not just for Matt Damon

Avoiding Duplication with Initializer Delegation

It’s time to think about rocket guidance. Rockets need fancy guidance systems to keep them flying perfectly straight. Declare a new structure named GuidanceSensorStatus with the following code:

struct GuidanceSensorStatus {
  var currentZAngularVelocityRadiansPerMinute: Double
  let initialZAngularVelocityRadiansPerMinute: Double
  var needsCorrection: Bool
 
  init(zAngularVelocityDegreesPerMinute: Double, needsCorrection: Bool) {
    let radiansPerMinute = zAngularVelocityDegreesPerMinute * 0.01745329251994
    self.currentZAngularVelocityRadiansPerMinute = radiansPerMinute
    self.initialZAngularVelocityRadiansPerMinute = radiansPerMinute
    self.needsCorrection = needsCorrection
  }
}

This struct holds the rocket’s current and initial angular velocity for the z-axis (how much it’s spinning). The struct also keeps track of whether or not the rocket needs a correction to stay on its target trajectory.

The custom initializer holds important business logic: how to convert degrees per minute to radians per minute. The initializer also sets the initial value of the angular velocity to keep for reference.

You’re happily coding away when the guidance engineers show up. They tell you that a new version of the rocket will give you an Int for needsCorrection instead of a Bool. The engineers say a positive integer should be interpreted as true, while zero and negative should be interpreted as false. Your team is not ready to change the rest of the code yet, since this change is part of a future feature. So how can you accommodate the guidance engineers while still keeping your structure definition intact?

No sweat — add the following custom initializer below the first initializer:

init(zAngularVelocityDegreesPerMinute: Double, needsCorrection: Int) {
  let radiansPerMinute = zAngularVelocityDegreesPerMinute * 0.01745329251994
  self.currentZAngularVelocityRadiansPerMinute = radiansPerMinute
  self.initialZAngularVelocityRadiansPerMinute = radiansPerMinute
  self.needsCorrection = (needsCorrection > 0)
}

This new initializer takes an Int instead of a Bool as the final parameter. However, the needsCorrection stored property is still a Bool, and you set correctly according to their rules.

After you write this code though, something inside tells you there must be a better way. There’s so much repetition of the rest of the initializer code! And if there’s a bug in the calculation of the degrees to radians conversion, you’ll have to fix it in multiple places — an avoidable mistake. This is where initializer delegation comes in handy.

Replace the initializer you just wrote with the following:

init(zAngularVelocityDegreesPerMinute: Double, needsCorrection: Int) {
  self.init(zAngularVelocityDegreesPerMinute: zAngularVelocityDegreesPerMinute,
   needsCorrection: (needsCorrection > 0))
}

This initializer is a delegating initializer and, exactly as it sounds, it delegates initialization to another initializer. To delegate, just call any other initializer on self.

Delegate initialization is useful when you want to provide an alternate initializer argument list but you don’t want to repeat logic that is in your custom initializer. Also, using delegating initializers helps reduce the amount of code you have to write.

To test the initializer, instantiate a variable named guidanceStatus:

let guidanceStatus = GuidanceSensorStatus(zAngularVelocityDegreesPerMinute: 2.2, needsCorrection: 0)
guidanceStatus.currentZAngularVelocityRadiansPerMinute // 0.038
guidanceStatus.needsCorrection // false

The playground should compile and run, and the two values you checked for the guidanceStatus properties will be in the sidebar.

One more thing — you’ve been asked to provide another initializer that defaults needsCorrection to false. That should be as easy as creating a new delegating initializer and setting the needsCorrection property inside before delegating initialization. Try adding the following initializer to the struct, and note that it won’t compile.

init(zAngularVelocityDegreesPerMinute: Double) {
  self.needsCorrection = false
  self.init(zAngularVelocityDegreesPerMinute: zAngularVelocityDegreesPerMinute,
    needsCorrection: self.needsCorrection)
}

Compilation fails because delegating initializers cannot actually initialize any properties. There’s a good reason for this: the initializer you are delegating to could very well override the value you’ve set, and that’s not safe. The only thing a delegating initializer can do is manipulate values that are passed into another initializer.

Knowing that, remove the new initializer and give the needsCorrection argument of the main initiaziler a default value of false:

init(zAngularVelocityDegreesPerMinute: Double, needsCorrection: Bool = false) {

Update guidanceStatus‘s initialization by removing the needsCorrection argument:

let guidanceStatus = GuidanceSensorStatus(zAngularVelocityDegreesPerMinute: 2.2)
guidanceStatus.currentZAngularVelocityRadiansPerMinute // 0.038
guidanceStatus.needsCorrection // false

👍 Way to go! Now you can put those DRY (Don’t Repeat Yourself) principles into practice.

Introducing Two-Phase Initialization

So far, the code in your initializers have been setting up your properties and calling other initializers. That’s the first phase of initialization, but there are actually two phases to initializing a Swift type.

Phase 1 starts at the beginning of initialization and ends once all stored properties have been assigned a value. The remaining initialization execution is phase 2. You cannot use the instance you are initializing during phase 1, but you can use the instance during phase 2. If you have a chain of delegating initializers, phase 1 spans the call stack up to the non-delegating initializer. Phase 2 spans the return trip from the call stack.

Struct2PhaseInit

Putting Two-Phase Initialization to Work

Now that you understand two-phase initialization, let’s apply it to our scenario. Each rocket engine has a combustion chamber where fuel is injected with oxidizer to create a controlled explosion that propels the rocket. Setting up these parameters is the phase 1 part to prepare for blastoff.

Implement the following CombustionChamberStatus struct to see Swift’s two-phase initialization in action. Make sure to show Xcode’s Debug area to see the output of the print statements.

struct CombustionChamberStatus {
  var temperatureKelvin: Double
  var pressureKiloPascals: Double
 
  init(temperatureKelvin: Double, pressureKiloPascals: Double) {
    print("Phase 1 init")
    self.temperatureKelvin = temperatureKelvin
    self.pressureKiloPascals = pressureKiloPascals
    print("CombustionChamberStatus fully initialized")
    print("Phase 2 init")
  }
 
  init(temperatureCelsius: Double, pressureAtmospheric: Double) {
    print("Phase 1 delegating init")
    let temperatureKelvin = temperatureCelsius + 273.15
    let pressureKiloPascals = pressureAtmospheric * 101.325
    self.init(temperatureKelvin: temperatureKelvin, pressureKiloPascals: pressureKiloPascals)
    print("Phase 2 delegating init")
  }
}
 
CombustionChamberStatus(temperatureCelsius: 32, pressureAtmospheric: 0.96)

You should see the following output in the Debug Area:

Phase 1 delegating init
Phase 1 init
CombustionChamberStatus fully initialized
Phase 2 init
Phase 2 delegating init

As you can see, phase 1 begins with the call to the delegating initializer init(temperatureCelsius:pressureAtmospheric:) during which self cannot be used. Phase 1 ends right after self.pressureKiloPascals gets assigned a value in the non-delegating initializer. Each initializer plays a role during each phase.

Isn’t the compiler super crazy smart? It knows how to enforce all these rules. At first, those rules might seem like nuisances, but remember that they provide a ton of safety.

What if Things Go Wrong?

You’ve been told the launch sequence will be fully autonomous, and that the sequence will perform a ton of tests to make sure all systems are good to go for launch. If an invalid value is passed into an initializer, the launch system should be able to know and react.

There are two ways to handle initialization failures in Swift: using failable initializers, and throwing from an initializer. Initialization can fail for many reasons, including invalid input, a missing system resource such as a file, and possible network failures.

Using Failable Initializers

There are two differences between normal initializers and failable initializers. One is that failable initializers return optional values, and the other is that failable initializers can return nil to express an initialization failure. This can be very useful — let’s apply it to the rocket’s tanks in our data model.

Each rocket stage carries two large tanks; one holds fuel, while the other holds oxidizer. To keep track of each tank, implement a new struct named TankStatus as follows:

struct TankStatus {
  var currentVolume: Double
  var currentLiquidType: String?
 
  init(currentVolume: Double, currentLiquidType: String?) {
    self.currentVolume = currentVolume
    self.currentLiquidType = currentLiquidType
  }
}
 
let tankStatus = TankStatus(currentVolume: 0.0, currentLiquidType: nil)

There’s nothing wrong with this code except that it doesn’t recognize failure. What happens if you pass in a negative volume? What if you pass in a positive volume value but no liquid type? These are all failure scenarios. How can you model these situatons using failable initializers?

Start by changing TankStatus‘s initializer to a failable initializer by appending a ? to init:

init?(currentVolume: Double, currentLiquidType: String?) {

Option-click on tankStatus and notice how the initializer now returns an optional TankStatus.

Update tankStatus‘s instantiation to match the following:

if let tankStatus = TankStatus(currentVolume: 0.0, currentLiquidType: nil) {
  print("Nice, tank status created.") // Printed!
} else {
  print("Oh no, an initialization failure occured.")
}

The instantiation logic checks for failure by evaluating whether the returned optional contains a value or not.

Of course, there’s something missing: the initializer isn’t actually checking for invalid values yet. Update the failable initializer to the following:

init?(currentVolume: Double, currentLiquidType: String?) {
  if currentVolume < 0 {
    return nil
  }
  if currentVolume > 0 && currentLiquidType == nil {
    return nil
  }
  self.currentVolume = currentVolume
  self.currentLiquidType = currentLiquidType
}

As soon as an invalid input is detected, the failable initializer returns nil. You can return nil at any time within a structure’s failable initializer. This is not the case with a class’s failable initializer, as you’ll see in Part 2 of this tutorial.

To see instantiation failure, pass an invalid value into tankStatus‘s instantiation:

if let tankStatus = TankStatus(currentVolume: -10.0, currentLiquidType: nil) {

Notice how the playground prints, “Oh no, an initialization failure occurred.” Because initialization failed, the failable initializer returned a nil value and the if let statement executed the else clause.

Throwing From an Initializer

Failable initializers are great when returning nil is an option. For more serious errors, the other way to handle failure is throwing from an initializer.

You have one last structure to implement: one to represent each astronaut. Start by writing the following code:

struct Astronaut {
  let name: String
  let age: Int
 
  init(name: String, age: Int) {
    self.name = name
    self.age = age
  }
}

The manager tells you an astronaut should have a non-empty String for his or her name property and should have an age ranging from 18 to 70.

To represent possible errors, add the following error enumeration before the implementation of Astronaut:

enum InvalidAstronautDataError: ErrorType {
  case EmptyName
  case InvalidAge
}

The enumeration cases here cover the possible problems you might into when initializing a new Astronaut instance.

Next, replace the the Astronaut initializer with the following implementation:

init(name: String, age: Int) throws {
  if name.isEmpty {
    throw InvalidAstronautDataError.EmptyName
  }
  if age < 18 || age > 70 {
    throw InvalidAstronautDataError.InvalidAge
  }
  self.name = name
  self.age = age
}

Note that the initializer is now marked as throws to let callers know to expect errors.

If an invalid input value is detected — either an empty string for the name, or an age outside the acceptable range — the initializer will now throw the appropriate error.

Try this out by instantiating a new astronaut:

let johnny = try? Astronaut(name: "Johnny Cosmoseed", age: 42)

This is exactly how you handle any old throwing method or function. Throwing initializers behave just like throwing methods and functions. You can also propagate throwing initializer errors, and handle errors with a docatch statement. Nothing new here.

To see the initializer throw an error, change johnny‘s age to 17:

let johnny = try? Astronaut(name: "Johnny Cosmoseed", age: 17) // nil

When you call a throwing initializer, you write the try keyword — or the try? or try! variations — to identify that it can throw an error. In this case, you use try? so the value returned in the error case is nil. Notice how the value of johnny is nil. Seventeen is too young for spaceflight, sadly. Better luck next year, Johnny!

To Fail or to Throw?

Initializing using a throwing initializer and try? looks an awful lot like initializing with a failable initializer. So which should you use?

Consider using throwing throwing initializers. Failable initializers can only express a binary failure/success situation. By using throwing initializers you can not only indicate failure, but also indicate a reason by throwing specific errors. Another benefit is that calling code can propagate any errors thrown by an initializer.

Failable initializers are much simpler though, since you don’t need to define an error type and you can avoid all those extra try? keywords.

Why does Swift even have failable initializers? Because the first version of Swift did not include throwing functions, so the language needed a way to manage initialization failures.

Progress is what gets us to Mars, so we can grow rocks.

Progress is what gets us to Mars, so we can grow rocks.

Where To Go From Here?

Wow — you’re not only halfway through getting humans to Mars, you’re now a Swift structure initialization guru! You can download the final playground for Part 1 here.

To learn all about Swift class initialization, carry on to Part 2 of this tutorial.

You can find more information about initialization in the initialization chapter of Apple’s The Swift Programming Language guide. If you have any questions or comments, please join the discussion in the forum below!

The post Swift Tutorial: Initialization In Depth, Part 1/2 appeared first on Ray Wenderlich.


Swift Tutorial: Initialization In Depth, Part 2/2

$
0
0

initialization-feature

In Part 1 of this tutorial, you learned about initialization in Swift and applied it by creating a launch sequence data module for a manned NASA mission to Mars. You implemented initializers for structs, tried initializer delegation, and learned when and why to use failable and throwable initializers.

But there’s more to learn, and NASA still needs your help! In this second part of the tutorial, you’ll learn about class initialization in Swift. Class initialization is very different from class initialization in Objective-C, and when writing class initializers in Swift for the first time, you’ll encounter many different compiler errors. This tutorial walks you through potential issues and gives you all the understanding necessary to avoid these compiler errors.

In this part of the tutorial, you’ll:

  • see the initializer delegation equivalent for classes,
  • learn the extra rules about failable and throwable initialization for classes,
  • learn how classes delegate initialization up the class hierarchy, and
  • learn how classes inherit initializers

Make sure to complete Part 1 first, because here you’ll build on what you learned there.

Getting Started

You can either continue working in the playground from Part 1, or create a new playground. The code in this part doesn’t depend on any code from Part 1, but Foundation is required for this tutorial, so make sure the playground imports Foundation. Importing UIKit or AppKit meets this requirement.

Failing or Throwing from Class Initializers

The countdown to Mars continues! In the first part, you learned about failable and throwing initializers, and now you’ll see how that process differs for class initializers.

The launch system needs a way to represent the launch site, so start by implementing the following class:

class LaunchSite {
  let name: String
  let coordinates: (String, String)
 
  init(name: String, coordinates: (String, String)) {
    self.name = name
    self.coordinates = coordinates
  }
}

LaunchSite is a simple two-property class with a basic initializer. coordinates is declared as a tuple of two string values.

To improve the initializer, try changing the initializer to a failable initializer by checking if any of the string values are empty.

init?(name: String, coordinates: (String, String)) {
  guard !name.isEmpty && !coordinates.0.isEmpty && !coordinates.1.isEmpty else {
    return nil
  }
  self.name = name
  self.coordinates = coordinates
}

Note that this will not compile.

SwiftInitClassError2

The initializer above would be a-ok if LaunchSite was declared as a struct. But unlike structs, classes will not let you return nil or throw during Phase 1 of initialization. This means that every single stored property must be given an initial value first.

Note: This will probably be fixed in a future version of Swift; now that Swift is open source, you can already see the change with the commit message “Add support for early return from designated initializers.” in the repository!

To fix the compiler error, move the guard statement to the end of the initializer:

init?(name: String, coordinates: (String, String)) {
  self.name = name
  self.coordinates = coordinates
 
  guard !name.isEmpty && !coordinates.0.isEmpty && !coordinates.1.isEmpty else {
    return nil
  }
}

Now the return nil gets called in Phase 2 of initialization. This is an easy fix because you have values passed in that you can set regardless of success or failure. However, it’s not always this easy. Sometimes on failure you don’t have values to set, so following this rule can be less than ideal — especially if you have a class with a lot of stored properties. Later in this tutorial, you’ll work through an example that demonstrates a streamlined way of handling this situation.

As you can see, unlike the Objective-C compiler, the Swift compiler cares a lot about the order in which things occur within class initializers. This is just one of many potential compiler errors you will learn to avoid.

via ESA

You’ll learn to avoid asteroids too. Image credit: ESA

Initializer Delegation

Lift-off to Mars is only a year away! You’ve completed all but one very important task before you can ship the launch systems code: you need to implement models that represent different rocket components. Specifically, the tanks that hold rocket fuel and liquid oxygen.

Along the way, you’ll see the difference in how initializer delegation works with classes.

Designated Initializers

Add the RocketComponent class to the end of your playground:

class RocketComponent {
  let model: String
  let serialNumber: String
  let reusable: Bool
 
  // Init #1a - Designated
  init(model: String, serialNumber: String, reusable: Bool) {
    self.model = model
    self.serialNumber = serialNumber
    self.reusable = reusable
  }
}

RocketComponent is another simple class. It has three constant stored properties and a designated initializer.

Remember delegating initializers from Part 1 of this tutorial? Recall that a chain of delegating initializers eventually ends by a call to a non-delegating initializer. In the world of classes, a designated initializer is just a fancy term for a non-delegating initializer. Just like with structures, these initializers are responsible for providing initial values to all non-optional stored properties declared without a default value.

The comment “// Init #1a – Designated” is not required, but as you go further in this tutorial, these types of comments will help keep your initializers organized.

At the bottom of the playground, write the following code to see the designated initializer in action:

let payload = RocketComponent(model: "RT-1", serialNumber: "234", reusable: false)

Convenience Initializers

What about delegating initializers? They have a fancy name too in the world of classes :]. Implement the following convenience initializer within RocketComponent:

// Init #1b - Convenience
convenience init(model: String, serialNumber: String) {
  self.init(model: model, serialNumber: serialNumber, reusable: false)
}

Notice how this looks just like a structure’s delegating initializer. The only difference here is that you have to prefix the declaration with the convenience keyword.

At the end of the playground, use the convenience initializer to create another instance of RocketComponent:

let fairing = RocketComponent(model: "Serpent", serialNumber: "0")

Similar to how they work with structs, convenience initializers let you have simpler initializers that just call through to a designated initializer.

Failing and Throwing Strategy

There’s an art to designing failable and throwing initializers — thankfully, it doesn’t require paint. At first, you might find yourself writing code that’s difficult to read, so below are some strategies to maximize your failable and throwing initializer legibility.

Failing and Throwing from Designated Initializers

Let’s say that all rocket components in this mission report their model and serial number as a formatted string: the model followed by a hyphen followed by the serial number. For example, “Athena-003”. Implement a new RocketComponent failable designated initializer that takes in this formatted identifier string.

// Init #1c - Designated
init?(identifier: String, reusable: Bool) {
  let identifierComponents = identifier.componentsSeparatedByString("-")
  guard identifierComponents.count == 2 else {
    return nil
  }
  self.reusable = reusable
  self.model = identifierComponents[0]
  self.serialNumber = identifierComponents[1]
}

You get an error.

SwiftInitClassError2

This is how someone might build this initializer, yet this version does not compile. Remember, you cannot fail or throw without first setting all stored properties to an initial value.

Last time, we solved this by simply moving the guard statement to the end. Try it here:

// Init #1c - Designated
init?(identifier: String, reusable: Bool) {
  let identifierComponents = identifier.componentsSeparatedByString("-")
  self.reusable = reusable
  self.model = identifierComponents[0]
  self.serialNumber = identifierComponents[1]
 
  guard identifierComponents.count == 2 else {
    return nil
  }
}

That looks pretty good, but you’re checking for the number of components after you use them! If there aren’t enough components, it’s possible that identifierComponents[1] won’t exist and you’ll be trying to access something out of bounds in the array, leading to a runtime trap.

Fix the initializer by reorganizing the logic flow as follows:

// Init #1c - Designated
init?(identifier: String, reusable: Bool) {
  self.reusable = reusable
 
  let identifierComponents = identifier.componentsSeparatedByString("-")
  guard identifierComponents.count == 2 else {
    self.model = ""
    self.serialNumber = ""
    return nil
  }
 
  self.model = identifierComponents[0]
  self.serialNumber = identifierComponents[1]
}

Yes, this works, but it’s harder to read. Thankfully, there is a better way! That’s coming up next.

Before moving on, instantiate the following constants to see this initializer at work:

let component = RocketComponent(identifier: "R2-D21", reusable: true)
let nonComponent = RocketComponent(identifier: "", reusable: true)

Notice in the sidebar how nonComponent is correctly set to nil because the identifier does not follow the model-serial number format.

Failing and Throwing From Convenience Initializers

Replace the initializer you just wrote with the following implementation:

// Init #1c - Convenience
convenience init?(identifier: String, reusable: Bool) {
  let identifierComponents = identifier.componentsSeparatedByString("-")
  guard identifierComponents.count == 2 else {
    return nil
  }
  self.init(model: identifierComponents[0], serialNumber: identifierComponents[1],
    reusable: reusable)
}

Wow, isn’t that a lot easier to read? It’s also more concise. Because convenience initializers are not responsible for setting all property values, they are not subject to designated initializers’ fail/throw rules.

When writing initializers, make the designated initializers non-failable and have them set all the properties. Then your convenience initializers can have the failiable logic and delegate the actual initialization to the designated initializer.

Note that there is a downside to this approach, relating to inheritance. Don’t worry, we’ll explore how to overcome this downside in the last section of this tutorial.

Subclassing

That’s all there is to know about class initialization for root classes. Root classes, which don’t inherit from other classes, are what you’ve been working with so far. The rest of this tutorial focuses on class initialization with inheritance.

Fair warning: this is where things get bumpy! Class initialization is a lot more complicated than struct initialization, because only classes support inheritance.

Differences from Objective-C

Note: If you’ve never seen Objective-C code before, don’t worry — you can still read this section!

If you’ve programmed in Objective-C, Swift class initialization will feel restrictive. Swift defines many new and not-so-obvious initialization rules with regards to classes and inheritance. Don’t be surprised if you run into unexpected compiler errors that enforce these initialization rules.

Don’t write any of this Objective-C code in your playground — you’ll hop back into your Swift playground soon enough, but first I’ll discuss Objective-C to show a naive approach to initialization.

Why are there so many rules with Swift? Consider the following Objective-C header:

@interface RocketComponent : NSObject
 
@property(nonatomic, copy) NSString *model;
@property(nonatomic, copy) NSString *serialNumber;
@property(nonatomic, assign) BOOL reusable;
 
- (instancetype)init;
 
@end

Assume the initializer does not set any of RocketComponent‘s properties. Objective-C will automatically initialize all properties to an empty-ish value, such as NO or 0 or nil. Bottom line: this code is capable of creating a fully initialized instance.

Note that the equivalent class with non-optional typed properties would not compile in Swift because the compiler would not know what values to use to initialize the properties. Swift does not initialize properties automatically to empty values; it only initializes optional typed properties automatically to nil. As you saw in Part 1 of this tutorial, programmers are responsible for defining initial values for all non-optional stored properties; otherwise the Swift compiler will complain.

This distinction between Objective-C and Swift initialization behavior is fundamental to understanding the long list of Swift class initialization rules. Say you update the Objective-C initializer to take initial values for each property:

@interface RocketComponent : NSObject
 
@property(nonatomic, copy) NSString *model;
@property(nonatomic, copy) NSString *serialNumber;
@property(nonatomic, assign) BOOL reusable;
 
- (instancetype)initWithModel:(NSString *)model
                 serialNumber:(NSString *)serialNumber
                     reusable:(BOOL)reusable;
 
@end

RocketComponent now knows how to initialize an instance without using empty values. This time, the Swift equivalent would compile successfully.

Adding Properties to Subclasses

Check out the following RocketComponent Objective-C subclass and its instantiation:

@interface Tank : RocketComponent
 
@property(nonatomic, copy) NSString *encasingMaterial;
 
@end
 
Tank *fuelTank = [[Tank alloc] initWithModel:@"Athena" serialNumber:@"003" reusable:YES];

Tank introduces a new property, but does not define a new initializer. That’s okay, because the new property will be initialized to nil per Objective-C behavior. Notice how fuelTank is a Tank initialized by the initializer implemented in RocketComponent, the superclass. Tank inherits initWithModel:serialNumber:reusable: from RocketComponent.

This is where things really start to break down in Swift. To see it, write in your playground the equivalent Tank subclass from above using Swift. Note that this code will not compile.

class Tank: RocketComponent {
  let encasingMaterial: String
}

Notice how this subclass introduces a new stored property, encasingMaterial. This code does not compile because Swift does not know how to fully initialize an instance of Tank. Swift needs to know what value should be used to initialize the new encasingMaterial property.

You have three options to fix the compiler error:

  1. Add a designated initializer that calls or overrides the designated initializer for the superclass RocketComponent.
  2. Add a convenience initializer that calls the designated initializer for the superclass RocketComponent.
  3. Add a default value for the stored property.

Let’s go for option 3 since it’s the simplest. Update the Tank subclass by declaring “Aluminum” as the default property value for encasingMaterial:

class Tank: RocketComponent {
  let encasingMaterial: String = "Aluminum"
}

It compiles and runs! Not only that, but your effort is rewarded with a bonus: you can take advantage of the initializers inherited from RocketComponent without adding one to Tank.

Using Inherited Initializers

Instantiate a tank with this code:

let fuelTank = Tank(model: "Athena", serialNumber:"003", reusable: true)
let liquidOxygenTank = Tank(identifier: "LOX-012", reusable: true)

That’s an easy way of solving the missing initializer compiler error. This works just as it would in Objective-C. However, most of the time your subclasses will not automatically inherit initializers from their superclasses. You will see this in action later.

Understanding the impact of adding stored properties within a subclass is critical to avoiding compiler errors. In preparation for the next section, comment out the fuelTank and liquidOxygenTank instantiations:

// let fuelTank = Tank(model: "Athena", serialNumber:"003", reusable: true)
// let liquidOxygenTank = Tank(identifier: "LOX-012", reusable: true)

Adding Designated Initializers to Subclasses

encasingMaterial from Tank is a constant property with a default value of "Aluminum". What if you needed to instantiate another tank that is not encased in Aluminum? To accommodate this requirement, remove the default property value and make it a variable instead of a constant:

var encasingMaterial: String

The compiler errors out with, “Class ‘Tank’ has no initializers”. Every subclass that introduces a new non-optional stored property without a default value needs at least one designated initializer. The initializer should take in the initial value for encasingMaterial in addition to initial values for all the properties declared in the RocketComponent superclass. You have already built designated initializers for root classes, and it’s time to build one for a subclass.

Let’s build out Option 1 from the “Adding properties to subclasses” section: add a designated initializer that calls or overrides the designated initializer for the superclass RocketComponent.

Your first impulse might be to write the designated initializer like this:

init(model: String, serialNumber: String, reusable: Bool, encasingMaterial: String) {
  self.model = model
  self.serialNumber = serialNumber
  self.reusable = reusable
  self.encasingMaterial = encasingMaterial
}

This looks like all the designated initializers you have built throughout this tutorial. However, this code won’t compile, because Tank is a subclass. In Swift, a subclass can only initialize properties it introduces. Subclasses cannot initialize properties introduced by superclasses. Because of this, a subclass designated initializer must delegate up to a superclass designated initializer to get all of the superclass properties initialized.

Add the following designated initializer to Tank:

// Init #2a - Designated
init(model: String, serialNumber: String, reusable: Bool, encasingMaterial: String) {
  self.encasingMaterial = encasingMaterial
  super.init(model: model, serialNumber: serialNumber, reusable: reusable)
}

The code is back to compiling successfully! This designated initializer has two important parts:

  1. Initialize the class’s own properties. In this case, that’s just encasingMaterial.
  2. Delegate the rest of the work up to the superclass designated initializer, init(model:serialNumber:reusable:).

Two-Phase Initialization Up a Class Hierarchy

Recall that two-phase initialization is all about making sure delegating initializers do things in the correct order with regards to setting properties, delegating and using a new instance. So far you’ve seen this play out for struct delegating initializers and for class convenience initializers, which are essentially the same.

There’s one more kind of delegating initializer: the subclass designated initializer. You built one of these in the previous section. The rule for this is super easy: you can only set properties introduced by the subclass before delegation, and you can’t use the new instance until phase 2.

To see how the compiler enforces two-phase initialization, update Tank‘s initializer #2a as follows:

// Init #2a - Designated
init(model: String, serialNumber: String, reusable: Bool, encasingMaterial: String) {
  super.init(model: model, serialNumber: serialNumber, reusable: reusable)
  self.encasingMaterial = encasingMaterial
}

This fails to compile because the designated initializer is not initializing all the stored properties this subclass introduces during phase 1.

Update the same initializer like this:

// Init #2a - Designated
init(model: String, serialNumber: String, reusable: Bool, encasingMaterial: String) {
  self.encasingMaterial = encasingMaterial
  self.model = model + "-X"
  super.init(model: model, serialNumber: serialNumber, reusable: reusable)
}

The compiler will complain that model is not variable. Don’t actually do this, but if you were to change the property from a constant to a variable, you would then see this compiler error:

This errors out because the subclass designated initializer is not allowed to initialize any properties not introduced by the same subclass. This code attempts to initialize model, which was introduced by RocketComponent, not Tank.

You should now be well equipped to recognize and fix this compiler error.

To prepare for the next section, update Tank's 2a initializer to how it was before this section:

// Init #2a - Designated
init(model: String, serialNumber: String, reusable: Bool, encasingMaterial: String) {
  self.encasingMaterial = encasingMaterial
  super.init(model: model, serialNumber: serialNumber, reusable: reusable)
}

Un-inheriting Initializers

Now that you’ve returned to a compiling version of Tank, uncomment the fuelTank and liquidOxygenTank instantiations from before:

let fuelTank = Tank(model: "Athena", serialNumber:"003", reusable: true)
let liquidOxygenTank = Tank(identifier: "LOX-012", reusable: true)

fuelTank and liquidOxygenTank no longer instantiate, so this code results in a compiler error. Recall that this compiled and ran fine before adding the designated initializer to Tank. What’s going on?

Both instantiations are attempting to create a Tank using initializers that belong to RocketComponent, which is Tank‘s superclass. The problem is that RocketComponent‘s initializers only know how to initialize the properties introduced by RocketComponent. These initializers have no visibility into properties introduced by subclasses. Therefore RocketComponent‘s initializers are incapable of fully initializing a Tank, even though Tank is a subclass.

This code would work fine in Objective-C because Tank‘s encasingMaterial property would be initialized to nil by the runtime before invoking any initializer. So in Objective-C, there’s no harm in Tank inheriting all of RocketComponent‘s initializers, because they are capable of fully initializing a Tank.

Even though automatic initializer inheritance is allowed in Objective-C, it’s clearly not ideal because Tank might assume that encasingMaterial is always set to a real string value. While this probably won’t cause a crash, it might cause unintended side effects. Swift does not allow this situation because it’s not safe, so as soon as you build a designated initializer for a subclass, the subclass stops inheriting all initializers, both designated and convenience.

In preparation for the next section, comment out the fuelTank and liquidOxygenTank instantiations again:

// let fuelTank = Tank(model: "Athena", serialNumber:"003", reusable: true)
// let liquidOxygenTank = Tank(identifier: "LOX-012", reusable: true)

The Initialization Funnel

To recap: convenience initializers delegate across to other convenience initializers until delegating to a designated initializer.

ClassInitDelegationUp

Designated initializers in subclasses must delegate up to a designated initializer from the immediate superclass.

ClassInitDelegationAcross

Keep in mind that a designated initializer in a subclass cannot delegate up to a superclass convenience initializer.

ConvenienceToConvenienceCannot

Also, a convenience initializer in a subclass cannot delegate up to a superclass convenience initializer. Convenience initializers can only delegate across the class in which they are defined.

DesignatedToConvenienceCannot

Each class in a class hierarchy either has:

  • no initializers
  • one or more designated initializer
  • one or more convenience initializer and one or more designated initializer

Consider the following class diagram:

ExampleClassHierarchy

Say you want to initialize an instance of class D using D’s designated initializer. Initialization will funnel up through C’s designated initializer and up to A’s designated initializer.

Or say you want to initialize an instance of E using E’s second convenience initializer. Initialization will move across to E’s first convenience initializer, then to E’s designated initializer. At that point, initialization will funnel up through D’s and then C’s designated initializers, and finally up to A’s designated initializer.

Class initialization begins moving across convenience initializers, if any, then proceeds to a designated initializer, then finally goes up through each designated initializer for each superclass.

Delegating Up the Funnel

Add the following LiquidTank subclass to the end of your playground:

class LiquidTank: Tank {
  let liquidType: String
 
  // Init #3a - Designated
  init(model: String, serialNumber: String, reusable: Bool,
      encasingMaterial: String, liquidType: String) {
    self.liquidType = liquidType
    super.init(model: model, serialNumber: serialNumber, reusable: reusable,
      encasingMaterial: encasingMaterial)
  }
}

You will use this class to trace initialization through the funnel. It has your standard subclass initializer: sets its own properties, and then calls the initializer on super.

Add the following two convenience initializers to LiquidTank:

// Init #3b - Convenience
convenience init(model: String, serialNumberInt: Int, reusable: Bool,
    encasingMaterial: String, liquidType: String) {
  let serialNumber = String(serialNumberInt)
  self.init(model: model, serialNumber: serialNumber, reusable: reusable,
    encasingMaterial: encasingMaterial, liquidType: liquidType)
}
 
// Init #3c - Convenience
convenience init(model: String, serialNumberInt: Int, reusable: Int,
  encasingMaterial: String, liquidType: String) {
    let reusable = reusable > 0
    self.init(model: model, serialNumberInt: serialNumberInt, reusable: reusable,
      encasingMaterial: encasingMaterial, liquidType: liquidType)
}

Now use LiquidTank‘s convenience initializer #3c to instantiate a new rocket propellant fuel tank:

let rp1Tank = LiquidTank(model: "Hermes", serialNumberInt: 5, reusable: 1,
  encasingMaterial: "Aluminum", liquidType: "LOX")

This initialization follows the following flow through the funnel of initializers: 3c > 3b > 3a > 2a > 1a. It first goes across LiquidTank‘s two convenience initializers; then delegation continues to LiquidTank‘s designated initializer. From there, initialization is delegated up to all the superclasses, Tank and RocketComponent. This also takes advantage of the same design decision you learned in Part 1 of this tutorial: two initializers can use the same set of parameter names and the runtime is smart enough to figure out which one to use based on the type of each argument. In this case, the initializer is called with an integer for reusable to indicate how many more times it can be launched, which means the compiler picks initializer #3c.

Re-inheriting Initializers

Remember that subclasses stop inheriting initializers once they define their own designated initializer. What if you want to be able to initialize a subclass using one of the superclass initializers?

Add the following designated initializer to Tank:

// Init #2b - Designated
override init(model: String, serialNumber: String, reusable: Bool) {
  self.encasingMaterial = "Aluminum"
  super.init(model: model, serialNumber: serialNumber, reusable: reusable)
}

This makes one of RocketComponent’s initializers available for instantiating Tank instances. When you want to use a superclass’s un-inherited designated initializer to instantiate a subclass, you override it just like in the example above.

Now add the following designated initializers to LiquidTank:

// Init #3d - Designated
override init(model: String, serialNumber: String, reusable: Bool) {
  self.liquidType = "LOX"
  super.init(model: model, serialNumber: serialNumber,
    reusable: reusable, encasingMaterial: "Aluminum")
}
 
// Init #3e - Designated
override init(model: String, serialNumber: String, reusable: Bool,
    encasingMaterial: String) {
  self.liquidType = "LOX"
  super.init(model: model, serialNumber: serialNumber, reusable:
    reusable, encasingMaterial: encasingMaterial)
}

This makes both RocketComponent‘s and Tank‘s designated initializers available for instantiating LiquidTank instances.

Now that these designated initializers are back in service, uncomment the fuelTank and liquidOxygenTank instantiations from before:

let fuelTank = Tank(model: "Athena", serialNumber:"003", reusable: true)
let liquidOxygenTank = Tank(identifier: "LOX-012", reusable: true)

The first line instantiates a Tank using the RocketComponent‘s overridden designated initializer. But take a look at the second line: it’s instantiating a Tank using RocketComponent‘s convenience initializer! You didn’t override it. This is how you get subclasses to inherit their superclasses’ convenience initializers.

Override all of a superclass’s set of designated initializers in order to re-inherit the superclass’s set of convenience initializers.

To go one step further, instantiate a LiquidTank using RocketComponent‘s convenience initializer at the bottom of your playground:

let loxTank = LiquidTank(identifier: "LOX-1", reusable: true)

This overrides all of Tank‘s designated initializers. This means that LiquidTank inherits all of RocketComponents‘s convenience initializers.

Overriding Using Convenience Initializers

Designated initializers are supposed to be very basic assignments of values to all stored properties, and normally take in an initial value for each property. Any time you need an initializer that simplifies initialization by having fewer arguments and/or doing some pre-processing on property values, you should make that a convenience initializer. That’s why they’re called convenience initializers, after all: they make initialization more convenient than using a designated initializer.

In the previous section, you overrode RocketComponent‘s designated initializer with a designated initializer in Tank. Think about what this override is doing: it is overriding RocketComponent‘s designated initializers to make it more convenient to initialize Tank instances. Initialization is more convenient because this override does not require a value for encasingMaterial.

When overriding a superclass designated initializer, you can either make it a designated initializer or a convenience initializer. To turn the overridden initializers in LiquidTank into convenience initializers, replace the code for initializers #3d and #3e with:

// Init #3d - Convenience
convenience override init(model: String, serialNumber: String, reusable: Bool) {
  self.init(model: model, serialNumber: serialNumber, reusable: reusable,
    encasingMaterial: "Aluminum", liquidType: "LOX")
}
 
// Init #3e - Convenience
convenience override init(model: String, serialNumber: String, reusable: Bool,
    encasingMaterial: String) {
  self.init(model: model, serialNumber: serialNumber,
    reusable: reusable, encasingMaterial: "Aluminum")
}

There is one downside to overriding superclass designated initializers with subclass designated initializers. If the subclass designated initializer has logic, you can’t delegate to it from a convenience initializer. Instead, you can override a superclass’s designated initializer with a convenience initializer; this allows you to delegate to the subclass’s designated initializer logic. You’ll try this next.

Failing and Throwing Strategy With Inheritance

Add the following convenience initializer to LiquidTank:

// Init #3f - Convenience
convenience init?(identifier: String, reusable: Bool, encasingMaterial: String,
    liquidType: String) {
  let identifierComponents = identifier.componentsSeparatedByString("-")
  guard identifierComponents.count == 2 else {
    return nil
  }
  self.init(model: identifierComponents[0], serialNumber: identifierComponents[1],
    reusable: reusable, encasingMaterial: encasingMaterial, liquidType: liquidType)
}

This initializer looks almost identical to RocketComponent‘s convenience initializer.

Instantiate a new LiquidTank using this new convenience initializer:

let athenaFuelTank = LiquidTank(identifier: "Athena-9", reusable: true,
  encasingMaterial: "Aluminum", liquidType: "RP-1")

This works, but there’s duplicate code in LiquidTank‘s and in RocketComponent‘s initializers. Duplicate code introduces the possibility for bugs, so this just won’t do.

No one wants bugs on Mars.

No one wants bugs on Mars.

To follow the DRY (Don’t Repeat Yourself) principle, add the following type method to RocketComponent:

static func decomposeIdentifier(identifier: String) ->
    (model: String, serialNumber: String)? {
  let identifierComponents = identifier.componentsSeparatedByString("-")
  guard identifierComponents.count == 2 else {
    return nil
  }
  return (model: identifierComponents[0], serialNumber: identifierComponents[1])
}

This code refactors out the duplicate code from the initializers and places it in a single place accessible to both initializers.

Note: Type methods are marked with the static keyword. They are called on the type itself instead of an instance. You might not have thought of it this way before, but calling a method inside the implementation of a class is really calling an instance method. For example, self.doSomething(). You need to use a type method in this situation because decomposeIdentifier(_:) as an instance method would not be available until phase 2, after all properties have been initialized. You’re using decomposeIdentifier(_:) as a utility to calculate a property value for initialization. I recommend playing around with calling methods in initializers of your own classes to get the hang of this concept.

Now update both convenience initializers from RocketComponent and LiquidTank to call the new static method:

// Init #1c - Convenience
convenience init?(identifier: String, reusable: Bool) {
  guard let (model, serialNumber) = RocketComponent.decomposeIdentifier(identifier) else {
    return nil
  }
  self.init(model: model, serialNumber: serialNumber, reusable: reusable)
}

and:

// Init #3f - Convenience
convenience init?(identifier: String, reusable: Bool, encasingMaterial: String,
    liquidType: String) {
  guard let (model, serialNumber) = RocketComponent.decomposeIdentifier(identifier) else {
    return nil
  }
  self.init(model: model, serialNumber: serialNumber, reusable: reusable,
    encasingMaterial: encasingMaterial, liquidType: liquidType)
}

This is a great way to take advantage of failable convenience initializers while removing any redundancy. You can still have the initializer return nil as needed, and you’ve refactored the common code into the type method to avoid repeating yourself.

Where to Go From Here?

Whew, that was a lot to cover! You’ve learned a ton about initialization in this two-parter tutorial … and thanks to you, the first manned mission to Mars is ready for lift-off. Great job!

If you want to compare code or just want a look at the final code, the complete playground for Part 2 can be downloaded here.

To review what you’ve learned here and to read about all the initialization rules and compiler safety checks, download Apple’s book The Swift Programming Language.

To get more practice and to see initialization in the wider context of structs and classes, check out our book, Swift Apprentice. We also have a great tutorial on Object-Oriented Design in Swift which touches on initialization.

Now that Swift is open source, you can find lots of interesting documents related to initialization in the Swift GitHub repo under the docs folder. By reading these documents you can learn the Swift team’s justification for initialization features and safety checks. Follow the Swift-evolution and Swift-evolution-announce mailing lists to get a glimpse of what’s on the horizon.

We hope you enjoyed this tutorial, and if you have any questions or comments, please join the forum discussion below!

The post Swift Tutorial: Initialization In Depth, Part 2/2 appeared first on Ray Wenderlich.

Core Data by Tutorials Updated for Xcode 7.3

$
0
0

Core Data by Tutorials Second Edition Now Available!

The updates keep coming! Today, we’re happy to announce that our popular book Core Data by Tutorials is now fully up-to-date for Xcode 7.3.

Xcode 7.3 has a few small changes to Swift – mostly minor syntax things – but we wanted to make sure that all the instructions work without any issues.

In addition to updating the book for Xcode 7.3, we’ve fixed some errata pointed out by readers – thanks all!

This is a free update for existing PDF customers. Here’s how you can get your copy:

  • If you’re an Core Data by Tutorials PDF customer, you can download the update for free on your My Loot page (version 2.2).
  • If you haven’t picked up a copy of Core Data by Tutorials yet, grab your copy now.

We’re hard at work updating the rest of our Swift books for Xcode 7.3 – stay tuned.

Aaron, Saul, Matt, Pietro and I hope you enjoy this update!

The post Core Data by Tutorials Updated for Xcode 7.3 appeared first on Ray Wenderlich.

Video Tutorial: Intermediate iOS Animations Part 2: Core Animation Models

What’s New in Android Studio 2.0

$
0
0

AndroidStudio2-feature

In the last quarter of 2015 Google announced a brand new, Android-centric conference called the Android Dev Summit. Google kept the conference content secret, promising “deep technical sessions,” but dropped huge hints about something new for Android Studio.

Sure enough, the big superstar of the Android Dev Summit (other than the platform and tool engineers) was Android Studio 2.0. The Android team buffed and polished the interface nicely; what’s more, clearly the Android Tools Team felt the need for speed, as they have increased the speed and performance of builds and the Android Emulator, which has also earned a shiny “2.0” badge.

On April 7, Google released Android Studio 2.0 in their “stable” channel, so it’s no longer just a preview, but the new standard for Android development! In this article, you will learn about the improvements Android Studio 2.0 has to offer, and will try out a few of them.

If you’re brand new to Android Development, you should work through the Android Tutorial for Beginners. In particular, you should be able to set up and run Android Studio and the Android Emulator. If you need some help with that, look at the Beginning Android Development Tutorial: Installing Android Studio.

Alright, let’s take Android Studio 2.0 for a test drive!

Getting Started

First, download the companion project for this article. It’s a complete Android project for you to use on your test drive. There are a few places where you will modify code, but just as part of demoing new Android Studio features.

Launch Android Studio, and in the Welcome to Android Studio dialog, select Import project (Eclipse ADT, Gradle, etc.).

Android Studio: Welcome to Android Studio

Choose the top-level directory of the companion project and click OK.

Select companion project

If you look through the project, you should see two activity classes and two RecyclerView view holder classes, along with the accompanying resource and layout files. Don’t worry too much about the details; you won’t be heavily editing these files.

Build and run. You should see this:

First build of companion app

The top card has a few widgets—you’ll get to play with those later. Below the widgets, you should see helpful links for further reading on some of the material covered in this article.

Improved IDE

Just because you’re an Android developer who makes fantastic UIs doesn’t mean you don’t crave ways to make even more fantastic UIs. Android Studio 2.0 feeds your craving, including several UI improvements and new tools for you to enjoy.

IntelliJ Features

Google based Android Studio on Jetbrains IntelliJ IDEA. While the two IDEs have different companies and development teams, they do import features from each other, which is great news as IntelliJ is packed with useful tools for code navigation, code inspection, and refactoring. In fact, Android Studio 2.0 already comes with new features from the newest (as of this article’s publication) release of IntelliJ, version 15.

One new feature is the instant results in the Find in Path action. Let’s try it out!

In Android Studio, select Edit \ Find \ Find in Path (or use the keyboard short CMD+Shift+F). In the Find in Path window that appears, select the Preview tab. Enter any search text in the Text to find field. For search results to appear in the Preview tab, make sure the Regular expressions checkbox in the Options tab is not checked.

Live Preview of Text Search

The search results should update in real time as you type. These results also utilize any options you set on the Options tab, giving full search power to even the most impatient.

A handy new code inspection tool from IntelliJ 15, Expression Type, helps out when you cannot immediately tell or remember the resulting type of an expression.

To see it in action, highlight an expression in your code and hit CTRL+Shift+P.

Using Expression Type

This determines the type of the expression’s value and displays it in a tooltip. Sweet!

You can learn more about the newest IntelliJ 15 features (that you get to use from Android Studio) from Jetbrains.

Deep Links Integration

In your app, you can enable deep links that allow your app to appear in relevant Google search results. You create these deep links via intent filters for handling certain URLs. If you are not familiar with intent filters, check out our Android: Intents Tutorial.

Android Studio 1.5 already povided an easy method to generate these intent filters in your Android Manifest, but Android Studio 2.0 adds static analysis that verifies whether your app is ready for app indexing.

To give it a try, open AndroidManifest.xml in Android Studio.

You should see the following:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.raywenderlich.as20allthethings"
          xmlns:android="http://schemas.android.com/apk/res/android">
 
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 
  <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:supportsRtl="true"
      android:theme="@style/AppTheme">
 
    <activity android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>
 
    <activity
        android:name=".DeepLinkActivity"
        android:theme="@style/AppTheme.Green"/>
 
  </application>
 
</manifest>

Right-click on the activity android:name=".DeepLinkActivity" tag, and in the context menu that appears, select Generate \ URL.

Add a Deep Link Intent Filter: Context Menu

Alternatively, click on the tag and hit Option+Enter; in the pop-up that appears, select Add URL.

Add a Deep Link Intent Filter:  Generate

Using either method tells Android Studio to generate the necessary intent filter. The activity should now look like this:

<activity
    android:name=".DeepLinkActivity"
    android:theme="@style/AppTheme.Green">
  <!-- ATTENTION: This intent was auto-generated. Follow instructions at
https://g.co/AppIndexing/AndroidStudio to publish your URLs. -->
  <intent-filter>
    <action android:name="android.intent.action.VIEW"/>
 
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <!-- ATTENTION: This data URL was auto-generated. We recommend that you use the HTTP scheme.
      TODO: Change the host or pathPrefix as necessary. -->
    <data
        android:host="as20allthethings.raywenderlich.com"
        android:pathPrefix="/deeplink"
        android:scheme="http"/>
  </intent-filter>
</activity>

As you can see, Android Studio did most of the work here in setting up the intent filter so that any URLs that match “http://as20allthethings.raywenderlich.com/deeplink” will be handled by this app.

To see the Android Studio 2.0 static analysis in action, change the data tag to look like the following:

<data
    android:host="as20allthethings.raywenderlich.com"/>

Now you should see Android Studio 2.0 complaining that you did something a little bad.

Deep Link Lint error

Here, Android Studio specifically warns you that Google search will not play nice with this invalid URL. Undo those changes to make Android Studio and your app happy again.

You may feel that the improvement is small, but app indexing is a powerful tool, and integrating with Google Search will increase the visibility and utility of your app. For more information on app indexing, check out this overview from Google Developers.

Unified Unit Tests and Android Instrumentation Tests

If you are familiar with unit testing on Android, you know that there are two types of unit tests in Android Studio:

  • Local unit tests are unit tests without dependencies on the Android framework; these run on the local machine only.
  • Instrumented unit tests are unit tests that have Android dependencies and must run on a device or emulator.

In previous versions you had to choose one of the two types from the Test Artifacts setting in the Build Variants window. You could only run tests of that type, and would only see tests of that type in the project overview.

Unit Tests Artifact

Unit Tests selection, before Android Studio 2.0

Android Instrumentation Tests Artifact

Android Instrumentation Tests selection, before Android Studio 2.0

Android Studio 2.0, however, has a unified testing view. Now you can view and run both kinds of tests, eliminating the need to choose a test artifact.

Project View: All Test Artifacts Enabled

For more information about unit testing in Android, check out developer.android.com.

GPU Profiler

A huge feature for GL graphics developers is the new GPU profiler. Aiming to save developers huge amounts of time during graphics debugging, the GPU profiler provides the power to closely examine the GPU state. Developers can record and replay a scene frame-by-frame as well as view the sequence of GPU commands that created that state and scene.

This article doesn’t look at all the details of the GPU profiler, but you can find out more on the Android Tools Project Site.

Android Studio: GPU Profiler

From the Android Dev Summit keynote presentation: https://youtu.be/xdItHEVfQ4U?t=15m57s

Depending on the apps you write, the GPU profiler may not be something you use often, but the next section will look at improvements in something that you probably have used many, many times: the Android Emulator.

Android Emulator 2.0

It’s fair to say that not many developers love the Android Emulator, and that many have lamented its super-slow start up and laggy performance. For a long time, the emulator lacked many of the features and UI convenience of third-party emulators.

Happily, the Android Emulator 2.0 has completely changed the game, receiving both a much-improved UI as well as a massive speed-up.

New Interface

The first thing to notice about the Android Emulator 2.0 is that while the screen rendering area might look the same, with a phone frame and gray window border, the emulator has a new toolbar.

Android Emulator 2.0

The Android team also added a feature that sounds simple but was, as they said, a frequently-wished-for improvement: the ability to resize the emulator by dragging the window (to sometimes ridiculous results).

Android Emulator 2.0: Resizing

Speaking of dragging, you can now transfer files onto the virtual device by dragging-and-dropping.

Android Emulator 2.0: Drag and Drop APKs

The new emulator toolbar provides easy-access controls for the emulator, such as Volume, Back, Home and Power Off. It also provides a screen rotation button (the old emulator required a keyboard shortcut or an arcane ADB command) and a screenshot button.

Click the bottom button of the toolbar to see the Extended controls window appear. Select Settings. From here, you can set the destination folder for screenshots:

Extended controls: Settings

The Extended controls window shows more of the awesome features Android Studio 2.0 provides for testing your app. You can emulate device conditions and verify behaviors such as how your app would handle different types of networks and speeds, battery status changes, location updates and more.

Extended controls: Cellular

There is even a control for emulating fingerprint sensor input.

Extended controls: Fingerprint

Let’s try out a few of these in the companion app.

Phone Call/SMS

Select Phone in the Extended controls window. You should see a form that contains input for a phone number and text message:

Extended controls: Phone

In the SMS text, enter Check this out! http://as20allthethings.raywenderlich.com/deeplink

Extended controls: Sending a SMS

Click SEND MESSAGE.

Extended controls: SMS received

Woohoo! You just sent your emulator a text message without breaking a sweat.

Note: As you might remember from the discussion about deep links integration, the companion now has an intent filter that handles the URL in the text message.

If you want to see the deep linking in action, open the SMS in the emulator and click the link.

Battery and Charging States

Another device state you can directly set and manipulate in version 2.0 is the battery status and charging state.

Launch the companion app. Part of the logic in the top card displays the current battery status of the device, and if you look at the battery status of the emulator and the battery status message in the top card, you will see that they match.

Companion App: Battery Status

To make changes, open the Extended controls window and select Battery.

Extended controls: Battery

There are several controls for manipulating the battery status. Use the Charge level slider to change the battery level, and watch it instantly update in the status bar of the emulator. To explicitly set the battery status, select Full from the Battery status dropdown. The top card detects the change and displays the new status immediately.

battery-status-dropdown

Location Updates

For your last stop on the extended controls portion of the tour, you will practice pushing location updates to the emulator.

If you look at the top card, you will see the text “No location yet”.

No location yet

The top card listens for location updates and displays the received location coordinates. Right now it is just waiting for you to give it some!

In the companion app, click the Start button. You’ll be prompted to give the app access to the device’s location. Click ALLOW.

Location permissions

At this point, the companion app waits for location updates.

To pass it an update, open the Extended controls window again and select Location. With Decimal selected, enter 37.4226 into Latitude and -122.084 into Longitude. Click SEND.

Location Coordinates Input

The top card should immediately update to reflect the new location.

Location update

If you don’t want to enter in location updates one by one, you can even load a set of coordinates into the window and “play” that list.

Location Coordinates List

With all these tools and more, Android Emulator 2.0 has been packed with exciting new utility and a streamlined interface. It is definitely worth the ride.

Better Builds

You might say to yourself, “Okay, a fast emulator is great, but I’m still spending too much time actually building my app. What do I do about that?”

Well, you could train your dog to code. If nothing else, that could get you some YouTube fame :]

The better solution is—as you might have guessed—Android Studio 2.0!

The Android Tools Team has attempted to rev up build and deployment speeds. They have also added a new feature: Instant Run. You’ll explore these improvements in the next section.

Faster Build Speeds

Reporting speed-ups of 2-2.5x for full build times, the Tools Team has made improvements in several areas of the build system. To fully discuss them would be a pretty deep dive, but generally speaking they include:

  • Improvements to the dx merger. dx is the build tool that converts Java classes to Dalvik executable format (.dex) files.
  • A shrinker for debug mode.
  • Builds that specifically target connected devices.

For information on builds and the build system in general, check out the docs on android.developer.com.

For more on these build system improvements in particular, check out this session presented at the Android Dev Summit.

Faster ADB

The Android Debug Bridge (ADB) on the emulator has received a push/pull protocol update. When deploying APKs to the new emulator, you will see up to a 5x speed increase.

ADB Push Speeds

From the Android Dev Summit keynote presentation: https://youtu.be/xdItHEVfQ4U?t=13m17s

Instant Run

Wonderfully, Android Studio 2.0 is all about the need for speed. While the Android Tools Team has sped up builds and deployments, they have also tried to reduce the number of times you have to deploy.

To this end, they have introduced Instant Run, which provides pushing of updates—code and resources—to a running instance of your app on a device or emulator without requiring a full reinstall. Obviously, this is a huge time-saver.

Instant Run works differently for different kinds of changes. Currently, there are three ways Instant Run implements updates:

  1. A hot swap: your app continues to run and uses the changes next time the relevant method is called. This applies to method changes.
  2. A warm swap: your app continutes to run but restarts the current activity. This applies to resource changes.
  3. A cold swap: your app restarts but does not reinstall. This applies to structural code changes.

You can try out Instant Run right now in the companion app.

To enable Instant Run, select Preferences \ Build, Execution, Deployment \ Instant Run. Ensure that Enable Instant Run to hot swap code/resource changes on deploy is checked and that Restart activity on code changes is unchecked.

instant-run

If the companion app is not yet running, launch it by clicking the Run button, and wait for it to launch.

Initial app run

When the app is running, you should see a lightning bolt next to the Run button. The lightning bolt indicates that Instant Run is available.

Instant Run Ready

To test it out, open colors.xml and make the following changes to the colors:

<resources>
  <color name="colorPrimary">#455A64</color>
  <color name="colorPrimaryDark">#263238</color>
  <color name="colorAccent">#2196F3</color>
</resources>

This simply changes the values of colorPrimary and colorPrimaryDark, which determine the colors of the status bar and action bar.

Hit the Run button. The screen will flicker, and you’ll see a toast notifying you that the activity restarted. You will also see that the app already shows the colors changes without a full build and install.

Instant Run: Warm Swap

Because of the activity restart, you can probably guess that this was a warm swap.

Now open CardViewHolder.java and make the following changes to the onClick method:

@Override
public void onClick(View v) {
  if (mListener == null) {
    return;
  }
 
  Snackbar.make(itemView, R.string.instant_run, Snackbar.LENGTH_SHORT).show();
 
  mListener.onToggleLocationUpdates();
}

This added code requests that a snackbar be shown whenever someone clicks the START/STOP button on the top card of the companion app.

Hit the Run button. A toast will appear to notify you that Instant Run “Applied code changes without activity restart.”
Instant Run: Hot swap

Can you guess what kind of swap that was?

If you guessed hot swap, give yourself a cookie! :] Instant Run was able to push the changes without even restarting the activity. And if you click the START/STOP button, you can verify that the changes were successfully pushed:

Instant Run!

Instant Run can dramatically increase productivity, and dramatically decrease the time you spend browsing the Internet as you wait for your builds to finish and deploy (you’ll have to catch up on funny dog pics later). Beyond that, Instant Run will make your layout and styling more efficient, since you can immediately and directly see how code changes result in UI changes.

Where to Go From Here

There certainly is a lot to learn and try out in Android Studio 2.0 and Android Emulator 2.0! Much of the information about the two comes from the Android Dev Summit presentations, so check out those and other great sessions via the recordings posted on YouTube.

Many of the cool new things in Android Studio 2.0 are works in progress. A great way to keep up with updates, bug fixes and new features is to regularly check the Recent Changes page over at the Android Tools Project Site.

The Android Tools Project Site also contains technical docs on many of the Android Studio features.

If you have any questions or comments, feel free to post your comments below or in the forum!

The post What’s New in Android Studio 2.0 appeared first on Ray Wenderlich.

tvOS Apprentice Updated for Xcode 7.3

$
0
0

TVT-Thumb

The updates keep going, and going, and going… :]

Today, we’re happy to announce that our popular book the tvOS Apprentice is now fully up-to-date for Xcode 7.3.

Xcode 7.3 has a few small changes to Swift – mostly minor syntax things – but we wanted to make sure that all the instructions work without any issues.

In addition to updating the book for Xcode 7.3, we’ve fixed some errata pointed out by readers – thanks all!

This is a free update for existing PDF customers. Here’s how you can get your copy:

  • If you’re a tvOS Apprentice PDF customer, you can download the update for free on your My Loot page (version 1.1).
  • If you haven’t picked up a copy of the tvOS Apprentice yet, grab your copy now.

We’re hard at work updating the rest of our Swift books for Xcode 7.3 – stay tuned.

The tvOS Apprentice team and I hope you enjoy this update!

The post tvOS Apprentice Updated for Xcode 7.3 appeared first on Ray Wenderlich.

Video Tutorial: Intermediate iOS Animation Part 3: Animation Timing

Making Overcast, Instapaper & Tumblr: A Top Dev Interview With Marco Arment

$
0
0
Marco Arment, creator of Overcast & Instapaper.

Marco Arment, creator of Overcast & Instapaper.

Welcome to another installment of our Top App Dev Interview series. Each interview in this series focuses on a successful mobile app or game developer and the path they took to get where they are today. Today’s special guest is Marco Arment.

Marco is a prolific technologist, technology writer and podcaster. He is best known for being lead developer and CTO of Tumblr, the sole creator of Instapaper and most recently the sole creator of Overcast, his popular podcast app for iOS.

When he’s not busy programming, Marco is either writing on his website or hosting one of his several podcasts such as the Accidental Tech Podcast (ATP), Top Four and Under the Radar.

Focus

Marco, you’re known for more than one successful project. What criteria do you use when coming up with ideas for projects or businesses?

There’s no reliable method to coming up with successful new projects — I have far more failures and abandoned projects than successes. The only way I know to increase my odds of finding success is to try more ideas.

Knowing when to move on is a tricky balance that I still haven’t mastered, but a good rule is to move on once you’re no longer motivated or able to do great work for a project.

You’re a prolific writer, podcaster and developer. What helps you prioritize what to do and what not to do?

I’m also a father and a lazy procrastinator, so my schedule is all over the place, and I don’t balance the time demands of my projects very well. (Most notably, I’ve barely written anything recently.)

I work in erratic bursts. I’ll accomplish relatively little for maybe a week, then have an incredible marathon in which I accomplish a week’s worth of work in a few hours. In reality, this is how I’ve always worked, even when employed full-time in regular jobs — I just tried to hide it, and my bosses seemed happy enough with the results of the productive bursts to overlook my useless periods.

Nobody should take time-management advice from me. I work this way because it’s the only way I can, not because it’s a good idea. If you have a better work ethic, use it.

If you want to tackle something completely new that you’ve never done before (for example implementing the “Smart Speed” and “Voice Boost” features in Overcast), how do you go about it?

Overcast, Marco's podcasting app for iOS

Overcast, Marco’s podcasting app for iOS

I often have crazy ideas like those, and I usually just build basic implementations to see if they’re any good, then try using them myself for a while. I’ve always taken a just-build-it approach to design and feature experimentation (rather than formal prototyping or image mockups).

Most of these ideas never see the light of day — not even to beta testers — either because I couldn’t get them to work well, or more often, because they end up being terrible ideas.

But occasionally, they end up being awesome, making it all worth it. This experimentation is by far my favorite part of development. One or two of these crazy ideas can define a product or set it apart from the competition for years.

Indie Development

You’re much more than a developer. You’re also your own product manager, project manager and businessman. How did you develop the non-technical skills you have now?

In today’s hyper-competitive market for people’s attention, every independent developer needs all of those skills, plus more. You can make a fantastic app, technically, but if there are big flaws in its design, marketing, or business model, you won’t get far.

I developed my relatively minimal skills in these areas over time the same way I developed most of my technical skills: out of necessity, at the last minute, while stumbling through, trying to gain as much wisdom as possible from more experienced people along the way.

I’ve been lucky to work with or near many people much smarter than me, from whom I’ve drawn incalculable value. And I practically live in my RSS reader (Remember those? Not dead!), voraciously reading blog posts from people in these fields for over a decade.

For the most part it seems like you are a one-man operation. What do you outsource and what do you keep in-house?

I outsource most icon design, since I’m generally terrible at it, and I hire an accountant for taxes. That’s it.

I’ve outsourced support before, but it’s very difficult to do well, and it’s hard to justify at App Store price levels. So, somewhat controversially, I currently don’t offer technical support and I don’t respond to most email. I set expectations accordingly in the app, and almost everyone is completely fine with that. The percentage of angry people now seems about the same (maybe lower!) than when I had expensive support staff.

What are some of the biggest mistakes to avoid as an indie developer?

By far, the biggest mistake I see indies make is having unrealistic expectations of how much the market will value what they’re making, assuming they can indulge themselves in months or years of fancy construction and consumers will pay for it.

It’s easy to look at successful, painstakingly crafted, impeccably designed apps from well-known developers like Panic or Omni and attribute their success to their craftsmanship, design, and delightful details. Far too many developers believe that if they polish an app to a similar level, they’ll be successful, too. And then they pour months or years of effort into an app that, more often than not, never takes off and can’t sustain that level of effort.

These high-profile success stories didn’t become successful because they invested tons of time or had world-class designs — they became successful because they solved common needs, that people were willing to pay good money for, in areas with relatively little competition. In short, they fit well and were well-timed in the market.

The craftsmanship and design were indulgent luxuries that their successful market fits enabled them to do, not the other way around. Most people buy these apps because they’re useful and necessary, not because they’re pretty.

It’s not enough to make something fancy — it needs to have sufficient value to the market first, which can then fund the fancy design and technical extravagance you want to do if it takes off.

Inspiration

In the past you’ve talked about design being about “how it works”, not just “how it looks” (like Steve Jobs used to say). What apps, other than your own, do you use that also take on this philosophy?

Marco hosts ATP with John Siracusa and Casey Liss.

Marco hosts ATP with John Siracusa and Casey Liss.

I love little delightful details and features. I’m always looking at apps for these, but I’ve found that looking into the world of other well-designed and luxury products is far more inspirational, since they’ve been doing it for much longer and are usually much better at it.

Cars are a great source, full of automated features, luxurious accents, lighting techniques, and control affordances. You don’t even need to go high-end to see them — a Honda Accord has more little niceties than most apps.

I’ve also recently gotten into mechanical watches, another solid source of delightful details. For instance, I recently learned that some manually-wound watches, upon running out of power, will stop the second hand at zero every time to make it easier to set them when they’re next used.

That’s exactly the kind of delightful little detail that I love: some potentially tricky engineering to achieve something that most people won’t even notice, but that makes the product nicer for everyone, and will really impress and delight the few that do notice it.

Who do you look up to? Who do you consider a success, either in our industry or otherwise?

I try to absorb as much wisdom as possible from people who do similar work, but in different ways or in different markets than me, like Brent Simmons, David Smith, Jason Snell, John Gruber, and CGP Grey.

I also look outside my immediate industry for potentially useful knowledge and wisdom — always finding tons — from people like David Karp, Seth Godin, Howard Stern, Trey Anastasio, and the late George Carlin.

What would you say to folks who want to make a living like you do?

Break the common assumption that you can painstakingly hand-craft one amazing app and make a full-time living exclusively from that app for years. That’s extremely rare, it’s not what I do, and I don’t think I can even name anyone who does that anymore.

Recognize that indie development is flooded with competition. This isn’t to discourage anyone from entering it, but should be considered when deciding what to do (and not do): keep your costs as low as possible, and get ideas to market quickly before assuming they’ll be successful. If they are, *then* invest more time. If not, move on and try something else. It’s hard to give up on an idea that you think is great, but when the market speaks, listen to it.

And as much as possible, diversify your income. Make multiple apps. Consulting is always a good option that can help fund other development. If you can write or podcast, do that, too. Not only can those bring in extra income, but they can build an audience to help promote your apps or consulting, no matter how big or small the audience is. It doesn’t take a huge audience to make a difference in an App Store full of undifferentiated alternatives.

Finally, don’t listen too much to me or any other single person. All I know is what worked for me, which won’t exactly work for anyone else because you can’t turn back time. Absorb as much as you can from a diverse pool of people. There’s tons of great wisdom out there if you look and listen.

Where to go from here?

And that concludes our Top App Dev Interview with Marco Arment. A huge thanks to Marco for sharing his journey with the iOS community :]

We hope you enjoyed this interview and that you take Marco’s advice to heart when it comes to becoming an indie app developer. In the end, working towards a successful app in the App Store takes more than good programming and good design.

There are also other things to consider such as building an audience, marketing and finding the right product-market fit. The good news is that these are all skills that you can learn, just like Marco did.

If you are an app developer with a hit app or game in the top 100 in the App store, we’d love to hear from you. Please drop us a line anytime.

If you have a request for any particular developer you’d like to hear from, please join the discussion in the forum below!

The post Making Overcast, Instapaper & Tumblr: A Top Dev Interview With Marco Arment appeared first on Ray Wenderlich.


Video Tutorial: Intermediate iOS Animation Part 4: Animation Groups

PaintCode Tutorial for Developers: Custom Progress Bar

$
0
0

PaintCode-ProgressBar-feature

As you may know, PaintCode is a fantastic little Mac app that turns your vector graphic designs into Core Graphics code you can easily use in your iOS apps.

A while back we wrote a PaintCode tutorial for designers and a PaintCode tutorial for developers that taught you how to create and animate a stop watch control in PaintCode, and integrate it into your own iOS app. You learned a lot; but that only scratches the surface of what PaintCode can do!

In this intermediate PaintCode tutorial, you’ll draw a dynamic custom progress bar in PaintCode. You’ll then add this progress bar to Songy, a music player app, to show the progress of the song playing from your device’s music library.

To properly test Songy, you will need a physical iOS device with at least one song stored in your music library. You can still follow along with the simulator, but you won’t be able to see the progress bar update in real time.

Without further, it’s time to get started on your custom progress bar!

Getting Started

First make sure you have a paid copy of PaintCode. The free trial will not work for this tutorial; it has a number of restrictions such as the inability to copy/paste, the inability to export code, and more.

Then open PaintCode and create a new document by going to File\New on the main menu.

Ensure that your PaintCode screen is set up with the Library on the left and that the Code panel at the bottom is visible and set to iOS > Swift. It’s always interesting to see the generated code as you move through the tutorial – if nothing else, it’s a cool way of learning Core Graphics! :]

PaintCodeInitial

Use the Inspector to rename the canvas to Progress Bar and set the Width to 290 and the Height to 13:

02-CanvasName1

Your canvas is now the correct size for the progress bar you’ll be making in this tutorial.

The basic elements that make up the progress bar are two rectangles with a corner radius. The first rectangle will be a stroke outline of the entire progress bar. The second rectangle will be a solid fill, which will indicate how much of the song track has been played.

In the toolbar at the top, click on the Rect button (the left-most button), then click and drag inside the canvas to create a rectangle. Don’t worry about how things look just yet – you’ll use the Inspector to fix that.

Click on the newly created rectangle to select it, then use the Inspector to change the name of the rectangle to Progress Outline. Set the Radius to 5, then modify the position and size of the rectangle to have X and Y values of 1, Width of 288, and Height of 10. Set the Fill color to No Fill and assign any color you like to Stroke:

ProgressOutline

You’ll change the final color once you’ve finished creating the progress bar.

Check out your canvas and you should have something that resembles the following image:

ProgressOutline

Next up – a second rectangle for the song progress indicator.

Click the Rect button in the toolbar and then click and drag inside of your canvas. In the Inspector, change the name of the rectangle to Progress Active, the Radius to 5, the X and Y values to 1, Width to 288, and Height to 10.

Select a Fill color and click the x next to Stroke to remove it:

ProgressActive

Your progress bar should look like the following:

ProgressBarActive

PaintCode Frames

Frames in PaintCode let you to create flexible elements. For example, you’ve created a progress bar that’s exactly 288 pixels wide. However, you probably want this control to resize for different screen sizes.

When you create a frame, PaintCode encloses the generated drawing code into a method where one of the parameters is the frame’s rectangle. Using PaintCode, you can then adjust how objects, such as your progress bar’s rectangle, resize within the frame.

In the top toolbar, click the Frame button and then click anywhere within the gray progress bar.

Look at the generated code in the Code section at the bottom of the screen; it has a method header with a frame property. The origin of your progress elements will depend upon this property.

Time to enclose your control in a frame.

Click Frame in the Browser pane on the right side. Ensure the Apply only to entirely enclosed shapes option is checked; this means that only shapes positioned entirely within the frame will be affected by your changes. This keeps the grey progress bar from moving out of position while you change the frame’s properties.

When the progress bar is fully enclosed, any changes you make to the frame’s properties will also change the progress bar’s properties.

Change the X and Y values to 0, Width to 290 and Height to 12:

ProgressFrame

If you look at the code at the bottom of the screen, you’ll see the Progress Outline rectangle width still doesn’t depend on the frame value:

//// Progress Outline Drawing
let progressOutlinePath = UIBezierPath(roundedRect: CGRect(x: frame.minX + 1, y: frame.minY + 1, width: 288, height: 10), cornerRadius: 5)
UIColor.blackColor().setStroke()
progressOutlinePath.lineWidth = 1
progressOutlinePath.stroke()

To fix this, you’ll configure the resizing constraints in the Inspector. Select the Progress Outline rectangle:

ResizingConstraints1

The constraints here indicate the relationship between the shape and its frame. In this case, the width constraint is a straight line, meaning the rectangle’s width doesn’t depend on the frame. Click the Width constraint to change it to a wavy line:

ResizingConstraints

Now your rectangle will resize when the frame resizes. The generated code for progressOutlinePath changes to reflect this:

let progressOutlinePath = UIBezierPath(roundedRect: CGRectMake(frame.minX + 1, frame.minY + 1,
         floor((frame.width - 1) * 0.99654 + 0.5), 10), cornerRadius: 5)

When you resize Frame, Progress Outline will resize too:

ResizeFrame

Note: In the above animated GIF demonstrating how Progress Outline resizes with the frame, I’ve hidden the Progress Active rectangle just for demonstration purposes.

Voilà – you have the basic progress bar. Now to dynamically resize Progress Active.

Setting up Variables

Now that you have the basic progress bar ready, it’s time to use one of PaintCode’s coolest features: Variables. In the left pane, you’ll see a section at the very bottom named Variables. Click the plus button and select Number from the popup menu.

Rename the number variable to progress and dismiss the popover:

ProgressVariable

Click on the Progress Active element in the right pane to select it. You’ll now connect the progress variable to the Progress Active element’s width.

Drag from the circle next to the numeric value of the progress variable you just created to the Width property for Progress Active:

Variable

Click and drag up and down over the numeric value of the progress variable; you’ll see the progress bar’s width change to match the value of the variable:

VariableActive

Magical2

Note: Along with numeric variables like this one that dynamically change numeric attributes, you can also create expression variables. Want the width to grow twice as fast as the variable? Create an expression that multiplies the progress number variable by two – and use that expression variable as the input for the bar’s width attribute.

Awesome job! You’ve finished the progress bar in PaintCode and are ready to take it into your iOS project.

Adding the Progress Bar to your Project

Before exporting the progress bar from PaintCode, download the starter project and take a look at what it contains.

The Starter Project

Songy shows a list of music stored in your Music library along with some buttons for you to interact with. Build and run the application to see what the app currently looks like; You should do this on a device with music in the device’s library so you have some music show up in the table view.

11-StarterProject

Play any song; you’ll notice there’s no progress indicator for the current song. This is where your custom progress bar comes into play.

Start by looking at Main.storyboard. This consists of a single scene with a table view to show the list of songs along with their album art. Below the table view, there are three labels to show the current song name, artist name, and album name.

While not visible, right below the last label is a UIView that will contain your custom progress bar. Finally, you have four buttons to change to the previous and next songs, play or pause, and stop the current song.

Switch over to ViewController.swift and briefly walk through the code that’s in place. At the top of the class there are outlets for all of the UI elements that the app needs to talk to.

Below these is an MPMusicPlayerController property that is initialized with the application music player, followed immediately by an array of MPMediaItem objects that return all of the items in your music library.

Below the property declarations, viewDidLoad() calls updatePlayerLabels(_:artist:album:) to clear the three labels of any placeholder text that may have been there when loading the controller from the storyboard. It also schedules an instance of NSTimer to call refresh().

updatePlayerLabels(_:artist:album:) updates the current song name, artist and album name.

refresh() is called repeatedly by the timer. It gets the current playing item (if one exists) and calls updatePlayerLabels(_:artist:album:) to show the information corresponding to the current song that is playing – or nothing if there is no song playing. This is the method you’ll modify to update your progress bar.

The IBAction methods for the Next, Play/Pause, Previous, and Stop buttons do what you’d expect as well as guard against the event that no song is currently playing. This will prevent nasty crashes.

Finally, the table view data source and delegate methods take care of displaying the music library information, and plays the song when one is selected.

Time to switch back to PaintCode so you can export the progress bar into the project.

Adding the PaintCode Code to Your App Using StyleKit

If you’ve read our PaintCode Tutorial for Designers, you’ll know all about the StyleKit class, which is generated by PaintCode and contains all the drawing code. Canvases are automatically added to the StyleKit catalog, so your progress bar is all ready to go.

In PaintCode, click on File\Export. In the popup window, click the StyleKit button and fill out the required information as follows:

PaintCodeExport

Click the Export button. When prompted, locate the Songy project code folder and click Save.

Back in Xcode, add the exported Swift file to your project either by dragging it into the Project Navigator, or by right-clicking the Songy folder in the Project Navigator and selecting Add files to “Songy”…:

13-AddingSwiftFile

You’ve now added the drawing code to your project.

If you look at PaintCodeTutorial.swift you’ll see that it’s a simple NSObject with a drawProgressBar() method. Next you need to create a UIView subclass that calls this method to draw the progress bar.

Right-click the Songy folder in the Project Navigator and select New File…. Choose iOS\Source\Cocoa Touch Class and click Next. Name the class ProgressBar and make it a subclass of UIView. Click Next and save the file into your project directory.

Open ProgressBar.swift and uncomment drawRect(_:). By overriding this method you can do any custom drawing you need.

Call the generated PaintCode code like so in drawRect(_:):

override func drawRect(rect: CGRect) {
  PaintCodeTutorial.drawProgressBar()
}

I always forget to change the UIView class in the storyboard – so I’ll remind you of it now! :] Switch over to Main.storyboard.

Inside the storyboard, locate the UIView below the labels. It’s white, so you might not be able to see it in the scene. Select Progress View from the Document Outline. With the view selected, switch to the Identity Inspector and change the class to ProgressBar.

Changing the class name in the identity inspector

Build and run your application; you’ll see the first version of your custom progress bar:

FirstProgressBar

Yup – it’s that easy to integrate PaintCode elements in your app! Simply export the StyleKit from PaintCode and call the StyleKit drawing method from drawRect(_:) in a UIView subclass.

The bar doesn’t quite stretch to the device width. This is because you’re using the default version of the PaintCode method – you’ll fix that shortly.

One of the best features of PaintCode is its tight integration with Xcode projects. You’ll next make a few changes in PaintCode and re-export the progress bar out to Xcode.

Adding Colors in StyleKits

Your progress bar is still a boring shade of gray. However, you can make it any color you like to fit the style of your app. If you decide to change the color, it’s easy to use StyleKit to adjust it and re-export.

You’ll create the color in the StyleKit Catalog; anything you create in the catalog will be available to you in your Xcode project.

In PaintCode, click on the StyleKit tab. Click Add Color and then Add New Color…. Choose any color you like for your progress bar and change the name of the color to something that better represents the color; I used PinkColor to represent a light pink:

09-StyleKitColor1

Back in the tab for your progress bar, change the Fill color of Progress Active and the Stroke color of Progress Outline to your new color:

StrokeColor

To re-export your changes to Xcode, simply press Cmd+R or choose File\Export Again from the top menu. PaintCode conveniently remembers where you previously saved the generated code and overwrites it.

Build and run your app again; the progress bar has been magically updated:

PinkProgressBar

And you didn’t need to touch a single line of code! How cool. :]

Making a Dynamic Progress Bar

Okay, you were promised a dynamic progress bar: one that reacts to changes within the app. To get this working, you’ll add a computed property to the ProgressBar view to hold the progress of a song and call the PaintCode method using this value.

In ProgressBar.swift add these properties to the class:

private var innerProgress: CGFloat = 0.0
var progress : CGFloat {
  set (newProgress) {
    if newProgress > 1.0 {
      innerProgress = 1.0
    } else if newProgress < 0.0 {
      innerProgress = 0
    } else {
      innerProgress = newProgress
    }
    setNeedsDisplay()
  }
  get {
    return innerProgress * bounds.width
  }
}

progress looks like a lengthy computed property, but it’s simply checking the normalized newProgress value to make sure it’s not doing any drawing outside the bounds of the progress bar. The setter calls setNeedsDisplay() to redraw the progress bar while the getter returns the internal, normalized progress multiplied by the view’s bound’s width.

Change drawRect(_:) to the following:

override func drawRect(rect: CGRect) {
  PaintCodeTutorial.drawProgressBar(frame: bounds,
      progress: progress)
}

The first parameter is the bounds of the view subclass so that the progress bar will stretch appropriately. The second parameter is the song progress for the variable you set up in PaintCode.

And that’s it for the progress bar! You don’t need to do any more work in this file. However, you need to hook the progress bar up to report the song’s progress.

Connecting the Progress Bar to Music

Open ViewController.swift and locate the IBOutlet progressView. Change it from a UIView to be of type ProgressBar:

@IBOutlet var progressView: ProgressBar!

Scroll down to refresh() and add the following right before you call updatePlayerLabels(_:artist:album:) in the if section of the conditional:

if (mediaPlayer.currentPlaybackTime /
                currentSong.playbackDuration) .isNormal {
  progressView.progress = CGFloat(mediaPlayer.currentPlaybackTime /
                currentSong.playbackDuration)
} else {
  progressView.progress = 0.0
}

This code compares the current playback time versus the total duration of the song, checks that there isn’t a division by zero and updates the progress property on the progress view. This should give you a normalized value between 0 and 1.0. When you set progress, the setter in ProgressBar will update the progress bar accordingly.

In the else section of the same conditional, add the following line before calling updatePlayerLabels(_:artist:album:):

progressView.progress = 0.0

This sets progress to 0, since no song is playing.

This is what the final refresh() looks like:

func refresh() {
  if let currentSong = mediaPlayer.nowPlayingItem {
    let title = currentSong.title ?? ""
    let artist = currentSong.artist ?? ""
    let album = currentSong.albumTitle ?? ""
 
    if (mediaPlayer.currentPlaybackTime /
               currentSong.playbackDuration) .isNormal {
      progressView.progress = CGFloat(mediaPlayer.currentPlaybackTime /
               currentSong.playbackDuration)
    } else {
      progressView.progress = 0.0
    }
    updatePlayerLabels(title, artist: artist, album: album)
  } else {
    progressView.progress = 0.0
    updatePlayerLabels("", artist: "", album: "")
  }
}

That’s it; build and run your app and check out your progress bar! Remember that you’ll need a physical device to play songs and see the progress bar update:

DynamicBar1

Changing PaintCode Generated Code

At the very beginning of the track, the progress bar fill bleeds outside the progress bar outline. You can fix this by clipping the fill to stay within the outline.

Open PaintCodeTutorial.swift and find the following line in drawProgressBar(frame:number:):

progressOutlinePath.stroke()

Add the following line immediately after the line above:

progressOutlinePath.addClip()

This adds a clipping path so progressActivePath won’t bleed outside the outline any more. It’s a small visual fix, but goes a long way towards making things look polished.

Note: Instead of manually adding the clipping path. I wanted to show this so you know you can change things, play with the code and experiment with Core Graphics. However, remember that if you now go back to PaintCode and re-export the document, your code will be overwritten by the generated code.

Build and run your project one final time and check out your pixel-perfect custom dynamic progress bar:

14-ProgressBarLive

Where to Go From Here?

You can download the final PaintCode file here, and the final Xcode project file here.

In this tutorial, you created a robust element within PaintCode, set up StyleKits and Variables and exported all of that into an iOS project for your use.

With this knowledge, you could try creating other iOS elements such as buttons, spinners, segmented controls, switches, or even custom components you’ve always wanted to create but thought were too difficult to acheive in Core Graphics.

Questions? Feedback? Comments? Join the forum discussion below and share them with us!

The post PaintCode Tutorial for Developers: Custom Progress Bar appeared first on Ray Wenderlich.

Video Tutorial: Intermediate iOS Animation Part 5: Animation Delegate

PaintCode Sketch Plugin Tutorial

$
0
0

PaintCode-SketchPlugin-feature

Recently, an issue came up on a map clustering library that I support. Someone asked how to change the size and color of custom map markers and clusters. After some Googling, this didn’t look like an easy fix. So I gave a cop out answer and said to just use hard-coded PNGs.

The next day, I found out about the new PaintCode Sketch plugin. This was just what I needed — it’s a plugin that automatically generates Swift code for your Sketch illustrations. I tried it out in my app and was making dynamically sized and colored map markers in no time!

The PaintCode Sketch plugin is great because it helps bridge the gap between design and implementation. Designers can now deliver icons as Swift code instead of littering Slack with PNGs. As a bonus, the PaintCode plugin exports colors as UIColor objects — no more stringly-typed hex values!

In this tutorial, you’ll get hands-on experience with the new PaintCode sketch plugin by exporting a Sketch illustration and using it in an app. You’ll learn how to dynamically size the image and modify its colors and other properties. Let’s dive in!

Paint Code Sketch Swift Comic

Getting Started

Here’s what you need to export Swift Core Graphics code from Sketch:

Note you do not need a copy of PaintCode 2 to do this; the PaintCode Sketch plugin is an independent product that exports the Swift Core Graphics code for Sketch illustrations, without the need for PaintCode 2 itself.

Start by installing Sketch and the PaintCode Sketch plugin.

Then, download this Sketch starter file which you’ll use to generate Swift code. This tutorial does not require any Sketch skills, but check out this Sketch Tutorial for iOS Developers if you want to learn some basics.

Note: Alternatively, if you’d prefer to skip exporting the code for the Sketch illustration and jump straight into using it in an app, you can skip to ahead to the Working with the Objective-Tea Starter Project section. I’ve used Sketch and the PaintCode Sketch plugin to export the Sketch illustration to Swift code, and have the pre-generated Swift file waiting for you.

Preparing the Sketch File

Open the starter Sketch file and take a look around. Inside the main canvas area, you’ll see an image of a bubble tea cup. Below the image, there’s a color palette with nine colored squares.

Sketch layer names

On the left, there’s a panel called the Layers List. Each layer has a name like liquid, bubbles, or Mango. PaintCode will convert these names to variables and comments. It’s important to use meaningful names, because this makes the generated code easier to read.

Prep the icon

Before you jump into using the PaintCode plugin, you need to do a little prep work. First, you’ll nest the bubble tea cup image inside an Artboard.

  1. Hold down the Space key and drag the canvas to pan around until you see the image.
  2. Click Insert\Artboard from the main menu (or use the shortcut key A).
  3. Drag your mouse to create a rectangle around the image.
  4. In the Layers List, rename the Artboard to BubbleTeaCup.
  5. To center the image within the Artboard, select the blue folder icon and drag the image until it snaps to the red line guides.

Create an Artboard around the bubble tea cup

By organizing layers inside an Artboard, you’re letting PaintCode know that you want to treat them as a single image. So if you have multiple icons, you should place each one inside its own Artboard.

Prep the color palette

Besides images, you can also make a color palette. Just create an Artboard named Library and drop in some shapes with different colors.

  1. Type the A key to use the Artboard tool.
  2. Drag your mouse to enclose all the colored squares.
  3. In the Layers List, rename the Artboard to Library.

Create a Library Artboard

PaintCode converts each of these shapes into an UIColor object, using the layer name and fill color. The type of shape doesn’t matter. PaintCode ignores the border color and width as well.

Pro tip: The Library also supports gradients and shadows too. Just create a shape using one of these properties from the right inspector panel:

RC-gradientShadow

  • Gradient: Inside the Fill picker, choose Linear Gradient to produce a CGGradient.
  • Shadow: Click the plus sign + next to Shadows to produce an NSShadow. Just make sure you de-select the Fill checkbox so that PaintCode knows your intentions.

Using the Plugin to Generate Swift Code

Now that your layers are properly named and organized into Artboards, it’s time to generate some Swift code. From the Plugins menu, select PaintCode.

Select PaintCode from the plugin menu

Sketch will drop down a plugin sheet with different options.

Paint code options sheet

  • PaintCode Plugin: Register a license key or purchase one on the website.
  • Choose Drawings: Select which items you wish to export as code.
  • Platform & Language: Choose between Swift and Objective-C.
  • Settings: Add project meta data to populate the comment block at the top of the generated Swift file. Note that the Class Name defaults to StyleKit.
  • Change Code Settings…: Configure code formatting options, like indent using 2 spaces.
  • Get Code Files: Export the file to the Desktop, or drag the Swift file icon to a Finder window.

For now, make sure Library and BubbleTeaCup are checked; otherwise, leave the options as their defaults. Then select Export, and PaintCode will save a file named StyleKit.swift to the Desktop.

Working with the Objective-Tea Starter Project

All of the steps related to Sketch are behind you now. From here on out, it’s just Xcode, baby!

Download the starter project for this tutorial here. The zip file contains an Xcode project for a fake bubble tea app, Objective-Tea. In this tutorial, you’ll work on an order page where thirsty iOS developers can choose drinks of different flavors and sizes.

RC-ObjectiveTeaLogos

Launch the ObjectiveTea.xcodeproj file, then build and run. You should see a two tabs:

  • Order: Customize your bubble tea order.
  • Stores: This is a map with store locations.

Starter project screens

Your job for the rest of this tutorial is to liven up the app with colors and dynamic images.

Note: If you jumped straight to this section, download this zip file and move the StyleKit.swift file to your Desktop.

Import the StyleKit File to Xcode

By default, PaintCode uses the name StyleKit as the class and file name. Import this file into the ObjectiveTea Xcode project:

  1. Drag the StyleKit.swift file from the Desktop into the Project navigator, right above Main.Storyboard.
  2. Make sure that Copy items if needed and the ObjectiveTea target are selected.
  3. Click Finish.

Import StyleKit into Xcode

You should end up with a StyleKit.swift file in your Xcode project.

Working with Colors

At the top of the file, you’ll see a Colors section. PaintCode generates a static constant for each colored square inside the Library Artboard.

//MARK: - Colors
 
static let plum = UIColor(hue: 0.126, saturation: 1, brightness: 0.804, alpha: 1)
static let strawberry = UIColor(hue: 0.002, saturation: 0.369, brightness: 0.945, alpha: 1)
...

Set the tab bar color

Let’s test out one of these colors on the tab bar icons. The sample project already has a TabBarController subclass wired up in the Storyboard.

Within TabBarController.swift, add the following line inside viewDidLoad():

tabBar.tintColor = StyleKit.rWGreen

Build and run. The tab bar icons should be green, just like the tea leaf on the app icon.

Green tab bar tint

Set the flavor colors

All of the flavors are gray, which is not very appetizing. Next, you’re going to integrate the rest of the StyleKit colors into the app.

Within OrderViewController.swift, there’s a flavors array that generates all the flavor objects. Each of these flavors are using gray as a placeholder color:

let milkTea = UIColor.grayColor()
...
let milkTeaFlavor = Flavor(name: "Milk Tea", color: milkTea)

Replace each flavor’s color with the StyleKit version:

let milkTeaFlavor = Flavor(name: "Milk Tea", color: StyleKit.milkTea)
let coffeeFlavor = Flavor(name: "Coffee", color: StyleKit.coffee)
let taroFlavor = Flavor(name: "Taro", color: StyleKit.taro)
let matchaGreenTeaFlavor = Flavor(name: "Matcha", color: StyleKit.matcha)
let mangoFlavor = Flavor(name: "Mango", color: StyleKit.mango)
let strawberryFlavor = Flavor(name: "Strawberry", color: StyleKit.strawberry)
let plumFlavor = Flavor(name: "Plum", color: StyleKit.plum)
let yogurtFlavor = Flavor(name: "Yogurt", color: StyleKit.yogurt)

Build and run. Each flavor should now have a pretty color.

Bubble tea colors

Canvas Drawings

The next section of the StyleKit file includes canvas drawing methods. This section does all the heavy lifting of drawing vector paths. The code also looks pretty intimidating. Just be glad you didn’t have to write it by hand =].

Open StyleKit.swift and find drawBubbleTeaCup(frame:resizing:). You’ll see it looks similar to the following:

//MARK: - Canvas Drawings
 
/// ObjectiveTea
class func drawBubbleTeaCup(frame frame: CGRect = CGRect(x: 0, y: 0, width: 161, height: 221), resizing: ResizingBehavior = .AspectFit) {
  /// BubbleTeaCup
  do {
    /// Liquid
    let liquid = UIBezierPath()
    ...
    /// Straw
    /// Cup
    /// Bubbles
    /// Smile
  }
}

PaintCode adds comments based on the layer names from the Sketch file to help make the code a little more readable.

The drawing method takes two parameters:

  • frame: You can set the image size by passing in a CGRect. Otherwise, it defaults to the dimensions from the Sketch file.
  • resizing: You can pass in a content mode such as Aspect Fit, Aspect Fill, Stretch, or Center. PaintCode provides a helper enum at the bottom of the file to produce these effects.

Create a custom view

The canvas drawing methods are designed to work with custom views.

Open up BubbleTeaCup.swift. This is an empty UIView subclass that’s already wired up in the Storyboard:

import UIKit
 
class BubbleTeaCup: UIView {
}

Replace the file’s contents with the following code:

import UIKit
 
@IBDesignable // 1
class BubbleTeaCup: UIView {
  override func drawRect(rect: CGRect) {
    StyleKit.drawBubbleTeaCup(frame: bounds) // 2
  }
}
  1. IBDesignable: Gives you an image preview in the Storyboard.
  2. drawBubbleTeaCup(frame:): Draws the vector image into the current graphics context. You pass in the bounds so the image takes up the entire view.

UIView has a method called drawRect(_:) which provides a graphics context (which I like to think of as a piece of scrap paper). The drawBubbleTeaCup(frame:) method takes care of drawing the image on this piece of paper, which then ends up on the screen.

Open Main.storyboard and look for the OrderViewController scene. You should see a preview of the bubble tea cup, thanks to @IBDesignable.

IBDesignable custom view

Build and run. The bubble tea cup image should now appear on the order tab.

Custom view shows up

Canvas Images

Switch back to StyleKit.swift and find the imageOfBubbleTeaCup(frame:resizing:) method. You’ll see this converts the drawing method to its UIImage equivalent:

//MARK: - Canvas Images
 
/// ObjectiveTea
 
class func imageOfBubbleTeaCup(size size: CGSize = CGSize(width: 161, height: 221), resizing: ResizingBehavior = .AspectFit) -> UIImage {
  var image: UIImage
 
  UIGraphicsBeginImageContextWithOptions(size, false, 0)
  StyleKit.drawBubbleTeaCup(frame: CGRect(origin: CGPoint.zero, size: size), resizing: resizing)
  image = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()
 
  return image
}

Each canvas image method takes two parameters:

  • size: This takes a CGSize. Otherwise, it defaults to the dimensions taken from Sketch.
  • resizing: The content mode is forwarded to the drawing method.

This method can be useful in situations where you just want a UIImage of the drawing at a particular size.

Set the map marker icon

Let’s test out the canvas image method on the Stores tab.

Open StoresViewController.swift and scroll to the bottom. The map uses a hard-coded PNG for the map marker:

pinView?.image = UIImage(named: reuseId)

Replace this line with the following:

pinView?.image = StyleKit.imageOfBubbleTeaCup(size: CGSize(width: 32, height: 32))

Here you set the MKAnnotationView image to a 32×32 icon of the bubble tea cup.

Build and run. You should now see little bubble tea cups at each store location.

Map markers

Set the tab bar icon

You can also use the canvas image methods to set tab bar icons.

Open TabBarController.swift. The viewDidLoad() method looks like this:

override func viewDidLoad() {
  tabBar.tintColor = StyleKit.rWGreen
}

Append the following code, right after the tintColor line.

let tabBarIconSize = CGSize(width: 32, height: 32) // 1
if let firstTabItem = tabBar.items?.first { // 2
  let bubbleTeaCupImage = StyleKit.imageOfBubbleTeaCup(size: tabBarIconSize) // 3
  firstTabItem.image = bubbleTeaCupImage // 4
  firstTabItem.selectedImage = bubbleTeaCupImage // 5
}

Let’s go over this line by line:

  1. Creates a CGSize of 32×32, which seems like a good size for this particular icon.
  2. Gets a handle to the first tab bar item.
  3. Generates an UIImage of the bubble tea cup.
  4. Sets the tab bar item image.
  5. Sets the selected image.

Build and run. You should now see the bubble tea cup icon in the tab bar. Since tab bar items use template images, you won’t see the individual bubbles.

Tab Bar icon selected image

Using different image sizes

The app has an order tab where you can customize your beverage. Although there’s a cute cup of bubble tea smiling back at you, it doesn’t do anything when you toggle the options on the form yet.

Draw the image based on beverage size

The form has a segmented control which lets you choose between Regular or Large. Your job is to make the preview icon change size based on the selection.

Open BubbleTeaCup.swift, and replace its contents with the following code:

import UIKit
 
// 1
enum BeverageSize {
  case Regular, Large
}
 
@IBDesignable
class BubbleTeaCup: UIView {
  // 2
  var beverageSize: BeverageSize = .Regular {
    didSet {
      setNeedsDisplay()
    }
  }
  override func drawRect(rect: CGRect) {
    // 3
    let imageSize: CGRect
    switch beverageSize {
    case .Regular:
      imageSize = bounds.insetBy(dx: bounds.width * 0.1, dy: bounds.height * 0.1) // 4
    case .Large:
      imageSize = bounds // 5
    }
    // 6
    StyleKit.drawBubbleTeaCup(frame: imageSize)
  }
}

Let’s review this section by section:

  1. Creates an enum with beverage size options. This goes outside the class body so the rest of the app has access to it.
  2. Stores the state of the beverage size, which you’ll user later when calculating the image size. It also triggers a re-draw whenever this value changes.
  3. Calculates the image size based on the beverage size.
  4. Regular has a slightly smaller width and height.
  5. Large takes up the full view.
  6. Draws the image based on the imageSize dimensions.

When you set the beverageSize property, the view refreshes its display to reflect the new beverage size.

Wire up the segmented control

For this to actually work, you need to wire up the order form’s segmented control.

Open OrderViewController.swift and replace the sizeChange @IBAction method with the following:

@IBAction func sizeChange(sender: UISegmentedControl) {
  switch sender.selectedSegmentIndex {
  case 0:
    bubbleTeaCup.beverageSize = .Regular
  case 1:
    bubbleTeaCup.beverageSize = .Large
  default:
    break
  }
}

This sets the beverageSize property of the custom view based on the selectedSegmentIndex.

Build and run. Now when you toggle between Regular and Large, the order preview updates accordingly.

Toggle beverage size

Changing the tea color at runtime

PaintCode really shines when you have to change individual image layers at runtime. This would be a nightmare using PNGs.

In this section, you’re going to change the color of the tea based on flavor selection.

Pass in a parameter to change the color

By default, the PaintCode drawing methods expose parameters for size and stretch. In order to support color changes, you’ll need to add your own parameter.

Open StyleKit.swift and replace the following line of code:

class func drawBubbleTeaCup(frame frame: CGRect = CGRect(x: 0, y: 0, width: 161, height: 221), resizing: ResizingBehavior = .AspectFit) {

With the following:

class func drawBubbleTeaCup(frame frame: CGRect = CGRect(x: 0, y: 0, width: 161, height: 221), teaColor: UIColor = milkTea, resizing: ResizingBehavior = .AspectFit) {

You’re squeezing in an additional parameter teaColor into the method signature. You also have it default to milkTea so it doesn’t break existing code.

Next, scroll to around line 64 where the liquid layer color fill happens:

...
UIColor(hue: 0.078, saturation: 0.447, brightness: 0.843, alpha: 1).setFill() // change this
liquid.fill()
...

Replace the code so it looks like this:

...
teaColor.setFill() // now uses the parameter
liquid.fill()
...

Instead of filling the liquid with a hard-coded UIColor, you use the teaColor parameter instead.

Note: If you need to re-export the StyleKit file from Sketch, remember that your custom changes will be wiped out. If controlling layer behavior with custom parameters is something you’ll be doing often, consider using the full featured PaintCode 2 Mac app which has a neat Variables feature.

Wire up the custom view

The next step is to wire up the BubbleTeaCup class to use this new parameter.

Open BubbleTeaCup.swift, and add the following property above drawRect(_:):

var teaColor = StyleKit.milkTea {
  didSet {
    setNeedsDisplay()
  }
}

The teaColor property keeps track of the liquid color, and re-draws the view when it changes.

Within the same file, update the following line of code:

StyleKit.drawBubbleTeaCup(frame: imageSize)

To this:

StyleKit.drawBubbleTeaCup(frame: imageSize, teaColor: teaColor)

The canvas drawing method supports a new parameter, and you pass it the current teaColor.

Wire up the collection view

All of the bubble tea flavors are in a collection view at the bottom of the order tab. When a user taps a cell, you want the order preview image to change color too.

Open OrderViewController.swift and append the following line to the end of collectionView(_:didSelectItemAtIndexPath:indexPath:):

bubbleTeaCup.teaColor = selectedFlavor.color

selectedFlavor represents the Flavor object that the user tapped (i.e. Mango). Here you set the teaColor to the flavor’s color.

Build and run. Now when you choose different flavors, the order preview image updates as well.

Changing flavor colors

Hold the bubbles

Bubble tea sure has a lot of carbs! The drinks are sugary, and the bubbles are made of starchy tapioca balls. It’d be nice if there was a no-bubble option.

Pass in a parameter to change the color

In this section, you’re going to parameterize the image again. But this time, you’ll pass a flag to indicate whether or not to draw the bubbles.

Open StyleKit.swift and replace the following line of code:

class func drawBubbleTeaCup(frame frame: CGRect = CGRect(x: 0, y: 0, width: 161, height: 221), teaColor: UIColor = milkTea, resizing: ResizingBehavior = .AspectFit) {

With the following:

class func drawBubbleTeaCup(frame frame: CGRect = CGRect(x: 0, y: 0, width: 161, height: 221), teaColor: UIColor = milkTea, addBubbles: Bool = true, resizing: ResizingBehavior = .AspectFit) {

You’re inserting yet another parameter addBubbles with a default value of true.

Next, scroll to around line 157 toward the end of the bubble-related code. Replace the following line:

bubbles.fill()

With this:

if addBubbles {
  bubbles.fill()
}

You only draw the bubbles if the addBubbles parameter is true.

Wire up the custom view

Like before, the next step is to wire up the BubbleTeaCup class to use this new parameter.

Open BubbleTeaCup.swift, and add the following property below teaColor:

var bubbles = true {
  didSet {
    setNeedsDisplay()
  }
}

This is yet another property that triggers a re-draw when its value changes.

Within the same file, update the following line of code:

StyleKit.drawBubbleTeaCup(frame: imageSize, teaColor: teaColor)

To this:

StyleKit.drawBubbleTeaCup(frame: imageSize, teaColor: teaColor, addBubbles: bubbles)

Here, you pass the bubbles flag to the canvas drawing method.

Wire up the switch

All that’s left is to wire up the UISwitch in the order form.

Open OrderViewController.swift and replace the toggleBubbles @IBAction method with the following:

@IBAction func toggleBubbles(sender: UISwitch) {
  bubbleTeaCup.bubbles = sender.on
}

This updates the bubbles flag whenever the UISwitch is toggled.

Build and run. Now when you toggle the switch, the bubbles in the order preview image should disappear.

Toggles bubbles, flavor, and size

Pretty cool! Play around a bit and think back on all you’ve accomplished:

  • You’ve taken a cool illustration designed in Sketch…
  • …used the new PaintCode Sketch plugin to auto-generate Core Graphics code for that illustration…
  • …which results in smaller binary size, scalability, and the ability to dynamically customize the image at runtime!

Where To Go From Here?

You can download the final project which includes the Xcode project and Sketch file here.

To learn more about the PaintCode plugin, check out the tutorials on the official site.

If you need to dig deeper into Core Graphics, this tutorial is a good place to start. And if you don’t use Sketch but still like what the PaintCode plugin can do, consider whether PaintCode 2 is right for you.

We hope you enjoyed this tutorial, and if you have any questions or comments, please join the discussion below!

The post PaintCode Sketch Plugin Tutorial appeared first on Ray Wenderlich.

Video Tutorial: Intermediate iOS Animation Part 6: Layer Springs

OS X Stack Views with NSStackView

$
0
0

NS_StackView_feature

We’ve all been there: that moment when you start laying down the UI of your app window and it all looks great.

But then you have to make it practical.

Once there are more than a few Cocoa controls laying around, you start planning how to put Auto Layout to work so that all your views reposition and resize as desired when the user resizes the app window.

The fun starts when you add constraints in Interface Builder — things can get complex very quickly. Often, you’ll end up with constraints that contradict each other and you need to retrace your steps to find the offending constraint and adjust it to play nicely with the rest.

Stack views were introduced with the release of OS X Mavericks, and ever since, they’ve spread to watchOS (well, a similar form at least) and iOS. The APIs for each platform differ to reflect the needs of each UI paradigm, but the core concept of leveraging the power of Auto Layout without the need to use constraints remains the same.

Note: This NSStackView tutorial assumes basic familiarity with Auto Layout. If you’re new to Auto Layout go check out the Auto Layout introduction tutorial, because iOS concepts are very similar to those used for OS X.

What is a Stack View?

A stack view allows you to arrange a number of views in a stack; it looks much like a table with a single column or a single row, depending whether you set a horizontal or vertical orientation for your stack:

Figure1_1

At first glance, it might not look like much, but you’ll be surprised how much power you gain from a simple stack. You’ll also enjoy greater control of spacing between the arranged views, their alignment, and so on.

Figure2_1

And finally, you can nest stacks. That’s where the real fun starts.

Figure3_1

When to Use a Stack View in Your OS X App?

A stack view is not a silver bullet to all of your UI problems, but it does make many day-to-day tasks much easier. For instance, sometimes you can design the complete layout of a window without creating a single constraint, and that’s a pretty big win!

Stack views are pretty handy in a number of cases, for instance when:

  • You plan on using split view but don’t need the user to be able to resize its subviews
  • You have a view on top or the sides of the window that shows and hides often, e.g. a notification bar
  • You need to align groups of controls in any table-like layout
  • You need a custom toolbar somewhere inside a view
  • And so many more…

To say there are lot of applications for a stack view would be an understatement. Once you finish this tutorial and try some stack view magic you’ll be able to spot opportunities where they can help your layout within your apps.

The Tutorial Project

In this tutorial, you’re going to work on an OS X app and implement a complex UI based on stack views.

One of the key points you’ll learn is how to customize a stack view layout beyond the built-in properties. Finally, you’ll build UI animations based on stacks.

By the time you’re finished, the app will be a fully functional raywenderlich.com book store and it will look like this:

Figure4_1

Getting Started

In this NSStackView tutorial, you’ll work on an app called Book Shop. It’s a complete working app that allows people to browse books on the raywenderlich.com store and purchase them through the actual store that opens in their browser.

Start by downloading the starter project for this tutorial: BookShop-starter.

Open BookShop.xcodeproj and select Main.storyboard to have a look at the current state of the app’s interface. You’ll see that someone had a hard time designing the UI and pretty much left you a big mess:

Figure5_1

No fear — thanks to stack views, finishing the app layout is as easy as can be!

Your First Stack View

Creating stack views in Interface Builder is really easy. In fact, you better pay close attention because you might blink and not notice you created them. :]

For your first steps with stack views, you’re going to focus on the part of the app that shows the text data about the selected book: the title, the current edition and the publisher:

Figure6_1

Your first task is to align the labels Title and iOS Animations by Tutorials in a horizontal stack. This will keep those two nicely aligned.

Select the Title label, then while pressing the Command key on your keyboard, select iOS Animations by Tutorials.

Figure7_1

Now find the stack button at the bottom of the Interface Builder panel and click it once:

Figure8_1

Once you click the Stack button, look back at the labels: they now look like one entity, and that’s your first stack view!

Figure9_1

But what happened? You had two views selected.

When you clicked on the stack button, Interface Builder checked the relative position between the selected views and assumed you wanted to create a horizontal stack! Check the Attributes Inspector that shows the stack properties:

Figure10_1

But what if Interface Builder guessed wrong? How difficult is to have a vertical stack instead?

It’s as simple as choosing Vertical from the orientation drop-down and checking the result:

008-vertical

That was easy! Now go back to Horizontal for orientation and let’s move on!

Since you’re almost a pro by now, stack up the rest of the labels thusly:

  • Select Edition and 1st edition and click the stack button to stack them
  • Select Publisher and Razeware LLC and click the stack button to stack those too

Your layout should now look like this:

009-stackviews

You now have all the labels aligned horizontally in pairs. Notice how you have the same spacing between sets. Each stack view applies the default spacing of 8 points between its views.

Good going so far! Things are looking organized. :]

Nesting Stack Views

You’ve seen how easy it is to organize labels in stacks; it cost you a few little clicks. But wouldn’t it be great if you could somehow organize the three rows of text you ended up with too?

Good news — this task is almost as easy! First of all, find the document outline button towards the lower-left corner of Interface Builder, and in case you don’t already have document outline pane open, click the button to do so.

010-outline-button

In your document outline, select the three stack views while holding the Command key on your keyboard, like so:

011-selected-stacks

I hope you already guessed the next step. Click the Stack button in the bottom right to stack together those…stack views!

012-nested-stacks

Now you have three horizontal stack views stacked vertically! It looks like a little table, and that’s precisely what you wanted.

Now it’s time to look into another property of stacks that you definitely need to use when nesting stacks. The alignment property (look it up in the Property Inspector while the stack view is selected) allows you to set how the views should be aligned in the alternate axis of the stack’s orientation:

  • For Horizontal stacks, Alignment lets you arrange views on their top, center, bottom or base line
  • For Vertical stacks, Alignment lets you arrange views on their leading, center and trailing

Feel free to play with the current stack’s orientation, but ultimately, set it to Center X to center all the text rows, like so:

013-centered-vertical

Hey that looks pretty cool! And to keep momentum up, go ahead and take care of that cover image too. In the document outline, select both the stack view (the one you just created) and the book cover image:

014-stack-image-selected

I guess by now there’s almost no need to say it but in the spirit of being totally clear I will: click Stack to stack those two together! Set the orientation of the new stack to Vertical to arrange the image and the text above each other.

015-stack-image-arranged

In your app, however, you want the image to appear above the texts, unlike the current arrangement. So, unfold the stack view in the document outline and drag the image view above to re-order the arranged views, like so:

016-rearrange

The image view should remain a sub-view of its original parent and should just appear above the Stack View, which is its sibling. As soon as you do that the views will appear like this in Interface Builder:

017-rearrange2

Now change alignment to Center X and spacing to 12. This will center the image and text horizontally and add a bit of spacing between them.

Finally, select the last stack view you created and the Buy now from raywenderlich.com button. Again, click the Stack button and make sure orientation is set to Vertical, alignment is Center X and spacing to 50.

Your final layout should look like this:

018-final-layout

Customizing the Stack

So far, you’ve created a number of stack views and hopefully you’re starting to feel like a pro. :] You have the default stack view configuration, however, and in this section you’ll see how customizing the default behavior can provide even more flexibility at almost no cost.

no_cost_impossible

The stack views you created so far tutorial grew in size along with their content. In a way, you’ve only been “wrapping” views together for the sake of aligning them and nesting stacks.

Stacks though can behave a bit differently if you fix their size and let them arrange their sub-views within that given space.

Full Window Layout

So far, you’ve got two “top” layout elements in your app’s UI. The former is the table on the left, and the latter is the stack view that wraps all the details about a single book plus the purchase button.

No matter how you arrange those elements you ultimately want them to spread nicely within the app’s window.

In the document outline select the table view and the top stack view you have so far:

023_selected_table_stack

Next — no surprise here — click the Stack button at the bottom of the Interface Builder pane to stack the two selected views together, effectively bundling them into a new horizontal stack.

Now click on the Pin button, which is located close to the Stack button, and enter four zeroes in the four boxes at the top of the popup. Make sure the four red lines light up while you enter the numbers in.

024_pin_window

Finally, click Add 4 Constraints to pin your top stack view to the window, effectively making it a “full window” view.

Just to make sure all views display correctly, click Resolve Auto Layout, located to the right of the Pin button, and choose Update Frames under All Views in View Controller. This will apply all current constraints and your layout will look like this:

025_fill_window

Since the table view has a constraint that sets its width to 180 points, the stack view respects that and lets the other arranged view fill all of the remaining space. Run the project and try resizing the window.

The table view fills up the window vertically but it always keeps its width because the width is pinned with a constraint.

Shift your attention to the book details. As you resize the window, the cover image and the texts always stay centered. Since the stack that contains them grows or shrinks to fill up the space not taken by the table view, its sub-views always stayed centered.

037_window_fill

This is all you needed to do to make your layout fill up the window. That was easy, n’est–ce pas?

Now look into another area of the layout where some of that same magic you just did could come handy.

Full Table Cell Layout

The table view doesn’t look all that nice at the moment, kind of like someone just threw in an image view and a label without any concern for alignment. Annoyingly, the text gets cut out at run time:

026_table

Time for you to add some stack view goodness to that table view.

In document outline, select the cell image and label. To do that, you’ll need to drill down through the view hierarchy as shown:

027_selected_cell_views

Aaaand…drumroll…you guessed it: click the Stack button in Interface Builder. This will bundle the image and label into a vertical stack view.

With the stack still selected, set the alignment to Center X. While you still have the stack selected, click on the Pin button at the bottom of Interface Builder and pin the stack to its parent view in all directions.

028_pin_cell

Since the nearest neighbor view of the stack view is the cell view, simply pin the stack to the cell itself. Click Add 4 Constraints to finish up and close the popup.

Select the stack view and click the Resolve Auto Layout issues button (to the right of Pin) and select Update Frames. The stack view takes up the whole table cell space and it now looks like this:

029_final_cell

Run the app and note how the stack view makes your whole table layout work like a charm.

Screen Shot 2016-02-14 at 8.01.59 PM

Using Constraints on Arranged Views

Stack views give you the power of Auto Layout without the hassle of creating all the constraints yourself, but you can still design constraints manually if you want. And sometimes, you do want to do that; sometimes default settings just don’t work. :]

There’s a few small issues with your layout that would benefit from a few constraints.

Select the Buy now from raywenderlich.com button and click the Pin button at the bottom of Interface Builder. From the popup menu, click the checkbox next to width and enter 250 in the box.

022_width_const

Click Add 1 Constraint to make it so. You’re setting the button width to 250 points, giving it nice padding on the sides so it’s easy on the eyes.

Adding custom constraints is that easy!

How about you align the window contents to the top of the window? Start by selecting your current top stack view.

030_selected_top_stack

In Attributes Inspector, set alignment to Top. This should move the book details views up the window, like so:

031_top_align

Now you’re going to add a bit of spacing on the top so that the cover image is not “stuck” to the window title bar. Select the stack containing the book details (second down the hierarchy):

032_selected_second_stack

Click the Pin button and add a Top constraint with the value of 20 points:

033_top_constraint

Click Add 1 Constraint, and you’ll see that the book details stack view now has 20 points as a top margin.

034_small_window

As you see, you can leave stacks to apply the default behavior and just add a constraint here and there to customize and perfect the layout!

Working with the Arranged Views

Now that you know how to stack up your layouts, the next level is to play around with the stack contents.

The stack view itself is just a container and displays nothing on screen. It merely arranges the layout of a bunch of views, and you can access those via the arrangedSubviews property. For each arranged view, you can show and hide, animate, or remove it from the stack at will.

Stack View Animations

In this last section you’re going to learn the basics of working with arranged subviews.

First of all, in order to access your stack view from code, you need to create an outlet for it. Open ViewController.swift and add a new outlet variable to the class:

@IBOutlet weak var topStack: NSStackView!

Now switch back to Main.storyboard and drag from your ViewController to the top stack view in the document outline while pressing Command on your keyboard:

035_connect_outlet

From the popup menu, select topStack, and voila! Your stack outlet is connected.

Note: Now that you have a live outlet to the stack view you can work with it from code in the same manner you do for labels, button, and other Cocoa controls. For example you can dynamically add arranged view by calling the addArrangedSubview(_:) method on your stack view or remove and arranged view by making use of removeArrangedSubview(_:).

Run the app and check the button in the top-right corner of the window:

036_menu_button

The menu button is selected by default, but if you click it repeatedly you’ll see it toggles between selected and deselected states. The button is already connected to the method in ViewController called actionToggleListView(_:), so you can just add your code at the bottom of the method body.

First, add an empty animation at the bottom of the method:

NSAnimationContext.runAnimationGroup({context in
  //configure the animation context
  context.duration = 0.25
  context.allowsImplicitAnimation = true
 
  //perform the animation
 
}, completionHandler: nil)

runAnimationGroup() allows you create UI animations by simply listing the desired changes in the argument closure. The animations closure gets one parameter, which is the animation context – you can adjust various aspects of the animation by changing the properties on the context. So far you set the animations duration and you enable implicit animations.

Note: Unlike on iOS, in OSX there are different (but similar in effect) APIs to create animations. I personally like using NSAnimationContext.runAnimationGroup(_) because it’s the closest to what I’m using on iOS and can write my code easier and faster by just using the same approach on both platforms.

Next you can just toggle the visibility of the first arranged view of the top stack — more specifically, the table view that shows the list of books. To make all changes in the window layout animate nicely, also add a call to layoutSubtreeIfNeeded().

Just below the comment //perform the animation (but still inside the closure) insert this:

self.topStack.arrangedSubviews.first!.hidden = button.tag==0 ? true : false
self.view.layoutSubtreeIfNeeded()

This will hide or show the book list each time you click the button. Since you made your changes from within an animation block, the layout flows nicely to accommodate your changes.

Note: Just like with any other animation under Auto Layout you need to force a layout pass from inside the animations block to animate the changes you do to your views. In fact changing the hidden property on your first arranged view will be automatically animated, the rest of the arranged views however will have to change position and you’d like to animated those changes. That’s why at the end of the block you make a call to layoutSubtreeIfNeeded().

And there you have the completed raywenderlich.com book store project!

Figure4_1

For kicks, choose your favorite book from the list and click on the purchase button. This will open your default web browser and take you directly to the book store page:

038_webshop

Where to Go From Here

To see the completed project, download BookShop-completed.zip.

This tutorial covered quite a bit! You know how to:

  • Align views in your UI by bundling them in stacks
  • Design complex layouts with nested stack views
  • Use constraints to customize stack layouts
  • And finally, how to interact with the arranged subviews

If you’d like to learn more about stack views and how to use them for fun and profit, consider the following resources:

  • Apple’s NSStackView docs: Here you’ll discover more about this class’s properties and methods.
  • Mysteries of Auto Layout, part 1: In this WWDC ’15 talk you’ll learn about the motivation behind stack views and see some live demos.
  • Finally, watch the UIStackView video series right here because most of the concepts on iOS and OS X are the same.
  • if you’d like to learn more about how the book list was coded in the starter project check out this great tutorial about Cocoa table views

If you have any questions or comments on this tutorial, feel free to join the discussion below in the forums! Thanks for joining me again!

The post OS X Stack Views with NSStackView appeared first on Ray Wenderlich.

Video Tutorial: Intermediate iOS Animation Part 7: Layer Keyframes


Video Tutorial: Intermediate iOS Animation Part 8: Shape And Mask Animations

TDD, and WWDC ’16 – Podcast S05 E12

$
0
0
test driven development

Interested in test driven development? Find out more in this episode!

Join Mic, Jake, and Andy as they discuss the benefits of test driven development, before moving on to speculate about what Apple might reveal at WWDC ’16.

This is the final episode of season five, but worry not as the podcast will return on June 8th.

[Subscribe in iTunes] [RSS Feed]

Interested in sponsoring a podcast episode? We sell ads via Syndicate Ads, check it out!

Show Notes

Test Driven Development

WWDC ’16

Contact Us

Where To Go From Here?

We hope you enjoyed this episode of our podcast. Be sure to subscribe in iTunes to get notified when the next episode comes out.

We’d love to hear what you think about the podcast, and any suggestions on what you’d like to hear in future episodes. Feel free to drop a comment here, or email us anytime at podcast@raywenderlich.com.

The post TDD, and WWDC ’16 – Podcast S05 E12 appeared first on Ray Wenderlich.

NSOutlineView on OS X Tutorial

$
0
0

NSOutlineView-feature

When writing applications, you often want to show data that has a list-like structure. For example, you might want to display a list of recipes. This can be easily done with a NSTableView. But what if you want to group the recipes by appetizer or main course? Now you have a problem, because table views have no sections. Your five-layer-dip recipe is right next to your linguine del mare recipe, which just won’t do!

Thankfully, NSOutlineView provides a lot more functionality. NSOutlineView is a common component in OS X applications, and is a subclass of NSTableView. Like a table view, it uses rows and columns to display its content; unlike a table view, it uses a hierarchical data structure.

To see an outline view in action, open Xcode with an existing project and have a look at the project navigator. Click on the triangle next to the project name to expand it. You’ll see a structure like the image below: beneath the project are groups, and inside the groups are Swift or Objective-C files.

Xcode's Outline View

In this NSOutlineView on OS X tutorial, you will learn how to use an outline view to show your own hierarchical data. To do this, you’ll write a RSS Reader-like application that loads RSS Feeds from a file and shows them in an outline view.

Getting Started

The starter project can be downloaded here. Open the project and take a peek. Besides the files created by the template, there is a Feeds.plist, which is the file you’ll load the feeds from. You’ll take a closer look at it later, when creating the model classes.

Open Main.storyboard to see the prepared UI. On the left is a plain outline view, and beside it is a white area, which is the web view. Those are grouped using a horizontal stack view, which is pinned to the window edges. Stack views are the latest and greatest way to deal with Auto Layout, if you haven’t yet given them a try. You can learn all about them in Marin’s great tutorial about NSStackViews.

Starter UI

Your first task: complete the UI. To do this, double-click in the header to change the title. For the first column, change it to Feed; change the second to Date.

Change_Header

That was easy! Now select the outline view, in the document outline — you’ll find it under Bordered Scroll View – Outline View \ Clip View \ Outline View. In the Attributes Inspector, change Indentation to 5, enable Floats Group Rows and disable Reordering.

nsoutline-inspector-new

Inside the document outline on the left, click on the triangle beside Outline View to expand it. Do the same for Feed and Date. Select the Table View Cell below Date.

Date_Selection

Change the Identifier to DateCell in Identity Inspector.

Change_Cell_Identifier

Now show the Size Inspector and change Width to 102. Repeat this step for the cell below Feed, changing the Identifier to FeedCell and Width to 320.

Expand the cell below feed and select the text field named Table View Cell.

Selected_Textfield

Use the Pin and Align menus on the Auto Layout toolbar to add an Auto Layout constraint of 2 points leading, plus another constraint to center the text field vertically. You will see the constraints in Size Inspector:

Constraints

Now select the table cell again (above the text field in the layout hierarchy). Duplicate it by pressing Cmd + C and Cmd + V, then change the Identifier of the duplicate to FeedItemCell. Now you have 3 different cells, one for each type of entry that will be shown in the outline view.

FinishedCells

Select Date, and in the Identity Inspector change the Identifier to DateColumn; do the same for Feed and change it to TitleColumn:

TitleColumn

The final step is to give the outline view a delegate and a data source. Select the outline view and right- or control-click on it. Drag a line from dataSource to the blue circle that represents your view controller; repeat this to set the delegate.

Add_Delegate

Run the project and you’ll see …

First_Run

There’s an empty outline view and an error message in your console, saying you have an illegal data source. What’s wrong?

Before you can fill the outline view and get rid of the error message, you need a data model.

Data Model

The data model for an outline view is a bit different than the one for a table view. Like mentioned in the introduction, an outline view shows a hierarchical data model, and your model classes have to represent this hierarchy. Every hierarchy has a top level or root object. Here this will be a RSS Feed; the name of the feed is the root.

Press Cmd + N to create a new class. Select Cocoa Class and click Next.

Create_Feed_Class_1

Name the class Feed and make it a subclass of NSObject. Then click Next and Create on the next screen.

Create_Feed_Class_2

Replace the automatically generated code with:

import Cocoa
 
class Feed: NSObject {
   let name: String
 
   init(name: String) {
     self.name = name
   }
}

This adds a name property to your class and provides an init method that sets the property to a provided value. Your class will store its children in an array, but before you can do this, you need to create a class for those children. Using the same procedure as before, add a new file for the FeedItem class. Open the newly created FeedItem.swift and replace the content with the following:

import Cocoa
 
class FeedItem: NSObject {
  let url: String
  let title: String
  let publishingDate: NSDate
 
  init(dictionary: NSDictionary) {
    self.url = dictionary.objectForKey("url") as! String
    self.title = dictionary.objectForKey("title") as! String
    self.publishingDate = dictionary.objectForKey("date") as! NSDate
  }
}

This is another simple model class: FeedItem has a url that you will use to load the corresponding article into the web view; a title; and a publishingDate. The initializer takes a dictionary as its parameter. This could be received from a web service or, in this case, from a plist file.

Head back to Feed.swift and add the following property to Feed:

var children = [FeedItem]()

This creates an empty array to store FeedItem objects.

Now add the following class method to Feed to load the plist:

class func feedList(fileName: String) -> [Feed] {
  //1
  var feeds = [Feed]()
 
  //2
  if let feedList = NSArray(contentsOfFile: fileName) as? [NSDictionary] {
    //3
    for feedItems in feedList {
      //4
      let feed = Feed(name: feedItems.objectForKey("name") as! String)
      //5
      let items = feedItems.objectForKey("items") as! [NSDictionary]
      //6
      for dict in items {
        //7
        let item = FeedItem(dictionary: dict)
        feed.children.append(item)
      }
      //8
      feeds.append(feed)
    }
  }
 
  //9
  return feeds
 }

The method gets a file name as its argument and returns an array of Feed objects. This code:

  1. Creates an empty Feed array.
  2. Tries to load an array of dictionaries from the file.
  3. If this worked, loops through the entries.
  4. The dictionary contains a key name that is used to inititalize Feed.
  5. The key items contains another array of dictionaries.
  6. Loops through the dictionaries.
  7. Initializes a FeedItem. This item is appended to the children array of the parent Feed.
  8. After the loop, every child for the Feed is added to the feeds array before the next Feed starts loading.
  9. Returns the feeds. If everything worked as expected, this array will contain 2 Feed objects.

Open ViewController.swift, and below the IBOutlet section add a property to store feeds:

var feeds = [Feed]()

Find viewDidLoad() and add the following:

if let filePath = NSBundle.mainBundle().pathForResource("Feeds", ofType: "plist") {
  feeds = Feed.feedList(filePath)
  print(feeds)
}

Run the project; you should see something like this in your console:

[<Reader.Feed: 0x600000045010>, <Reader.Feed: 0x6000000450d0>]

You can see that you’ve successfully loaded two Feed objects into the feeds property — yay!

Introducing NSOutlineViewDataSource

So far, you’ve told the outline view that ViewController is its data source — but ViewController doesn’t yet know about its new job. It’s time to change this and get rid of that pesky error message.

Add the following extension below your class declaration of ViewController:

extension ViewController: NSOutlineViewDataSource {
 
}

This makes ViewController adopt the NSOutlineViewDataSource protocol. Since we’re not using bindings in this tutorial, you must implement a few methods to fill the outline view. Let’s go through each method.

Your outline view needs to know how many items it should show. For this, use the method outlineView(_: numberOfChildrenOfItem:) -> Int.

func outlineView(outlineView: NSOutlineView, numberOfChildrenOfItem item: AnyObject?) -> Int {
  //1
  if let feed = item as? Feed {
    return feed.children.count
  }
  //2
  return feeds.count
}

This method will be called for every level of the hierarchy displayed in the outline view. Since you only have 2 levels in your outline view, the implementation is pretty straightforward:

  1. If item is a Feed, it returns the number of children.
  2. Otherwise, it returns the number of feeds.

One thing to note: item is an optional, and will be nil for the root objects of your data model. In this case, it will be nil for Feed; otherwise it will contain the parent of the object. For FeedItem objects, item will be a Feed.

Onward! The outline view needs to know which child it should show for a given parent and index. The code for this is similiar to the previous code:

func outlineView(outlineView: NSOutlineView, child index: Int, ofItem item: AnyObject?) -> AnyObject {
  if let feed = item as? Feed {
    return feed.children[index]
  }
 
  return feeds[index]
}

This checks whether item is a Feed; if so, it returns the FeedItem for the given index. Otherwise, it return a Feed. Again, item will be nil for the root object.

One great feature of NSOutlineView is that it can collapse items. First, however, you have to tell it which items can be collapsed or expanded. Add the following:

func outlineView(outlineView: NSOutlineView, isItemExpandable item: AnyObject) -> Bool {
  if let feed = item as? Feed {
    return feed.children.count > 0
  }
 
  return false
}

In this application only Feeds can be expanded and collapsed, and only if they have children. This checks whether item is a Feed and if so, returns whether the child count of Feed is greater than 0. For every other item, it just returns false.

Run your application. Hooray! The error message is gone, and the outline view is populated. But wait — you only see 2 triangles indicating that you can expand the row. If you click one, more invisible entries appear.

Second_Run

Did you do something wrong? Nope — you just need one more method.

Introducing NSOutlineViewDelegate

The outline view asks its delegate for the view it should show for a specific entry. However, you haven’t implemented any delegate methods yet — time to add conformance to NSOutlineViewDelegate.

Add another extension to your ViewController in ViewController.swift:

extension ViewController: NSOutlineViewDelegate {
 
}

The next method is a bit more complex, since the outline view should show different views for Feeds and FeedItems. Let’s put it together piece by piece.

First, add the method body to the extension.

func outlineView(outlineView: NSOutlineView, viewForTableColumn tableColumn: NSTableColumn?, item: AnyObject) -> NSView? {
  var view: NSTableCellView?
  // More code here
  return view
}

Right now this method returns nil for every item. In the next step you start to return a view for a Feed. Add this code above the // More code here comment:

//1
if let feed = item as? Feed {
  //2
  view = outlineView.makeViewWithIdentifier("FeedCell", owner: self) as? NSTableCellView
  if let textField = view?.textField {
    //3
    textField.stringValue = feed.name
    textField.sizeToFit()
  }
}

This code:

  1. Checks if item is a Feed.
  2. Gets a view for a Feed from the outline view. A normal NSTableViewCell contains a text field.
  3. Sets the text field’s text to the feed’s name and calls sizeToFit(). This causes the text field to recalculate its frame so the contents fit inside.

Run your project. While you can see cells for a Feed, if you expand one you still see nothing.

Third_Run

This is because you’ve only provided views for the cells that represent a Feed. To change this, move on to the next step! Still in ViewController.swift, add the following property below the feeds property:

let dateFormatter = NSDateFormatter()

Change viewDidLoad() by adding the following line after super.viewDidLoad():

dateFormatter.dateStyle = .ShortStyle

This adds an NSDateformatter that will be used to create a nice formatted date from the publishingDate of a FeedItem.

Return to outlineView(_:viewForTableColumn:item:) and add an else-if clause to if let feed = item as? Feed:

else if let feedItem = item as? FeedItem {
  //1
  if tableColumn?.identifier == "DateColumn" {
    //2
    view = outlineView.makeViewWithIdentifier("DateCell", owner: self) as? NSTableCellView
 
    if let textField = view?.textField {
      //3
      textField.stringValue = dateFormatter.stringFromDate(feedItem.publishingDate)
      textField.sizeToFit()
    }
  } else {
    //4
    view = outlineView.makeViewWithIdentifier("FeedItemCell", owner: self) as? NSTableCellView
    if let textField = view?.textField {
      //5
      textField.stringValue = feedItem.title
      textField.sizeToFit()
    }
  }
}

This is what you’re doing here:

  1. If item is a FeedItem, you fill two columns: one for the title and another one for the publishingDate. You can differentiate the columns with their identifier.
  2. If the identifier is dateColumn, you request a DateCell.
  3. You use the date formatter to create a string from the publishingDate.
  4. If it is not a dateColumn, you need a cell for a FeedItem.
  5. You set the text to the title of the FeedItem.

Run your project again to see feeds filled properly with articles.

Fourth_Run

There’s one problem left — the date column for a Feed shows a static text. To fix this, change the content of the if let feed = item as? Feed if statement to:

if tableColumn?.identifier == "DateColumn" {
  view = outlineView.makeViewWithIdentifier("DateCell", owner: self) as? NSTableCellView
  if let textField = view?.textField {
    textField.stringValue = ""
    textField.sizeToFit()
  }
} else {
  view = outlineView.makeViewWithIdentifier("FeedCell", owner: self) as? NSTableCellView
  if let textField = view?.textField {
    textField.stringValue = feed.name
    textField.sizeToFit()
  }
}

To complete this app, after you select an entry the web view should show the corresponding article. How can you do that? Luckily, the following delegate method can be used to check whether something was selected or if the selection changed.

func outlineViewSelectionDidChange(notification: NSNotification) {
  //1
  guard let selectedIndex = notification.object?.selectedRow else {
    return
  }
  //2
  if let feedItem = notification.object?.itemAtRow(selectedIndex) as? FeedItem {
    //3
    let url = NSURL(string: feedItem.url)
    //4
    if let url = url {
      //5
      self.webView.mainFrame.loadRequest(NSURLRequest(URL: url))
    }
  }
}

This code:

  1. Checks if there is a selected row. If not, return early.
  2. Checks if the selected row contains a FeedItem or a Feed.
  3. If a FeedItem was selected, creates a NSURL from the url property of the Feed object.
  4. Checks whether this succeeded.
  5. Finally, loads the page.

Before you test this out, return to the Info.plist file. Add a new Entry called App Transport Security Settings and make it a Dictionary if Xcode didn’t. Add one entry, Allow Arbitrary Loads of type Boolean, and set it to YES.

Note: Adding this entry to your plist causes your application to accept insecure connections to every host, which can be a security risk. Usually it is better to add Exception Domains to this entry or, even better, to use backends that use an encrypted connection.

Change_Info_Plist

Now build your project and select a FeedItem. Assuming you have a working internet connection, the article will load after a few seconds.

Finishing Touches

Your example application is now working, but there are at least two common behaviors missing: double-clicking to expand or collapse a group, and the ability to remove an entry from the outline view.

Let’s start with the double-click feature. Open the Assistant Editor by pressing Alt + Cmd + Enter. Open Main.storyboard in the left part of the window, and ViewController.swift in the right part.

Right-click on the outline view inside the Document Outline on the left. Inside the appearing pop-up, find doubleAction and click the small circle to its right.

AssistantEditor

Drag from the circle inside ViewController.swift and add an IBAction named doubleClickedItem. Make sure that the sender is of type NSOutlineView and not AnyObject.

AddAction

Switch back to the Standard editor (Cmd + Enter) and open ViewController.swift. Add the following code to the action you just created.

@IBAction func doubleClickedItem(sender: NSOutlineView) {
  //1
  let item = sender.itemAtRow(sender.clickedRow)
 
  //2
  if item is Feed {
    //3
    if sender.isItemExpanded(item) {
      sender.collapseItem(item)
    } else {
      sender.expandItem(item)
    }
  }
}

This code:

  1. Gets the clicked item.
  2. Checks whether this item is a Feed, which is the only item that can be expanded or collapsed.
  3. If the item is a Feed, asks the outline view if the item is expanded or collapsed, and calls the appropriate method.

Build your project, then double-click a feed. It works!

The last behavior we want to implement is allowing the user to press backspace to delete the selected feed or article.

Still inside ViewController.swift, add the following method to your ViewController. Make sure to add it to the normal declaration and not inside an extension, because the method has nothing to do with the delegate or datasource protocols.

override func keyDown(theEvent: NSEvent) {
  interpretKeyEvents([theEvent])
}

This method is called every time a key is pressed, and asks the system which key was pressed. For some keys, the system will call a corresponding action. The method called for the backspace key is deleteBackward(_:).

Add the method below keyDown(_:):

override func deleteBackward(sender: AnyObject?) {
  //1
  let selectedRow = outlineView.selectedRow
  if selectedRow == -1 {
    return
  }
 
  //2
  outlineView.beginUpdates()
 
  outlineView.endUpdates()
}
  1. The first thing this does is see if there is something selected. If nothing is selected, selectedRow will have a value of -1 and you return from this method.
  2. Otherwise, it tells the outline view that there will be updates on it and when these updates are done.

Now add the following between beginUpdates() and endUpdates():

//3
if let item = outlineView.itemAtRow(selectedRow) {
 
  //4
  if let item = item as? Feed {
    //5
    if let index = self.feeds.indexOf( {$0.name == item.name} ) {
      //6
      self.feeds.removeAtIndex(index)
      //7
      outlineView.removeItemsAtIndexes(NSIndexSet(index: selectedRow), inParent: nil, withAnimation: .SlideLeft)
    }
  }
}

This code:

  1. Gets the selected item.
  2. Checks if it is a Feed or a FeedItem.
  3. If it is a Feed, searches the index of it inside the feeds array.
  4. If found, removes it from the array.
  5. Removes the row for this entry from the outline view with a small animation.

To finish this method, add the code to handle FeedItems as an else part to if let item = item as? Feed:

else if let item = item as? FeedItem {
  //8
  for feed in self.feeds {
    //9
    if let index = feed.children.indexOf( {$0.title == item.title} ) {
      feed.children.removeAtIndex(index)
      outlineView.removeItemsAtIndexes(NSIndexSet(index: index), inParent: feed, withAnimation: .SlideLeft)
    }
  }
}
  1. This code is similar to the code for a Feed. The only additional step is that here it iterates over all feeds, because you don’t know to which Feed the FeedItem belongs.
  2. For each Feed, the code checks if you can find a FeedItem in its children array. If so, it deletes it from the array and from the outline view.

Note: Not only can you delete a row, but you can also add and move rows. The steps are the same: add an item to your data model and call insertItemsAtIndexes(_:, inParent:, withAnimation:) to insert items, or moveItemAtIndex(_:, inParent:, toIndex:, inParent:) to move items. Make sure that your datasource is also changed accordingly.

Now your app is complete! Build and run to check out the new functionality you just added. Select a feed item and hit the delete key–it’ll disappear as expected. Check that the same is true for the feed as well.

Where To Go From here?

Congrats! You’ve created an RSS Feed Reader-type app with hierarchical functionality that allows the user to delete rows at will and to double-click to expand and collapse the lists.

You can download the final project here.

In this NSOutlineView on OS X tutorial you learned a lot about NSOutlineView. You learned:

  • How to hook up an NSOutlineView in Interface Builder.
  • How to populate it with data.
  • How to expand/collapse items.
  • How to remove entries.
  • How to respond to user interactions.

There is lots of functionality that you didn’t get chance to cover here, like support for drag and drop or data models with a deeper hierarchy, so if you want to learn more about NSOutlineView, take a look at the documentation. Since it is a subclass of NSTableView, Ernesto García’s tutorial about table views is also worth a look.

I hope you enjoyed this NSOutlineView on OS X tutorial! If you have any questions or comments, feel free to join the forum discussion below.

The post NSOutlineView on OS X Tutorial appeared first on Ray Wenderlich.

Video Tutorial: Intermediate iOS Animation Part 9: Gradient Animations

iOS 9 by Tutorials Updated for Xcode 7.3

$
0
0

iOS 9 by Tutorials

It’s an update storm!

Today, we’re happy to announce that iOS 9 by Tutorials is now fully up-to-date for Xcode 7.3.

Xcode 7.3 has a few small changes to Swift – mostly minor syntax things – but we wanted to make sure that all the instructions work without any issues. We also added a small new section about Swift 2.2 in the “Swift 2” chapter in the book.

In addition to updating the book for Xcode 7.3, we’ve fixed some errata pointed out by readers – thanks all!

This is a free update for existing PDF customers. Here’s how you can get your copy:

  • If you’re an iOS 9 by Tutorials PDF customer, you can download the update for free on your My Loot page (version 1.1).
  • If you haven’t picked up a copy of iOS 9 by Tutorials yet, grab your copy now.

At this point we’ve updated most of our Swift books to Xcode 7.3, but there’s a few left to come – stay tuned.

The iOS 9 by Tutorials team and I hope you enjoy this update!

The post iOS 9 by Tutorials Updated for Xcode 7.3 appeared first on Ray Wenderlich.

Viewing all 4370 articles
Browse latest View live


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