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

iOS 10 Screencast: Memory Graph Debugger


Screencast: Beginning C# Part 6: Section Review – Control Flow

How to Make a Game Like Monster Island Tutorial

$
0
0
Want to learn how to make a game like Monster Island? Read on to find out.

Want to learn how to make a game like Monster Island? Read on to find out.

In this how to make a game like Monster Island tutorial, you will level up your knowledge of the SpriteKit physics system by creating a game named ZombieCat. Your goal as a zombie, is to defeat evil cats by throwing beakers of zombie goo at them—turning them into zombie cats. To do that, you’ll implement one of the major UI features of Monster Island: A large power meter showing the strength and direction of your throw.

Zombies AND cats—what could be better!

In case you’ve never played it, Monster Island is a fun physics-based puzzle game by Miniclip in which you defeat monsters by flinging bombs at them.

If you haven’t used Apple’s SpriteKit framework before, check out Sprite Kit Swift 2 Tutorial for Beginners. This tutorial assumes you’re familiar with actions, the physics system and the scene editor.

Let’s dive in!

Getting Started

This project uses Swift 3 and requires, at a minimum, Xcode beta 4. Once you have that, go ahead and download a copy of the starter project, and look through it.

Open GameScene.sks to see the basic elements of a physics puzzle level already set up.

The walls, cats and obstacles all have physics bodies defined for them, as well as their Category Mask values set in the Attributes Inspector.

Make a game like Monster Island tutorial. Evil cats up to no good.

Evil cats up to no good.

Creating the Projectile

At this point, all you can do in the game is watch the cats quietly plotting to take over the world. Scary, right? You need a way to fight back. That way, of course, is zombie goo. :]

In GameScene.swift, add these properties just before didMove(to:)

var pinBeakerToZombieArm: SKPhysicsJointFixed?
var beakerReady = false

Add a method to create the node for your beaker of goo.

func newProjectile () {
  let beaker = SKSpriteNode(imageNamed: "beaker")
  beaker.name = "beaker"
  beaker.zPosition = 5
  beaker.position = CGPoint(x: 120, y: 625)
  let beakerBody = SKPhysicsBody(rectangleOf: CGSize(width: 40, height: 40))
  beakerBody.mass = 1.0
  beakerBody.categoryBitMask = PhysicsType.beaker
  beakerBody.collisionBitMask = PhysicsType.wall | PhysicsType.cat
  beaker.physicsBody = beakerBody
  addChild(beaker)
 
  if let armBody = childNode(withName: "player")?.childNode(withName: "arm")?.physicsBody {
    pinBeakerToZombieArm = SKPhysicsJointFixed.joint(withBodyA: armBody, bodyB: beakerBody, anchor: CGPoint.zero)
    physicsWorld.add(pinBeakerToZombieArm!)
    beakerReady = true
  }
}

Add the following line to didMove(to:):

newProjectile()

This is a fairly standard example of creating a new SKSpriteNode, setting its properties, adding a SKPhysicsBody and adding it to the scene. Two properties you might not be familiar with are categoryBitMask and collisionBitMask. These mask values are how the physics system identifies which sprites interact with each other.

Each physics body has a categoryBitMask property you set to one of the values defined in the PhysicsType struct located at the top of GameScene.swift. Sprites will only collide with or bounce off objects where the categoryBitMask matches the other object’s collisionBitMask.

The beaker is attached to the zombie with a SKPhysicsJoint. A fixed joint keeps two physics bodies in the same relative position. In this case, the beaker will move with the arm body, until the joint is removed.

Note: The physics simulation uses two types of body interactions, collision and contact.

Collision: In this type of interaction, the two sprites bounce off of each other like a ball off a wall. The physics simulation automatically takes care of the collision calculation, so you don’t have to deal with angles or differences in mass.

Contact: This interaction alerts you when two objects touch or overlap. The moving object will continue to move through the other object, unless you change its motion manually. You’d use contacts to be informed when an event happens, such as a ball crossing a goal line, without changing the object’s motion.

For more details about these interactions, or bit masks in general, the Making Contact section of How To Create a Breakout Game with Sprite Kit and Swift gives a great explanation.

Build and run to see your new beaker of zombie goo. You’re almost ready to attack those cats!

New beaker appears on screen

bloop

Throwing the Beaker

Now that you’ve got the beaker in the game, you need to be able to use it as a weapon.

You have to beaker-ful with zombie goo. It could create a cat-atrophy.

Meow.

To throw the beaker, all you have to do is remove the SKSKPhysicsJointFixed and give it an impulse in the physics system. An impulse is like a kick, represented by a vector that has both an X and a Y component.

Add the following methods to GameScene.swift:

func tossBeaker(strength: CGVector) {
  if beakerReady == true {
    if let beaker = childNode(withName: "beaker") {
      if let arm = childNode(withName: "player")?.childNode(withName: "arm") {
        let toss = SKAction.run() {
        self.physicsWorld.remove(self.pinBeakerToZombieArm!)
        beaker.physicsBody?.applyImpulse(strength)
        beaker.physicsBody?.applyAngularImpulse(0.1125)
        self.beakerReady = false
      }
      let followTrough = SKAction.rotate(byAngle: -6*3.14, duration: 2.0)
 
      arm.run(SKAction.sequence([toss, followTrough]))
    }
 
    // explosion added later
    }
  }
}
 
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  tossBeaker(strength: CGVector(dx: 1400, dy: 1150))
}

When using the physics system, you change the motion of a sprite through its physics body, not the sprite itself. SKPhysicsBody has two methods you could use to throw the beaker, applyForce and applyImpulse. Since you want the change to be instantaneous, use applyImpulse. Usually, thrown objects spin while in the air, and applyAngularImpulse simulates that. You can adjust the angular impulse to get the desired amount of spin, or even change its direction by using a negative number.

Don’t forget to remove the SKPhysicsJoint, or the beaker will stay attached to the zombie hand.

Build and run the game. When you tap on the screen, the beaker should fly around. Notice how the beaker bounces off of the walls and cats.

Make a game like Monster Island tutorial. A beaker is in flight.

Wheeee!

But despite all that spinning and bouncing, there’s no explosion. For that, you need the explosion effect.

Adding the Explosion Animation

To display the explosion image, you’ll need a SKSpriteNode. You may be wondering where the best place is to position the explosion. There are several answers, but one of the simplest is to add it as a child of the beaker.

Add the following to the end of newProjectile():

let cloud = SKSpriteNode(imageNamed: "regularExplosion00")
cloud.name = "cloud"
cloud.setScale(0)
cloud.zPosition = 1
beaker.addChild(cloud)

This creates a new sprite and adds it as a child node of the beaker, meaning the two will move and rotate together. You set the scale to zero to hide the sprite, since the explosion happens later. Setting the zPosition ensures the cloud appears on top of the beaker instead of underneath.

To see the explosion, add the following to tossBeaker(strength:) replacing the explosion added later comment:

if let cloud = beaker.childNode(withName: "cloud") {
 
  // 1
  let fuse = SKAction.wait(forDuration: 4.0)
  let expandCloud = SKAction.scale(to: 3.5, duration: 0.25)
  let contractCloud = SKAction.scale(to: 0, duration: 0.25)
 
  // 2
  let removeBeaker = SKAction.run() {
    beaker.removeFromParent()
  }
  let boom = SKAction.sequence([fuse, expandCloud, contractCloud, removeBeaker])
 
  // 3
  let respawnBeakerDelay = SKAction.wait(forDuration: 1.0)
  let respawnBeaker = SKAction.run() {
    self.newProjectile()
  }
  let reload = SKAction.sequence([respawnBeakerDelay, respawnBeaker])
 
  // 4
  cloud.run(boom) {
    self.run(reload)
  }
}

Taking this step-by-step:

  1. The first three actions wait 4 seconds before making the cloud grow and shrink in the form of an explosion. Feel free to experiment with these values for different effects.
  2. Normally, this would be a simple removeFromParent action, but these actions run on the cloud node. You need to remove the beaker node instead, so you define a runBlock action. Then you combine the actions in a sequence.
  3. These actions give you another beaker to toss at the cats.
  4. Finally, you run the sequence of actions from Step 2 on the cloud node. While you could have the reload actions in the main sequence action, the completion block will come in handy later.

Build and run to see how dangerous zombie goo can be.

Make a game like Monster Island tutorial. boom

Down with the ferocious felines!

Animate the Explosion

You’ve got an explosion now, but it’s pretty basic. To really knock those kitties off their paws, animate the explosion during the expansion and contraction step. The starter project includes images regularExplosion00.png through regularExplosion08.png, and here you’ll add an action that cycles through them.

First, add a property to the top of GameScene.swift:

var explosionTextures = [SKTexture]()

Now add the following to the end of didMove(to:):

for i in 0...8 {
  explosionTextures.append(SKTexture(imageNamed: "regularExplosion0\(i)"))
}

This builds the array of SKTextures for the animation.

Next, find section 2 of the tossBeaker(strength:) method and replace the line let boom = SKAction.sequence... with the following:

let animate = SKAction.animate(with: explosionTextures, timePerFrame: 0.056)
 
let expandContractCloud = SKAction.sequence([expandCloud, contractCloud])
let animateCloud = SKAction.group([animate, expandContractCloud])
 
let boom = SKAction.sequence([fuse, animateCloud, removeBeaker])

You calculate the value for timePerFrame by dividing the total duration for the expand and contract animation (0.5 s) by the number of frames (9).

Build and run to see your upgraded explosion.

The explosion animation now uses multiple frames.

Your dog would approve. :]

Setting the Explosion Range

When the beaker explodes, you’ll want to know which cat sprites are within range of the explosion. One way to do this is to create a separate SKPhysicsBody for the explosion and use the contact system to be notified when the explosion touches a cat. However, since each SKSpriteNode can only have one physics body attached to it, you’ll create an invisible node for the explosion radius and add it to the beaker as a child.

Add the following to the end of newProjectile():

let explosionRadius = SKSpriteNode(color: UIColor.clear, size: CGSize(width: 200, height: 200))
explosionRadius.name = "explosionRadius"
 
let explosionRadiusBody = SKPhysicsBody(circleOfRadius: 200)
explosionRadiusBody.mass = 0.01
explosionRadiusBody.pinned = true
explosionRadiusBody.categoryBitMask = PhysicsType.explosionRadius
explosionRadiusBody.collisionBitMask = PhysicsType.none
explosionRadiusBody.contactTestBitMask = PhysicsType.cat
 
explosionRadius.physicsBody = explosionRadiusBody
beaker.addChild(explosionRadius)

After you create the explosion physics body, you set its mass property to 0.01 to minimize the amount of mass the explosionRadiusBody will add to the beakerBody.

Notice how explosionRadiusBody has none for its collisionBitMask. You don’t want this extra “bubble” around the beaker to collide with anything, because then it would look like the beaker bounced before it hit the object. You do want the contactTestBitMask set to cat, so that the system will recognize those sprites overlapping as a contact.

Modify the if let cloud statement in tossBeaker(strength:) to look like:

if let cloud = beaker.childNode(withName: "cloud"),
   let explosionRadius = beaker.childNode(withName: "explosionRadius") {

Next, add the following to section 2 in tossBeaker(strength:), just after the let animate... line:

let greenColor = SKColor(red: 57.0/255.0, green: 250.0/255.0, blue: 146.0/255.0, alpha: 1.0)
let turnGreen = SKAction.colorize(with: greenColor, colorBlendFactor: 0.7, duration: 0.3)
 
let zombifyContactedCat = SKAction.run() {
  if let physicsBody = explosionRadius.physicsBody {
    for contactedBody in physicsBody.allContactedBodies() {
      if (physicsBody.contactTestBitMask & contactedBody.categoryBitMask) != 0  ||
        (contactedBody.contactTestBitMask & physicsBody.categoryBitMask) != 0  {
        contactedBody.node?.run(turnGreen)
        contactedBody.categoryBitMask = PhysicsType.zombieCat
      }
    }
  }
}

This action finds all the physics bodies in contact with the explosionRadius body and uses the colorize(with:colorBlendFactor:duration:) action to turn the new zombie cat a putrid green color.

The if statement with contactTestBitMask and categoryBitMask is there because the allContactedBodies() method returns all the SKPhysicsBody objects touching the given body, instead of only the ones that match the contactTestBitMask. This statement filters out the extra physics bodies.

Change the expandContractCloud action to this:

let expandContractCloud = SKAction.sequence([expandCloud, zombifyContactedCat, contractCloud])

Update the collisionBitMask for the beaker in newProjectile() to:

beakerBody.collisionBitMask = PhysicsType.wall | PhysicsType.cat | PhysicsType.zombieCat

Without this change, the beaker would pass through the zombie cats—which would make sense if the zombie goo turned the cats into ghosts, but sadly, it does not.

Build and run. The beaker should explode next to the cat on the right, turning him into a zombie cat. Finally!

Make a game like Monster Island tutorial. One of the cats has been turned into a zombie.

Meow – Brains!

Making Sprites React

Now that the cats know what’s coming, it would be great to show how afraid they are of your beaker of goo. Since you already have a SKPhysicsBody object to tell when the beaker is close to a cat, you can have the contact system notify you when this body touches a cat node. The system does this by calling delegate methods in your class. You’ll set that up next.

First, since you want to change the image texture for the cat sprites when contact starts, then revert it when it ends, it makes sense to store these textures in a property for easy access. Add these properties to the property section at the top of GameScene.swift:

let sleepyTexture = SKTexture(imageNamed: "cat_sleepy")
let scaredTexture = SKTexture(imageNamed: "cat_awake")

To keep your code nice and organized, add a class extension at the bottom of GameScene.swift to conform to the SKPhysicsContactDelegate protocol:

// MARK: - SKPhysicsContactDelegate
extension GameScene: SKPhysicsContactDelegate {
 
  func didBegin(_ contact: SKPhysicsContact) {
    if (contact.bodyA.categoryBitMask == PhysicsType.cat) {
      if let catNode = contact.bodyA.node as? SKSpriteNode {
        catNode.texture = scaredTexture
      }
    }
 
    if (contact.bodyB.categoryBitMask == PhysicsType.cat) {
      if let catNode = contact.bodyB.node as? SKSpriteNode {
        catNode.texture = scaredTexture
      }
    }
  }
 
  func didEnd(_ contact: SKPhysicsContact) {
    if (contact.bodyA.categoryBitMask == PhysicsType.cat) {
      if let catNode = contact.bodyA.node as? SKSpriteNode {
        catNode.texture = sleepyTexture
      }
    }
 
    if (contact.bodyB.categoryBitMask == PhysicsType.cat) {
      if let catNode = contact.bodyB.node as? SKSpriteNode {
        catNode.texture = sleepyTexture
      }
    }
  }
}

Both methods are almost identical, except that the first changes the texture to the afraid cat, and the second sets it back to the sleepy cat. When this method is called, it is passed a SKPhysicsContact object, which contains the two bodies that generated the contact as bodyA and bodyB. One quirk of this system: there is no guarantee which body will be A and which will be B, so it’s helpful to test both. If the categoryBitMask of that body matches the value for cat, you can reassign the texture of that body.

Next, add the following line to the end of didMove(to:):

physicsWorld.contactDelegate = self

This assigns the GameScene class as the delegate for the physics contact system. The system will call didBegin(_:) and didEnd(_:) on the delegate each time the appropriate physics bodies touch or stop touching. The values of categoryBitMask and contactTestBitMask determine which bodies trigger these method calls.

You’ll need to switch from the afraid cat texture back to sleepy cat if the cat turns into a zombie (zombies aren’t afraid anymore, obviously). Update the zombifyContactedCat action in tossBeaker(strength:) to this:

let zombifyContactedCat = SKAction.run() {
  if let physicsBody = explosionRadius.physicsBody {
    for contactedBody in physicsBody.allContactedBodies() {
      if (physicsBody.contactTestBitMask & contactedBody.categoryBitMask) != 0  ||
        (contactedBody.contactTestBitMask & physicsBody.categoryBitMask) != 0  {
        if let catNode = contactedBody.node as? SKSpriteNode {
          catNode.texture = self.sleepyTexture // set texture to sleepy cat
        }
        contactedBody.node?.run(turnGreen)
        contactedBody.categoryBitMask = PhysicsType.zombieCat
      }
    }
  }
}

It’s a simple addition, but having the enemies in a game react to their surroundings, especially their impending doom, can add a lot of fun and anticipation.

Build and run to see the effect.

Cat is afraid because the exploding beaker is near.

Oh noes

Power Meter

The beaker throw is looking great, but you need to get that pesky remaining cat. It’s time to add the power meter so you can adjust the strength and angle of your throw.

In GameScene.sks, drag a Color Sprite from the object library into your scene for the base arrow. Set the name, texture, position and anchor point attributes to the following values:

Sprite settings for angle meter.

Sprite settings for angle meter.

Next, drag a second Color Sprite into the scene for the power indicator, and set its name, parent, texture, position, anchor point, and zPosition attributes:

Sprite settings for power meter.

Sprite settings for power meter.

The arrow tells you the direction of the thrown beaker, and the size of the green bar is the strength of the throw. Making the arrow the parent of the green bar means that the two will rotate together, and the anchor point setting makes sure that the arrow rotates around its end, instead of the center of the sprite.

Build and run to see how it looks.

Added sprite for the power meter.

Still need more power.

Accessing the Power Meter From Code

Tracking touches as you drag your finger across the screen doesn’t have to be complicated. Instead of calculating based on touch directly, you can add a UIGestureRecognizer to do the heavy lifting.

In this case, a UIPanGestureRecognizer is perfect, since it measures how far your finger has moved from the starting point in either direction.

Add these properties to GameScene.swift:

var previousThrowPower = 100.0
var previousThrowAngle = 0.0
var currentPower = 100.0
var currentAngle = 0.0
var powerMeterNode: SKSpriteNode? = nil
var powerMeterFilledNode: SKSpriteNode? = nil

Here you keep track of the current and previous values for power and angle, along with references to the power meter nodes so they can move.

The way UIPanGestureRecognizer works is that you provide an update method for it to call. Add this to the end of GameScene.swift just after touchesBegan(_:with:):

func handlePan(recognizer:UIPanGestureRecognizer) {
  if recognizer.state == UIGestureRecognizerState.began {
    // do any initialization here
  }
 
  if recognizer.state == UIGestureRecognizerState.changed {
    // the position of the drag has moved
    let viewLocation = recognizer.translation(in: self.view)
    print("x: \(viewLocation.x) y: \(viewLocation.y)")
  }
 
  if recognizer.state == UIGestureRecognizerState.ended {
    // finish up
    tossBeaker(strength: CGVector(dx: 1600, dy: 1100))
  }
}

Shortly after you start sliding your finger on the screen, the UIPanGestureRecognizer recognizes this as a pan and calls your update method, with the UIPanGestureRecognizer as a parameter. The state of the recognizer tells you if the pan has just started, is moving, or has just ended, giving you a chance to respond appropriately in the update method.

Scroll up to didMove(to:) and add the following before the end of the method:

powerMeterNode = childNode(withName: "powerMeter") as? SKSpriteNode
powerMeterFilledNode = powerMeterNode?.childNode(withName: "powerMeterFilled") as? SKSpriteNode
 
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
view.addGestureRecognizer(panRecognizer)

Here you get the power meter nodes from GameScene.sks, then add a UIPanGestureRecognizer to the scene.

Finally, delete the touchesBegan(_:) method.

Build and run the app. As you scroll your finger across the screen, look at Xcode’s console window, which will show you the current displacement, meaning the distance from your initial touch to your finger’s current position.

Console output from gesture recognizer

Sample console output

Take a look at the sign of the numbers in each direction. Notice that dragging your finger upwards makes the y values negative, not positive. This is because the UIPanGestureRecognizer works in the UIKit coordinate system, where the origin is in the upper left, instead of the SpriteKit coordinate system, where the origin is the lower left.

Shows translation values for several touch values

UIPanGestureRecognizer Translation

The power meter isn’t moving, however, so you’ll tackle that next.

Updating the Meter

A meter that doesn’t move isn’t very helpful, so here you’ll update it to reflect a user’s touch.

For this game, the x component of the translation will change the power from 0% to 100%, while the y component will change the angle from 0° (horizontal) to 90° (vertical). To achieve this, add a method to do the calculations:

func updatePowerMeter(translation: CGPoint) {
  // 1
  let changeInPower = translation.x
  let changeInAngle = translation.y
  // 2
  let powerScale = 2.0
  let angleScale = -150.0
  // 3
  var power = Float(previousThrowPower) + Float(changeInPower) / Float(powerScale)
  var angle = Float(previousThrowAngle) + Float(changeInAngle) / Float(angleScale)
  // 4
  power = min(power, 100)
  power = max(power, 0)
  angle = min(angle, Float(M_PI_2))
  angle = max(angle, 0)
  // 5
  powerMeterFilledNode?.xScale = CGFloat(power/100.0)
  powerMeterNode?.zRotation = CGFloat(angle)
  // 6
  currentPower = Double(power)
  currentAngle = Double(angle)
}

Here’s a summary of what’s happening:

  1. Split the translation value into an x part for changing power, and a y part for changing angle.
  2. Define scale factors for power and angle changes. The values need to be scaled down, otherwise a small finger movement will change the power from 0 to 100%. Larger factors mean it takes a longer pan gesture to produce a given change in power or angle. Don’t make the factors too large, or you will run out of screen before you get the value you want. The angle scale value is negative, because of the flipped sign of the values coming from the gesture recognizer.
  3. Compute the new power and angle by taking the previous value and adding the change, dividing by the scale factors from part 2. Starting with the previous values keeps the arrow from having a jump back to 0 power with every new gesture.
  4. Make sure the power and angle values are between the minimum and maximum values that make sense.
  5. Adjust the sprite parameters to match the computed power and angle.
  6. Save these computed values so that when the gesture ends, you can provide the right impulse to the beaker.

Each time the UIPanGestureRecognizer updates, you compute the new power from 0 to 100 and use the xScale property to stretch the green bar accordingly. At the same time, you compute the updated angle and set the zRotation on the entire meter to make it rotate. Since rotating an SKSpriteNode also rotates its internal x and y axes, you can set the xScale property on the power bar to scale it horizontally regardless of the orientation of the power arrow.

Next, find the section of handlePan(recognizer:) where you check for UIGestureRecognizerState.changed, and update it to call this new method:

if recognizer.state == UIGestureRecognizerState.changed {
  // the position of the drag has moved
  let translation = recognizer.translation(in: self.view)
  updatePowerMeter(translation: translation)
}

Build and run. Now, dragging your finger around the screen adjusts both the green power bar as well as the angle of the arrow.

Power meter adjusts based on touch input.

This one is juuusst right.

Throwing With the Correct Impulse

The last thing to do is use the computed power and angle, instead of the hard coded values, to throw the beaker.

In the section of handlePan(recognizer:) where you check for UIGestureRecognizerState.ended, update the if statement to look like:

if recognizer.state == UIGestureRecognizerState.ended {
  // finish up
  let maxPowerImpulse = 2500.0
  let currentImpulse = maxPowerImpulse * currentPower/100.0
 
  let strength = CGVector( dx: currentImpulse * cos(currentAngle),
                           dy: currentImpulse * sin(currentAngle) )
  tossBeaker(strength: strength)
}

Here you put together the strength vector by calculating its x and y values.

If you’re not familiar with turning a vector into a x and y components, you make use of some functions from trigonometry.

X and Y Components of a Vector

X and Y Components of a Vector

You scale a maximum value down to currentImpulse, which is r in the diagram. θ is the angle from the vector to the x-axis, which you have as currentAngle.

Add these lines to tossBeaker(strength:) at the end of section 1:

previousThrowPower = currentPower
previousThrowAngle = currentAngle

Build and run; the beaker will now use your custom values. See if you can get the last remaining cat!

Make a game like Monster Island tutorial. Projectile thrown with a custom angle and power.

Get that cat right meow!

Win or Lose

You’re almost done! All that’s left is to track whether you convert all the cats to zombies before running out of beakers.

Your GameScene.sks file already has labels for the number of beakers and cats remaining, so you just need to add the code. Add the following to the property section of GameScene.swift:

var beakersLeft = 3
var catsRemaining = 2

Now add the following method:

func updateLabels() {
  if let beakerLabel = childNode(withName: "beakersLeftLabel") as? SKLabelNode {
    beakerLabel.text = "\(beakersLeft)"
  }
 
  if let catsLabel = childNode(withName: "catsRemainingLabel") as? SKLabelNode {
    catsLabel.text = "\(catsRemaining)"
  }
}

This method simply updates the labels onscreen to match the current values.

Add this method:

func checkEndGame() {
  if catsRemaining == 0 {
    print("you win")
    if let gameOverScene = GameOverScene(fileNamed: "GameOverScene") {
      gameOverScene.scaleMode = scaleMode
      gameOverScene.won = true
      view?.presentScene(gameOverScene)
    }
    return
  }
 
  if beakersLeft == 0 {
    print("you lose")
    if let gameOverScene = GameOverScene(fileNamed: "GameOverScene") {
      gameOverScene.scaleMode = scaleMode
      view?.presentScene(gameOverScene)
    }
  }
}

The game is over when you run out of beakers or if you convert all the cats to zombies. The files for GameOverScene.sks and GameOver.swift are included in the starter project.

Find the zombifyContactedCat action inside the tossBeaker(strength:) method and change it to:

let zombifyContactedCat = SKAction.run() {
  if let physicsBody = explosionRadius.physicsBody {
    for contactedBody in physicsBody.allContactedBodies() {
      if (physicsBody.contactTestBitMask & contactedBody.categoryBitMask) != 0  ||
        (contactedBody.contactTestBitMask & physicsBody.categoryBitMask) != 0  {
        if let catNode = contactedBody.node as? SKSpriteNode {
          catNode.texture = self.sleepyTexture
        }
        contactedBody.node?.run(turnGreen)
        self.catsRemaining -= 1
        contactedBody.categoryBitMask = PhysicsType.zombieCat
      }
    }
  }
}

The main change you made was subtracting 1 from the catsRemaining property. You do this immediately after turning the cat green to keep track of the number of cats remaining.

Finally, update the completion block in section 4 of tossBeaker(strength:) to:

cloud.run(boom) {
  self.beakersLeft -= 1
  self.run(reload)
  self.updateLabels()
  self.checkEndGame()
}

This subtracts the thrown beaker from the internal count and updates the labels to the current values, then checks to see if you won or lost the game.

Build and run. As you play, you should see the labels displaying the number of cats and beakers remaining. The game also displays whether you won.

Win and lose game splash screen.

When you zombie-fy all the cats, you win!

Finishing Touches

For one last bit of flair, add a particle emitter to the beaker. The starter project includes BeakerSmoke.sks, which looks like a toxic green cloud coming from the beaker, and BeakerSparkTrail.sks, which looks like a burning fuse to ignite the goo. You can add these to the beaker by adding the following lines to tossBeaker(strength:), between sections 1 and 2.

if let sparkNode = SKEmitterNode(fileNamed: "BeakerSparkTrail") {
  beaker.addChild(sparkNode)
}
 
if let smokeNode = SKEmitterNode(fileNamed: "BeakerSmoke") {
  smokeNode.targetNode = self
  beaker.addChild(smokeNode)
}

The targetNode property changes which node the particles themselves are added to, in this case the scene node itself. If the smoke particles are added to the beaker node, the smoke spins around as the beaker spins, which doesn’t look right.

Build and run, then admire your handiwork.

The beaker now leaves a smoke trail and has sparks from a fuse.

Danger! Danger!

Voila! Those cats don’t stand a chance. ;]

Note: No cats were harmed in the implementation of this tutorial!

Where to Go From Here?

Download the completed project here.

In this tutorial, you used SpriteKit’s physics system to create a game similar to Monster Island, only better since it zombie-fies cats! You learned how to create and throw a projectile, animate a contact explosion and make sprites react to their surroundings. You also learned to incorporate a power meter to measure the user’s touch in order to throw the projectile.

There are tons of levels you can create using the tools learned in this tutorial. You can also explore ideas like obstacles that move and walls that can be destroyed. The options are endless!

For more about creating games with SpriteKit, check out 2D iOS & tvOS Games by Tutorials.

I hope you enjoyed this tutorial. If you have comments or questions, please join the forum discussion below.

Artwork by Vicki Wenderlich and kenney.nl.

The post How to Make a Game Like Monster Island Tutorial appeared first on Ray Wenderlich.

raywenderlich.com at #Pragma Conference 2016

$
0
0

Pragma-feature

We are happy to announce that we are one of the proud sponsors of #Pragma Conference 2016, this October in Verona, Italy.

Last year’s conference was a hit and the line up for 2016 is looking quite promising!

This year, one of our long time tutorial team members, Ellen Shapiro, will be giving a talk. Ellen hasn’t chosen the title of her talk yet, but she promises it will be awesome!

Also, the organizer of #Pragma Conference, #pragma mark, has been kind enough to set up a 10% off discount for all raywenderlich.com readers. To get it, just order a ticket with the discount code PRAGMARAY10.

Also stay tuned for our official raywenderlich.com conference, RWDevCon, coming in March. Ticket sales open very soon *hint hint*. :]

The post raywenderlich.com at #Pragma Conference 2016 appeared first on Ray Wenderlich.

RWDevCon 2017: Ticket Sales Open in 1 Week!

$
0
0
RWDevCon 2017: Ticket Sales Open in 1 Week!

RWDevCon 2017: Ticket Sales Open in 1 Week!

This year we ran our 2nd annual conference focused on high quality hands-on tutorials called RWDevCon.

The conference was a huge hit and got rave reviews, so we are running it for the 3rd time next March! This year we’re making a number of improvements, including:

  • Optional Pre-Conference Workshop: We’re adding an optional 3rd day to the conference – your choice of a workshop on either Advanced App Architecture, or Advanced Apple Debugging and Reverse Engineering.
  • Cherry Blossoms: The conference is during cherry blossom season in D.C. – you should consider bringing the family and making a trip out of it! :]

This is just a quick heads-up that ticket sales for the conference will open up in 1 week, on Mon Aug 15 @ 9:00 AM EST.

And even better, the first 75 people who buy tickets will get $100 off.

For the past two years, the tickets have sold out very quickly, so if you’re interested in attending, be sure to snag your ticket while you still can.

If you’d like a reminder when tickets go on sale, sign up for our raywenderlich.com weekly newsletter. We hope to see you at the conference!

The post RWDevCon 2017: Ticket Sales Open in 1 Week! appeared first on Ray Wenderlich.

UIActivityViewController Tutorial: Sharing Data

$
0
0
UIActivityViewController tutorial

UIActivityController is the shiznay!

A lot of developers want to be able to share their app data via email, Messages, or AirDrop. Sharing is a convenient way for users to send data to each other or between devices – and it may even net you some new customers!

Luckily, since iOS6 Apple has provided the handy but much overlooked UIActivityViewController class which provides a clean interface for sharing and manipulating data inside your app. You’re going to learn everything you need to know in this UIActivityViewController tutorial!

To setup sharing inside your app you just have to configure a few keys inside your applications Info.plist file and handle a few system callbacks inside your applications AppDelegate. Once setup, iOS can open your app with the URL pointing to the data to import or export.

Ready for some beer sharing fun? Read on.

Getting Started

Start by downloading the starter project for this tutorial, which is a modified version of the Beer Tracker app used in a previous tutorial. Build and run (Product \ Run or ⌘R) the project in Xcode; you’ll see the following:

UIActivityViewController tutorial

Well, that’s no good, there are no beers to share. Lets get started so you can start sharing wonderful beers with everyone.

UTIs and your Plist

The first thing you need to do is set up your Info.plist to let iOS know your app can handle Beer Tracker Documents. To do this you need to register your app as being able to handle certain Uniform Type Identifiers, or UTIs, exporting any UTIs that are not already known by the system.

In summary, UTIs are unique identifiers that represent documents. There are UTIs already built-in to iOS for handling common document types such as public.jpeg or public.html.

You’re going to register your app to handle documents with the com.raywenderlich.BeerTracker.btkr UTI representing the description of a beer. You’ll tell iOS information about the UTI such as what file name extension it uses, what mime-type it’s encoded as when sharing and finally the file’s icon.

So let’s see it in action! Open Info.plist, and add the following entries under the Information Property List key:

UIActivityViewController tutorial

You can read up on what each of these value’s mean in Apple’s UTI guide, but here are the important things to note:

  • The Document types entry defines what UTIs your app supports – in your case, the com.raywenderlich.BeerTracker.btkr UTI, as an Owner/Editor.
  • The Document types is also where you set the names of the icons iOS should use when displaying your file type. You’ll need to make sure you have an icon for each of the sizes listed in the plist.
  • The Exported Type UTIs entry gives some information about com.raywenderlich.BeerTracker.btkr, since it isn’t a public UTI. Here you define files ending in .btkr, or files that have a mime type of application/beertracker can be handled by your app.

Believe it or not, by setting these keys, you have informed iOS to start sending your app files that end with the .btkr extension. You can test this out by emailing yourself a copy of this sample beer file. Please make sure you unzip the file before emailing it to yourself otherwise both the file extension UTI and mime type will be wrong.

UIActivityViewController tutorial

You can tap on the attachment and it will prompt you to open the beer in the Beer Tracker app. Selecting Beer Tracker will open the app, however it won’t load the data from the sample file because you haven’t implemented the code for that yet.

Now that you are a UTI wizard, lets sprinkle some magic.

Note: If you don’t see “Copy to Beer Tracker” in the UIActivityViewController displayed after tapping the attached file in your email, you may need to edit the order of supported applications by scrolling to the end of the list, selecting More, and movings “Copy to Beer Tracker” to the top of the list.

Importing App Data

Before you can handle opening data from the file, you’ll need some code that can work with the file passed. Open Beer.swift, and replace the importDataFromURL(_:) method with the following:

static func importDataFromURL(url: NSURL) {
  // 1
  guard let dictionary = NSDictionary(contentsOfURL: url),
    beerInfo = dictionary as? [String: AnyObject],
    name = beerInfo[Keys.Name.rawValue] as? String,
    rating = beerInfo[Keys.Rating.rawValue] as? NSNumber else {
      return
  }
 
  // 2
  let beer = Beer(name: name, note: beerInfo[Keys.Note.rawValue] as? String, rating: rating)
 
  // 3
  if let base64 = beerInfo[Keys.ImagePath.rawValue] as? String,
    imageData = NSData(base64EncodedString: base64, options: .IgnoreUnknownCharacters),
    image = UIImage(data: imageData) {
      beer.saveImage(image)
  }
 
  // 4
  BeerManager.sharedInstance.beers.append(beer)
  BeerManager.sharedInstance.saveBeers()
 
  // 5
  do {
    try NSFileManager.defaultManager().removeItemAtURL(url)
  } catch {
    print("Failed to remove item from Inbox")
  }
}

Here’s a step-by-step explanation of the above code:

  1. Verify the app can read the contents of the URL provided to it. Once verified make sure the data is of a type the application expects and has the minimum data set required to import a beer.
  2. Create a new Beer object with data from the URL.
  3. If image information exists in the beer data, process the image and persist to disk.
  4. Add the new beer to your app’s data
  5. Finally, delete the document that was saved to your app’s sandbox when iOS opened it.
Note: If you don’t delete these files as they come in, your app will continue to grow in size with no way for the user to clear the app’s data – except… delete your app!

Next, when an external app wants to send your app a file, it does so via the application(_:openURL:options:) method. Open AppDelegate.swift, and add the following code underneath the application(_:didFinishLaunchingWithOptions:) method:

// MARK: - Handle File Sharing
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
  // 1
  guard url.pathExtension == "btkr" else { return false }
 
  // 2
  Beer.importDataFromURL(url)
 
  // 3
  guard let navigationController = window?.rootViewController as? UINavigationController,
    beerTableViewController = navigationController.viewControllers.first as? BeersTableViewController else {
      return true
  }
 
  // 4
  beerTableViewController.tableView.reloadData()
  return true
}

Here’s a step-by-step explanation of the above:

  1. Verify the URL’s extension is btkr since your app only supports files with that extension.
  2. Use the static method on the Beer object you added above to import the data into your app.
  3. Verify the root view controller is an instance of a UINavigationController and that its first view controller is an instance of BeersTableViewController.
  4. Reload BeersTableViewController‘s table view to show the newly imported beer, then return true to inform iOS that your app successfully processed the provided beer information.
Note: The method still returns true even if the view controller hierarchy was not setup correctly. This is done because your app has in fact processed the provided beer information in step 2 above.

Build and run your app. If all works well you should be able to open the email attachment and see the beer imported into your app as shown below.

UIActivityViewController tutorial

Exporting App Data

So far in this UIActivityViewController tutorial you’ve added functionality to your app that handles importing data from other apps, however what if you wish to share your app’s data? You’re in luck here, as Apple has made exporting data almost as nice as a lime infused cerveza on a hot beach – maybe.

Your app will need code to handle brewing exporting your favorite beers. Open Beer.swift and replace the existing exportToFileURL() definition with the following:

func exportToFileURL() -> NSURL? {
  // 1
  var contents: [String: AnyObject] = [Keys.Name.rawValue: name, Keys.Rating.rawValue: rating]
 
  // 2
  if let image = beerImage() {
    let data = UIImageJPEGRepresentation(image, 1)
    contents[Keys.ImagePath.rawValue] = data?.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
  }
 
  // 3
  if let note = note {
    contents[Keys.Note.rawValue] = note
  }
 
  // 4
  guard let path = NSFileManager.defaultManager()
     .URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first else {
        return nil
  }
 
  // 5
  let saveFileURL = path.URLByAppendingPathComponent("/\(name).btkr")
  (contents as NSDictionary).writeToURL(saveFileURL, atomically: true)
  return saveFileURL
}

Here’s a step-by-step explanation of the above code:

  1. Create a Dictionary to hold your basic beer information.
  2. If you have an image, encode it to a base64 string to save in the dictionary. This makes it very easy to share your photo and data all in the same file.
  3. If you have notes, save those as well.
  4. Verify your app can access its Documents directory without error.
  5. Finally, persist the dictionary data to your Documents directory, and return the URL to the newly created file.

Now that you can export Beer data to a file, you’re going to need an easy way to share it. Open BeerDetailViewController.swift, and replace the implementation of the share(_:) method with the following:

@IBAction func share(sender: AnyObject) {
  guard let detailBeer = detailBeer,
    url = detailBeer.exportToFileURL() else {
      return
  }
 
  let activityViewController = UIActivityViewController(
    activityItems: ["Check out this beer I liked using Beer Tracker.", url],
    applicationActivities: nil)
  presentViewController(activityViewController, animated: true, completion: nil)
}

Here you’ve added a check to verify you have a detail beer, and can retrieve the URL from the exportToFileURL() method. Next, you create an instance of a UIActivityViewController passing in a message to be used, if possible and the URL to your app’s data file. UIActivityViewController will do all of the heavy lifting for you. Since you defined all of the required information in your Info.plist file, it’ll know just what to do with it. Finally you present the UIActivityViewController to the user.

Note: UIActivityViewController has been around since iOS6, however it is a very useful and sometimes under appreciated class. The message you pass to UIActivityViewController will be used by applications such as Mail and Messages, adding this to the body of your message.

Build and run your app, open a beer, and try to share. You’ll notice that you see a few options available to you as shown below:

UIActivityViewController tutorial

Perhaps one the best options is the ability to AirDrop. If you have two devices – or better yet, a friend with the Beer Tracker app installed – you can test AirDropping beers!

UIActivityViewController tutorial

Where To Go From Here?

You can download the finished project from this UIActivityViewController tutorial here.

Now that you know how iOS imports and exports app data, you’re ready to take this knowledge and start sharing your favorite beers or any other data of your choice.

In the meantime, if you have any questions or comments about this tutorial or Sharing Data in general, please join the forum discussion below!

The post UIActivityViewController Tutorial: Sharing Data appeared first on Ray Wenderlich.

iOS 10 Screencast: Measurement Formatter

Drag and Drop Tutorial for macOS

$
0
0
Drag_and_Drop_Tutorial_for_macOS

Learn all about drag and drop for macOS!

Ever since the invention of the Mac, drag and drop has been a part of the user interface. The quintessential example is in Finder, where you can drag files around to organize things or drop them in the trash.

The fun doesn’t stop there.

You can drag your latest sunset panorama from Photos and drop it in Messages, or pull a file from Downloads on the dock and drop it right in an email. You get the point, right? It’s cool and an integral part of the macOS experience.

Drag and drop has come a long way from its beginnings and now you can drag almost anything anywhere. Try it and you might be pleasantly surprised by the actions and types supported by your favorite apps.

In this drag and drop tutorial for macOS, you’ll discover how to add support to your own apps, so users can get the full Mac experience with your app.

Along the way, you’ll learn how to:

  • Implement core drag and drop actions on NSView subclasses
  • Accept data dropped from other applications
  • Provide data to be dragged into other views of your app
  • Create custom dragged types

Getting Started

This project uses Swift 3 and requires, at a minimum, Xcode 8 beta 4. Download the starter project, open it in Xcode and build and run it.

window-starting

Meet the Project App

Many kids enjoy playing with stickers and making cool collages with them, so you’re going to build an app that features this experience. You can drag images onto a surface and then you can kick things up a few notches by adding sparkles and unicorns to the view.

After all, who doesn’t like unicorns and sparkles? :]

To keep you focused on the objective — building out support for dragging and dropping — the starter project comes complete with the views you’ll require. All you need to do is learn about the mechanics of drag and drop.

There are three parts to the project window:

  • The sticker view where you’ll drag images and other things
  • Two smaller views that you’ll turn into different dragging sources

Take a look at the project.

project-display
You’ll edit four specific files as you work through this tutorial, and they’re in two places: Dragging Destinations and Dragging Sources:

In Dragging Destinations:

  • StickerBoardViewController.swift: the main view controller
  • DestinationView.swift: view that sits on top of the upper section of the window — it will be the recipient of your drag actions

view-hierachy

In Dragging Sources:

  • ImageSourceView.swift: bottom view with the unicorn image that you’ll turn into a dragging source
  • AppActionSourceView.swift: view that has the label Sparkles — you’ll turn this into another type of dragging source

There are some other files in the Drawing and Other Stuff groups that provide helper methods and are essential to the project app, but you won’t need to give them any of your time. Go ahead and explore if you’d like to see how this thing is built!

Pasteboards and Dragging Sessions

Drag and drop involves a source and a destination.

You drag an item from a source, which needs to implement the NSDraggingSource protocol. Then you drop it into a destination, which must implement the NSDraggingDestination protocol in order to accept or reject the items received. NSPasteboard is the class that facilitates the exchange of data.

The whole process is known as a dragging session:

dragging session macroscopic view

When you drag something with your mouse, e.g., a file, the following happens:

  1. A dragging session kicks off when you initiate a drag.
  2. Some data bits — often an image and URL — are chosen to represent the information placed on the dragging pasteboard.
  3. You drop that image on a destination, which chooses to reject or accept it and take some action — for instance, move the file to a new folder.
  4. The dragging session concludes.

That’s pretty much the gist of it. It’s a pretty simple concept!

First up is creating a dragging destination for receiving images from Finder or any other app.

Creating a Dragging Destination

A dragging destination is a view or window that accepts types of data from the dragging pasteboard. You create a dragging destination by adopting NSDraggingDestination.

This diagram shows the anatomy of a dragging session from the point of view of a dragging destination.
dragging session

There are a few steps involved in creating the destination:

  1. When building the view, you have to declare the types that it should receive from any dragging session.
  2. When a dragging image enters the view, you need to implement logic to allow the view to decide whether to use the data as well as let the dragging session know its decision.
  3. When the dragging image lands on the view, you use data from the dragging pasteboard to show it on your view.

Time to get down with some codeness!

Select DestinationView.swift in the project navigator and locate the following method:

func setup() {
}

Replace it with this:

var acceptableTypes: Set<String> { return [NSURLPboardType] }
 
func setup() {
  register(forDraggedTypes: Array(acceptableTypes))
}

This code defines a set with the supported types. In this case, URLs. Then, it calls register(forDraggedTypes:) to accept drags that contain those types.

Add the following code into DestinationView to analyze the dragging session data:

//1.
let filteringOptions = [NSPasteboardURLReadingContentsConformToTypesKey:NSImage.imageTypes()]
 
func shouldAllowDrag(_ draggingInfo: NSDraggingInfo) -> Bool {
 
  var canAccept = false
 
  //2.
  let pasteBoard = draggingInfo.draggingPasteboard()
 
  //3.
  if pasteBoard.canReadObject(forClasses: [NSURL.self], options: filteringOptions) {
    canAccept = true
  }
  return canAccept
 
}

You’ve done a few things in here:

  1. Created a dictionary to define the desired URL types (images).
  2. Got a reference to the dragging pasteboard from the dragging session info.
  3. Asked pasteboard if it has any URLs and whether those URLs are references to images. If it has images, it accepts the drag. Otherwise, it rejects it.

NSDraggingInfo is a protocol that declares methods to supply information about the dragging session. You don’t create them, nor do you store them between events. The system creates the necessary objects during the dragging session.

You can use this information to provide feedback to the dragging session when the app receives the image.

NSView conforms to NSDraggingDestination, so you need to override the draggingEntered(_:) method by adding this code inside the DestinationView class implementation:

//1.
var isReceivingDrag = false {
  didSet {
    needsDisplay = true
  }
}
 
//2.
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
  let allow = shouldAllowDrag(sender)
  isReceivingDrag = allow
  return allow ? .copy : NSDragOperation()
}

This is what the code above does:

  1. Creates a property named isReceivingDrag to track when the dragging session is inside the view and has data that you want. It triggers a redraw on the view each time it is set.
  2. Overrides the draggingEntered(_:) , and decides if it accepts the drag operation.

In section two, the method needs to return an NSDragOperation. You have probably noticed how the mouse pointer changes depending on the keys you hold down or the destination of a drag.

For example, if you hold down Option during a Finder drag, the pointer gains a green + symbol to show you a file copy is about to happen. This value is how you control those pointer changes.

In this config, if the dragging pasteboard has an image then it returns .copy to show the user that you’re about to copy the image. Otherwise it returns NSDragOperation() if it doesn’t accept the dragged items.

Handling an Exit

What enters the view may also exit, so the app needs to react when a dragging session has exited your view without a drop. Add the following code:

override func draggingExited(_ sender: NSDraggingInfo?) {
  isReceivingDrag = false
}

You’ve overridden draggingExited(_:) and set the isReceivingDrag variable to false.

Tell the User What’s Happening

You’re almost done with the first stretch of coding! Users love to see a visual cue when something is happening in the background, so the next thing you’ll add is a little drawing code to keep your user in the loop.

Still in DestinationView.swift, find draw(:_) and replace it with this.

override func draw(_ dirtyRect: NSRect) {
 
  if isReceivingDrag {
    NSColor.selectedControlColor.set()
 
    let path = NSBezierPath(rect:bounds)
    path.lineWidth = Appearance.lineWidth
    path.stroke()
  }
}

This code draws a system-colored border when a valid drag enters the view. Aside from looking sharp, it makes your app consistent with the rest of the system by providing a visual when it accepts a dragged item.

Note: Want to know more about custom drawing? Check out our Core Graphics on macOS Tutorial.

Build and run then try dragging an image file from Finder to StickerDrag. If you don’t have an image handy, use sample.jpg inside the project folder.

buildrun-add-plus

You can see that the cursor picks up a + symbol when inside the view and that the view draws a border around it.

When you exit the view, the border and + disappears; absolutely nothing happens when you drag anything but an image file.

Wrap up the Drag

Now, on to the final step for this section: You have to accept the drag, process the data and let the dragging session know that this has occurred.

Append the DestinationView class implementation with the following:

override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
  let allow = shouldAllowDrag(sender)
  return allow
}

The system calls the above method when you release the mouse inside the view; it’s the last chance to reject or accept the drag. Returning false will reject it, causing the drag image to slide back to its origination. Returning true means the view accepts the image. When accepted, the system removes the drag image and invokes the next method in the protocol sequence: performDragOperation(_:).

Add this method to DestinationView:

override func performDragOperation(_ draggingInfo: NSDraggingInfo) -> Bool {
 
  //1.
  isReceivingDrag = false
  let pasteBoard = draggingInfo.draggingPasteboard()
 
  //2.
  let point = convert(draggingInfo.draggingLocation(), from: nil)
  //3.
  if let urls = pasteBoard.readObjects(forClasses: [NSURL.self], options:filteringOptions) as? [URL], urls.count > 0 {
    delegate?.processImageURLs(urls, center: point)
    return true
  }
  return false
 
}

Here’s what you’re doing in there:

  1. Reset isReceivingDrag flag to false.
  2. Convert the window-based coordinate to a view-relative coordinate.
  3. Hand off any image URLs to the delegate for processing, and return true — else you reject the drag operation returning false.

Note: Feeling extra heroic? If you were to make an animated drop sequence, performDragOperation(:_) would be the best place to start the animation.

Congratulations! You’ve just finished the first section and have done all the work DestinationView needs to receive a drag.

Use DestinationView’s Data

Next up you’ll use the data that DestinationView provides in its delegate.

Open StickerBoardViewController.swift and introduce yourself to the class that is the delegate of DestinationView.

To use it properly, you need to implement the DestinationViewDelegate method that places the images on the target layer. Find processImage(_:center:) and replace it with this.

func processImage(_ image: NSImage, center: NSPoint) {
 
  //1.
  invitationLabel.isHidden = true
 
  //2.
  let constrainedSize = image.aspectFitSizeForMaxDimension(Appearance.maxStickerDimension)
 
  //3.
  let subview = NSImageView(frame:NSRect(x: center.x - constrainedSize.width/2, y: center.y - constrainedSize.height/2, width: constrainedSize.width, height: constrainedSize.height))
  subview.image = image
  targetLayer.addSubview(subview)
 
  //4.
  let maxrotation = CGFloat(arc4random_uniform(Appearance.maxRotation)) - Appearance.rotationOffset
  subview.frameCenterRotation = maxrotation
 
}

This code does the following tricks:

  1. It hides the Drag Images Here label.
  2. It figures out the maximum size for the dropped image while holding the aspect ratio constant.
  3. It constructs a subview with that size, centers it on the drop point and adds it to the view hierarchy.
  4. It randomly rotates the view a little bit for a bit of funkiness.

With all that in place, you’re ready to implement the method so it deals with the image URLs that get dragged into the view.
Replace processImageURLs(_:center:) method with this:

func processImageURLs(_ urls: [URL], center: NSPoint) {
  for (index,url) in urls.enumerated() {
 
    //1.
    if let image = NSImage(contentsOf:url) {
 
      var newCenter = center
      //2.
      if index > 0 {
        newCenter = center.addRandomNoise(Appearance.randomNoise)
      }
 
      //3.
      processImage(image, center:newCenter)
    }
  }
}

What you’re doing here is:

  1. Creating an image with the contents from the URLs.
  2. If there is more than one image, this offsets the images’ centers a bit to create a layered, randomized effect.
  3. Pass the image and center point to the previous method so it can add the image to the view.

Now build and run then drag an image file (or several) to the app window. Drop it!

window-demo-1

Look at that board of images just waiting to be made fearlessly fanciful.

You’re at about the halfway point and have already explored how to make any view a dragging destination and how to compel it to accept a standard dragging type — in this case, an image URL.

Intermission: let's all go to the lobby and get ourselves some drinks. And snacks. And new iMacs

Creating a Dragging Source

You’ve played around with the receiving end, but how about the giving end?

In this section, you’ll learn how to supercharge your app with the ability to be the source by letting those unicorns and sparkles break free and bring glee to the users’ images in the right circumstances.

All dragging sources must conform to the NSDraggingSource protocol. This MVP (most valuable player) takes the task of placing data (or a promise for that data) for one or more types on the dragging pasteboard. It also supplies a dragging image to represent the data.

When the image finally lands on its target, the destination unarchives the data from the pasteboard. Alternatively, the dragging source can fulfil the promise of providing the data.

You’ll need to supply the data of two different types: a standard Cocoa type (an image) and custom type that you create.

Supplying a Standard Dragging Type

The dragging source will be ImageSourceView — the class of the view that has the unicorn. Your objective is simple: get that unicorn onto your collage.

The class needs to adopt the necessary protocols NSDraggingSource and NSPasteboardItemDataProvider, so open ImageSourceView.swift and add the following extensions:

// MARK: - NSDraggingSource
extension ImageSourceView: NSDraggingSource {
  //1.
  func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor context: NSDraggingContext) -> NSDragOperation {
    return .generic
  }
}
 
// MARK: - NSDraggingSource
extension ImageSourceView: NSPasteboardItemDataProvider {
  //2.
  func pasteboard(_ pasteboard: NSPasteboard?, item: NSPasteboardItem, provideDataForType type: String) {
    //TODO: Return image data
  }
}
  1. This method is required by NSDraggingSource. It tells the dragging session what sort of operation you’re attempting when the user drags from the view. In this case it’s a generic operation.
  2. This implements the mandatory NSPasteboardItemDataProvider method. More on this soon — for now it’s just a stub.

Start a Dragging Session

In a real world project, the best moment to initiate a dragging session depends on your UI.

With the project app, this particular view you’re working in exists for the sole purpose of dragging, so you’ll start the drag on mouseDown(with:).

In other cases, it may be appropriate to start in the mouseDragged(with:) event.

Add this method inside the ImageSourceView class implementation:

override func mouseDown(with theEvent: NSEvent) {
  //1.
  let pasteboardItem = NSPasteboardItem()
  pasteboardItem.setDataProvider(self, forTypes: [kUTTypeTIFF])
 
  //2.
  let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)
  draggingItem.setDraggingFrame(self.bounds, contents:snaphot())
 
  //3.
  beginDraggingSession(with: [draggingItem], event: theEvent, source: self)
}

Things get rolling when the system calls mouseDown(with:) when you click on a view. The base implementation does nothing, eliminating the need to call super. The code in the implementation does all of this:

  1. Creates an NSPasteboardItem and sets this class as its data provider. A NSPasteboardItem is the box that carries the info about the item being dragged. The NSPasteboardItemDataProvider provides data upon request. In this case you’ll supply TIFF data, which is the standard way to carry images around in Cocoa.
  2. Creates a NSDraggingItem and assigns the pasteboard item to it. A dragging item exists to provide the drag image and carry one pasteboard item, but you don’t keep a reference to the item because of its limited lifespan. If needed, the dragging session will recreate this object. snapshot() is one of the helper methods mentioned earlier. It creates an NSImage of an NSView.
  3. Starts the dragging session. Here you trigger the dragging image to start following your mouse until you drop it.

Build and run. Try to drag the unicorn onto the top view.

buildrun-drag-unicorn

An image of the view follows your mouse, but it slides back on mouse up because DestinationView doesn’t accept TIFF data.

Take the TIFF

In order to accept this data, you need to:

  1. Update the registered types in setup() to accept TIFF data
  2. Update shouldAllowDrag() to accept the TIFF type
  3. Update performDragOperation(_:) to take the image data from the pasteboard

Open DestinationView.swift.

Replace the following line:

var acceptableTypes: Set<String> { return [NSURLPboardType] }

With this:

var nonURLTypes: Set<String>  { return [String(kUTTypeTIFF)] }
var acceptableTypes: Set<String> { return nonURLTypes.union([NSURLPboardType]) }

You’ve just registered the TIFF type like you did for URLs and created a subset to use next.

Next, go to shouldAllowDrag(:_), and add find the return canAccept method. Enter the following just above the return statement:

else if let types = pasteBoard.types, nonURLTypes.intersection(types).count > 0 {
  canAccept = true
}

Here you’re checking if the nonURLTypes set contains any of the types received from the pasteboard, and if that’s the case, accepts the drag operation. Since you added a TIFF type to that set, the view accepts TIFF data from the pasteboard.

Unarchive the Image Data

Lastly, update performDragOperation(_:) to unarchive the image data from the pasteboard. This bit is really easy.

Cocoa wants you to use pasteboards and provides an NSImage initializer that takes NSPasteboard as a parameter. You’ll find more of these convenience methods in Cocoa when you start exploring drag and drop more.

Locate performDragOperation(_:), and add the following code at the end, just above the return sentence return false:

else if let image = NSImage(pasteboard: pasteBoard) {
  delegate?.processImage(image, center: point)
  return true
}

This extracts an image from the pasteboard and passes it to the delegate for processing.

Build and run, and then drag that unicorn onto the sticker view.

buildrun-drag-unicorn-plus

You’ll notice that now you get a green + on your cursor.

The destination view accepts the image data, but the image still slides back when you drop. Hmmm. What’s missing here?

Show me the Image Data!

You need to get the dragging source to supply the image data — in other words: fulfil its promise.

Open ImageSourceView.swift and replace the contents of pasteboard(_:item:provideDataForType:) with this:

//1.
if let pasteboard = pasteboard, type == String(kUTTypeTIFF), let image = NSImage(named:"unicorn") {
  //2.
  let finalImage = image.tintedImageWithColor(NSColor.randomColor())
  //3.
  let tiffdata = finalImage.tiffRepresentation
  pasteboard.setData(tiffdata, forType:type)
}

In this method, the following things are happening:

  1. If the desired data type is kUTTypeTIFF, you load an image named unicorn.
  2. Use one of the supplied helpers to tint the image with a random color. After all, colorful unicorns are more festive than a smattering of all-black unicorns. :]
  3. Transform the image into TIFF data and place it on the pasteboard.

Build and run, and drag the unicorn onto the sticker view. It’ll drop and place a colored unicorn on the view. Great!

buildrun-add-unicorns

So.many.unicorns!

Dragging Custom Types

Unicorns are pretty fabulous, but what good are they without magical sparkles? Strangely, there’s no standard Cocoa data type for sparkles. I bet you know what comes next. :]

sparkle

Note: In the last section you supplied a standard data type. You can explore the types for standard data in the API reference.

In this section you’ll invent your own data type.

These are the tasks on your to-do list:

  1. Create a new dragging source with your custom type.
  2. Update the dragging destination to recognize that type.
  3. Update the view controller to react to that type.

Create the Dragging Source

Open AppActionSourceView.swift. It’s mostly empty except for this important definition:

enum SparkleDrag {
  static let type = "com.razeware.StickerDrag.AppAction"
  static let action = "make sparkles"
}

This defines your custom dragging type and action identifier.

Dragging source types must be Uniform Type Identifiers. These are reverse-coded name paths that describe a data type.

For example, if you print out the value of kUTTypeTIFF you’ll see that it is the string public.tiff.

To avoid a collision with an existing type, you can define the identifier like this: bundle identifier + AppAction. It is an arbitrary value, but you keep it under the private namespace of the application to minimize the risk of using an existing name.

If you attempt to construct a NSPasteboardItem with a type that isn’t UTI, the operation will fail.

Now you need to make AppActionSourceView adopt NSDraggingSource. Open AppActionSourceView.swift and add the following extension:

// MARK: - NSDraggingSource
extension AppActionSourceView: NSDraggingSource {
 
  func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor
    context: NSDraggingContext) -> NSDragOperation {
 
    switch(context) {
    case .outsideApplication:
      return NSDragOperation()
    case .withinApplication:
      return .generic
    }
  }
}

This code block differs from ImageSourceView because you’ll place private data on the pasteboard that has no meaning outside the app. That’s why you’re using the context parameter to return a NSDragOperation() when the mouse is dragged outside your application.

You’re already familiar with the next step. You need to override the mouseDown(with:) event to start a dragging session with a pasteboard item.

Add the following code into the AppActionSourceView class implementation:

override func mouseDown(with theEvent: NSEvent) {
 
  let pasteboardItem = NSPasteboardItem()
  pasteboardItem.setString(SparkleDrag.action, forType: SparkleDrag.type)
  let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)
  draggingItem.setDraggingFrame(self.bounds, contents:snaphot())
 
  beginDraggingSession(with: [draggingItem], event: theEvent, source: self)
 
}

What did you do in there?

You constructed a pasteboard item and placed the data directly inside it for your custom type. In this case, the data is a custom action identifier that the receiving view may use to make a decision.

You can see how this differs from ImageSourceView in one way. Instead of deferring data generation to the point when the view accepts the drop with the NSPasteboardItemDataProvider protocol, the dragged data goes directly to the pasteboard.

Why would you use the NSPasteboardItemDataProvider protocol? Because you want things to move as fast as possible when you start the drag session in mouseDown(with:).

If the data you’re moving takes too long to construct on the pasteboard, it’ll jam up the main thread and frustrate users with a perceptible delay when they start dragging.

In this case, you place a small string on the pasteboard so that it can do it right away.

Accept the New Type

Next, you have to let the destination view accept this new type. By now, you already know how to do it.

Open DestinationView.swift and add SparkleDrag.type to the registered types. Replace the following line:

var nonURLTypes: Set<String>  { return [String(kUTTypeTIFF)] }

With this:

var nonURLTypes: Set<String>  { return [String(kUTTypeTIFF),SparkleDrag.type] }

Now SparkleDrags are acceptable!

performDragOperation(:_) needs a new else-if clause, so add this code at the end of the method just before return false:

else if let types = pasteBoard.types, types.contains(SparkleDrag.type),
  let action = pasteBoard.string(forType: SparkleDrag.type) {
  delegate?.processAction(action, center:point)
  return true
}

This addition extracts the string from the pasteboard. If it corresponds to your custom type, you pass the action back to the delegate.

You’re almost done, you just need to update StickerBoardViewController to deal with the action instruction.

Handle the Action Instruction

Open StickerBoardViewController.swift and replace processAction(_:center:) with this:

func processAction(_ action: String, center: NSPoint) {
  //1.
  if action == SparkleDrag.action  {
    invitationLabel.isHidden = true
 
    //2.
    if let image = NSImage(named:"star") {
 
      //3.
      for _ in 1..<Appearance.numStars {
 
        //A.
        let maxSize:CGFloat = Appearance.maxStarSize
        let sizeChange = CGFloat(arc4random_uniform(Appearance.randonStarSizeChange))
        let finalSize = maxSize - sizeChange
        let newCenter = center.addRandomNoise(Appearance.randomNoiseStar)
 
        //B.
        let imageFrame = NSRect(x: newCenter.x, y: newCenter.y, width: finalSize , height: finalSize)
        let imageView = NSImageView(frame:imageFrame)
 
        //C.
        let newImage = image.tintedImageWithColor(NSColor.randomColor())
 
        //D.
        imageView.image = newImage
        targetLayer.addSubview(imageView)
      }
    }
  }
}

The above code does the following:

  1. Only responds to the known sparkle action
  2. Loads a star image from the bundle
  3. Makes some copies of the star image and…
    1. Generates some random numbers to alter the star position.
    2. Creates an NSImageView and sets its frame.
    3. Gives the image a random color — unless you’re going for a David Bowie tribute, black stars are a bit gothic.
    4. Places the image on the view.

Build and run. Now you can drag from the sparkles view onto the sticker view to add a spray of stars to your view.

final

Where to go From Here?

Congratulations, you created a custom drag and drop interface in your very own app!

You can use the Save Image To Desktop button to save your image as a JPG with the name StickerDrag. Maybe take it a step further and tweet it to the team @rwenderlich.

Here’s the source code for the the completed project.

This drag and drop tutorial for macOS covered the basics of the Cocoa drag and drop mechanism, including:

  • Creating a dragging destination and accepting several different types of data
  • Using the dragging session lifecycle to provide user feedback of the drag operation
  • Decoding information from the pasteboard
  • Creating a dragging source and providing deferred data
  • Creating a dragging source that provides a custom data type

Now you have the knowledge and experience needed to support drag and drop in any macOS app.

There’s certainly more to learn.

You could study up on how to apply effects, such as changing the dragging image during the drag or implementing an animated drop transition, or working with promised files — Photos is one application that places promised data on the dragging pasteboard.

Another interesting topic is how to use drag and drop with NSTableView and NSOutlineView, which work in slightly different ways. Learn about it from the following resources:

If you have any questions or comments about this drag and drop tutorial for macOS, please join the discussion below! And remember, sometimes life is a dragging experience, but everything’s better with unicorns and sparkles. :]

The post Drag and Drop Tutorial for macOS appeared first on Ray Wenderlich.


iOS 10 Screencast: Audio File Speech Transcription

Lead iOS Developer at Next PLC: A Top Dev Interview With Lee Burrows

$
0
0
Lee Burrows, lead iOS developer at Next PLC.

Lee Burrows, lead iOS developer at Next PLC.

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

Lee is a leading iOS technologist, well known for heading up the iOS team for the biggest retailer in the UK, Next PLC.

Next PLC is a British multinational clothing retailer based in the UK with over 700 stores. In addition, an online web presence with over 3 million active customers of which 500,000 actively use their iOS app per month.

Since we prepared this interview, Lee has moved on to a Senior iOS Developer position for Capital One, the eighth-largest bank holding company in the whole of the US.

Working On a Big Team

Lee, can you give us a sense of how big the Next app and team is and how it’s structured?

I work in the eCommerce department. Here you will find 55 or so developers, just 4 of which are in our iOS team. All developers report directly to the product owner.

We also have our own dedicated QA team, who strive on breaking our implementation and are fast to point out when something isn’t quite up to scratch for production. A little up the office we have the UI & UX teams and technical architects.

It looks a little something like this:

Lee's team structure at Next PLC

Lee’s team structure at Next PLC

Could you please describe the process by which your team works with the design team?

We are very closely coupled with the design team. It was always pushed upon us to be more “open desk” and the huge open office allowed this. We could often visit their desks and make suggestions.

Unfortunately, designs at Next were never approved by the higher ups until we went to release. At any stage they could and quite often did change. This ultimately had large issues with development timescales but something we learned to deal with…fast!

I often see this happen within very large companies. The design seems to be the forefront of ideas, with development the second thought. I think it is crucial for all skill sets to be involved throughout, from prototype right through to App Store delivery.

How much of the Next app is written in Swift? What were the challenges in transitioning the app from Objective-C to Swift in a large team environment?

Before Swift arrived, we made the iPad app in Objective-C. This is my proudest achievement to date: it includes a completely custom UI exhibiting UICollectionViews used to their greatest potential and a UIPageViewController that really went under the knife in Instruments.

Custom CollectionView used on the Next iPad App

Custom UICollectionView used on the Next iPad app

The iPad app ended up being about 33,000 lines of Objective-C code. Later, we wrote the iPhone app in Swift, and it ended up being a little smaller in size. To make sure we re-used some core components between the two platforms, we created an internal private CocoaPod. It contains UI elements that were generic to both iPhone and iPad apps for reusability and of course all our API data access.

We are currently bridging Objective-C classes in our CocoaPod to our Swift code base. The transition over to Swift was a fun one, although initially I was against it! I was not overly comfortable with Swift as it was still in version 1 at that point, but after persuasion from some of the guys we took the plunge.

Debugging Swift back then was extremely painful, and it still is to this day when debugging Objective-C code in a Swift project. The po command and I are now best of friends. :]

For other developers or teams, what advice would you give for a successful development life-cycle?

I would recommend you make sure your team fully understand your chosen source control system (GIT/SVN) and ensure they adhere to all the best practices. I have lost count how many times I tell developers to pull down as often as possible and push up just as often.

For us, communication is key. We encourage the use of our “Confessions” channel on Slack, a place where anyone can dump a snippet of code and allow time for other developers to offer an alternative solution.

For any developer looking to join a huge company, just remember that’s all you are: a developer. Unfortunately the chances of your fancy design and animation making the App Store release are probably small. In fact, only one of my fancy animations made it into the App Store and that was still scrutinized!

Being a Team Lead

Lee's workstation at Next PLC.

Lee’s workstation at Next PLC.

As a lead iOS developer, you are responsible for multiple skilled iOS developers, how do you manage those on a daily basis?

I generally have a 60/40 time split between getting my head down in code and managing the team. I use my favorite app, Todoist, to manage what development tasks I want to be completed and I use sticky notes attached to my monitor for analysis tasks and other ad-hoc duties other departments may need me for.

Being the Lead iOS Developer, it was all about being approachable. When you hold such a title, people will look at you like you’re Mr. StackOverflow and it’s wise to be approachable. After all, your suggestions around problems could well be the ones implemented.

It can be very frustrating managing a team when not many of our ideas get implemented. I remember I had to remove a developer’s force touch feature because it wasn’t in the requirements.

What’s your interview process while hiring new iOS developers? What sort of things do you look for in an ideal hire on your team?

We do most of our interviewing over the phone and sometimes face to face. Once we’re happy with a hire we get them to take an iOS quiz which generally gives us a good idea of their skillset. Here at Next, no interview is the same: we mix the process regularly to keep it fresh.

I love when developers talk about Swift, or anything new. It shows they keep up with the latest in the iOS development world and gives them chance to show off their passion for development.

Swift is the forefront of Lee's interview questions.

Swift is the forefront of Lee’s interview questions.

If someone loves what they do they won’t tell you in those exact words, you’ll just know. If you can’t sense it what would be the point in hiring someone who didn’t love what they do? If you love what you do you’ll do it faster and probably better.

We have asked questions like:

  1. What feature do you love the most in Swift?
  2. Can you describe the purpose of using Playgrounds?

I love very broad questions, since it allows a lot of mini questions to tail off their responses. I’ve had a lot of bad experiences with developers and SCM, I guess next time I would go more in depth about git and branching models.

Hiring contractors is usually a lot easier. We just have a quick telephone interview to assess their development history, a quick code pairing exercise, and that’s it – they’re in. Of course, we can always drop them with a little notice – I like to remind them of this, in a friendly way of course. :]

Do you have any final advice for readers looking to level up their iOS skills?

Keep on top of your development. iOS especially moves incredibly fast each year following WWDC. Swift is about to get kicked into version 3; it’s moving fast you just can’t sit still.

Watch the Apple videos, visit plenty of tutorial websites, fire up Xcode and get ahead of the game.

Where To Go From Here?

And that concludes our Top App Dev Interview with Lee Burrows. Huge thanks to Lee for sharing his experience with the iOS community.

We hope you enjoyed this interview and that you can take Lee’s advice when it comes to being a Lead iOS Developer or an iOS Developer within a large corporation. I think when working within a large corporation you’re a small cog in a giant wheel, everyone spinning to create the final product. We wish Lee all the best in his new position at Capital One.

If you are an app developer with a hit app or game in the top 100 in the App store or other significantly cool experience, 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 Lead iOS Developer at Next PLC: A Top Dev Interview With Lee Burrows appeared first on Ray Wenderlich.

RWDevCon 2017: Tickets Now Available!

$
0
0

RWDevCon-feature

Next March, we are running an iOS conference focused on high quality hands-on tutorials called RWDevCon 2017.

Today, the team and I are happy to announce that RWDevCon 2017 tickets are now available!

And good news – the first 75 people who buy tickets will get a $100 discount off the standard ticket price.

Keep reading to find out what makes RWDevCon special, and what’s in store this year!

What Makes RWDevCon Special

RWDevCon is designed around 4 main principles:

1) Hands-On Tutorials

RWDevCon is unique in that it is focused on high quality hands-on tutorials. It has 3 simultaneous tracks of tutorials, leading to some challenging and fun choices on which to attend! :]

In each tutorial, you will follow along with a hands-on demo with the instructor:

DerekSelander

After the demo, you’ll break out into a hands-on lab, where you’ll be challenged to try things out on your own – and the instructor will be right with you if you have any questions.

GregHeo

We really think this hands-on experience is the best way to learn, and this way you won’t just leave with notes and references – you’ll leave with actual new skills.

“The hands-on tutorials were worth their weight in gold. Some of the concepts I spend hours reading about were cleared up in 30 minutes.” –RWDevCon attendee

2) Team Coordination

Vault-Small

Just like we do for books and tutorials on this site, RWDevCon is highly coordinated as a team. This lets us:

  • Cover the material you want. We send a survey to all attendees with potential tutorial topics, and let everyone vote on what they want. We then cover the top voted topics.
  • Practice and polish. Each speaker is assigned a tech editor, and practices once with their tech editor, and once with me. The result is a well polished talks that give you a great experience.
  • Coordinate materials. We develop our tutorial materials in a standard format, and the result is high quality content that remains useful even after the conference – we even make a 600+ page conference book!
“The demos and labs have been SO polished. Basically my ideal iOS conference because I came away learning so much!” –RWDevCon attendee

3) Inspiration

After a long days work on hands-on tutorials, you’ll be ready for a break.

That’s why at the end of the day, we switch to something completely different: inspiration talks.

These are short 18-minute non-technical talks with the goal of giving you a new idea, some battle-won advice, and leaving you excited and energized.

If you’re curious what these look like, check out our RWDevCon videos.

“The inspiration talks surprised me the most. I really enjoyed those. I loved all of the technical sessions but the inspiration talks were unexpected.” –RWDevCon attendee

4) Friendship

We believe one of the best parts about going to a conference is the people, and there’s plenty of opportunities to meet new friends.

RWDevCon

We’ll have an opening reception before the conference begins to get to meet each other, board games at lunch, and an awesome party on Friday night. We have some surprises up our sleeves this year too – you won’t want to miss it! :]

“Better food and more fun than WWDC! Lots left to work on after I go home – really met the goal of providing content to cement the knowledge.” –RWDevCon attendee

Where To Go From Here?

If you’re interested in getting a ticket, now’s the best time:

  • Before it sells out: RWDevCon only has a limited amount of spaces, and for the past two years the conference has sold out very quickly, so now’s your chance to have a guaranteed ticket.
  • To lock in your discount: The first 75 people who buy tickets will a $100 discount off the standard ticket price – but this won’t last long!

You can grab your ticket at the RWDevCon web site. We hope to see you there! :]

The post RWDevCon 2017: Tickets Now Available! appeared first on Ray Wenderlich.

TestFlight Tutorial: iOS Beta Testing

$
0
0
Learn how to use TestFlight to beta test your iOS apps!

Learn how to beta test your iOS apps!

Update note: This tutorial has been updated by Tom Elliott. The original tutorial was written by Dani Arnaout.

TestFlight Beta Testing is an Apple product that makes it easy to invite users to test your iOS, watchOS and tvOS apps before you release them into the App Store. This TestFlight tutorial will walk you through integrating TestFlight into your own apps.

This is one of those rare tutorials where you don’t have to code — just follow through the steps in this tutorial and you’ll be up and running with TestFlight in no time! :]

Getting Started

Don’t have an app right now but still want to proceed with this tutorial? No problem! Download our beloved Flappy Felipe project and use that as you follow along. Make sure you change the bundle ID of the app to your own unique ID; for example, com.yourname.FlappyFelipe.

This tutorial assumes that your app is set up for provisioning, and has an app ID created in both the developer portal and on iTunes Connect.

This setup is outside the scope of this tutorial, but you should be able to use automatic provisioning as described in Setting up Xcode to automatically manage your provisioning profiles, and create a record in iTunes by following the instructions in Create an iTunes Connect Record for TestFlight Beta Testing in the iTunes Connect Developer Guide.

Submitting your Build to iTunes Connect

Open up your project in Xcode, make sure you have a correct Bundle Identifier, that your Team ID is set, and that you’ve chosen the automatic Distribution Certificate Code Signing Identity:

AA- Code Signing

Choose Product\Archive from the top toolbar:

2- Product Archive

Once Xcode finishes archiving your project, click the shiny blue Upload to App Store… button:

3- Archive

Now you need to choose your development team:

4- Choose Team

Finally, click Upload:

5- Submit

Wait for a few minutes as your build uploads. Grab a coffee, perhaps, or if you have a slow internet connection, go grab a bite. Or two. Or three. :]

6-Upload2.png

Once you’re done, you should receive a success message like the following:

success

That’s all the work required for Xcode. Your beta build is now available on iTunes Connect, and that’s where you’ll be doing the rest of the work to set up TestFlight.

Create and Enable Testers to Beta Test Apps

Your build is ready for testing, but who’s going to test it?

Apple defines two types of testers for Test Flight:

  • Internal Tester: This is an iTunes Connect user that has an Admin, Technical, App Manager, Developer, or Marketer role with access to your app. This is usually a team member or a client you’re developing an app for. You can add up to 25 internal testers.
  • Note: Apple are in the process of deprecating the Technical role in favour of the App Manager role. At the time of writing both roles are available. If you have existing users with the Technical role you should start migrating them over to the App Manager role. New users should be created with the App Manager role.
  • External Tester: This is any user outside of your team that wants to test your app. An external tester has no access to your iTunes Connect account in any way, and can only download and install the app. You can add up to 2000 external testers.

Before your external developers can test your app, you have to submit your app to be reviewed by Apple, just as you would with a normal App Store submission. These reviews tend to go faster than normal app reviews (although don’t count on it), and once it’s approved you can let external developers test your app. Internal testers, on the other hand, are instantaneously able to test new builds.

You’ll learn more about external testers later, but for now, let’s focus on internal testers.

To add an internal tester, head to the Users and Roles section in iTunes Connect:

10 - Users and roles

On the Users and Roles screen, click the + button to add a new user:

11- Users

Fill in your new user info and click Next:

15- Roles

You’ll need to use a unique email address for your new user. If you don’t have a second email account, you can usually append +whateveryouwant to the first part of your email address, and the email will still get delivered to you. For example tom+mytestaccount@razeware.com.

Now you need to assign roles for the user. In most cases, you’ll want to choose App Manager. You can read more about the privileges for each role and choose the appropriate one for your user.

Note: The number of different roles and permissions can be a bit daunting! When it comes to Test Flight, use this handy table to help you.
Admin App Manager Developer Marketer Sales
Can be an Internal Tester ✗
Can Upload a Build ✗ ✗ Can Submit a Build for External Testing ✗ ✗ ✗

Once that’s done, click Next:

16- Roles

Choose the type of notifications you want your new testers to receive, then click Save:

17- notifications

Your user is now created, but as the message indicates, that user first needs to verify his or her email address before the account will show in iTunes Connect.

Creating a new internal beta tester is only the first part of the process. The remaining step is to invite this particular tester to test your latest build.

It’s time to enable your app for testing — so the tester actually has something to test! :]

Starting Beta Testing

To start beta testing of your app, go to the My Apps section on the iTunes Connect home page and click on your app:

20- connect

Select the Activity tab and you’ll find your latest build. Make sure it is no longer marked as processing. If it is, go make another cup of coffee and come back later. :]

Activity

Next, click on the TestFlight tab, then Internal Testing in the left hand menu. Click Select Version to Test and choose the version you just uploaded. Finally, click Start Testing and, in the confirmation pop-up, Start Testing again.

Start Testing
All selected testers will now receive an email that lets them download and install this build from the TestFlight app. There are detailed instructions on how to do that in the last section of this tutorial.

That takes care of internal testers, but what about external testers?

That’s just as easy! First, go to the Test Information tab and fill in your Feedback Email, Marketing URL and Privacy Policy URL. You can choose to add a License Agreement at this stage as well if you wish, but it is not necessary.

30- TestInformation

Next, go to the External Testing tab, click the + button and select Add New Testers:

32- External

Add the email addresses of any external users you want to add. Once you’re finished, click Add to add these testers to your account. All external testers will count toward your 2000 external tester limit:

33-External2

Click Save.

You now need to select a build (again) for your external testers, and put that build through the Beta App Review.

Note: Why do you need to select the build again? Well you may want your internal and external testers to be testing different builds. For example, your external testers may be testing your next release candidate, but your internal testers are testing your master build. By making you select a build for internal and external testers separately iTunes Connect allows this kind of separation.

Click Add Build To Test, select your build, and then click Next.

34-BetaTest1

Fill in all the fields. Remember – the more information you give Apple the easier it is for them to review your app! Finally, hit Submit.

35-BetaTest2

Your app will be added to the review queue! :]

Note: In my own experience, your first beta app review can take up to 48 hours to be approved. Subsequent beta app reviews are usually much faster.

31-AppInReview

Once the app has passed Beta App Review you will receive an email with confirmation that your app can now be used by external testers.

Note: A build is only valid for 60 days. If you want your testers to use the app beyond that, you’ll have to upload a new build before the expiration date.

Head back to the External Testing section for your app in iTunes Connect, select the build and hit Save. A dialog will pop up confirming that you are about to notify people. Click Start Testing.

32-ConfirmNotification

Your external testers will then receive an invitation email similar to the one received by your internal testers as described above.

Note: What happens if invites go missing? Currently there is no easy way to re-send invite emails if they go missing. For internal testers the easiest approach is probably to upload a new build (as it doesn’t have to go through Beta App Review). For external testers you can either remove the user and then re-add the user as a tester, or remove your app from external testing and then quickly re-add it. This second approach will re-send an email invite to all your external testers so be careful! :]

That shows the developer’s perspective of app testing, but what does it look like from the tester’s perspective?

Testing an App

As an internal tester, you need to link your Apple ID to iTunes Connect (external testers can skip to the TestFlight App section below). By now, you should have received an email from iTunes Connect that looks like this:

21- Email

Click on activate your account and follow the supplied steps. Once your account is ready for testing, get your iOS device and go to the Settings app. Scroll down to iTunes & App Store:

19- Settings

Log in with the account you just verified a minute ago. If you’re already logged in with another account, log out first:

20- Log in

TestFlight App

Go to the App Store, and search for the TestFlight app:

21- Search

Download the TestFlight app and launch it.

Note: If you’re required to log in, simply use the same credentials you used to verify your account.

Internal testers will automatically receive an email when new versions of the app are uploaded to iTunes Connect. External testers will receive a similar email after the app has been through Beta App Review and the build has been pushed out to external testers by an Admin or App Manager in iTunes Connect:

24- Invite Email

Open this email on your testing device, then tap Start Testing. This will launch TestFlight and show you the app you need to test. A tester must tap Start Testing on the device they’ll be testing on; otherwise the app won’t be available for download by the tester. Tap Accept, then Install, and wait for the app to download:

25- Accept

The app will be downloaded and appear on your home screen!

That was the hardest part of being a tester. From now on, whenever a new version of this app is available, you’ll see a notification from TestFlight. All you need to do is update your app and run the latest version.

Where to Go From Here?

In this TestFlight tutorial you learned how to upload your test build and invite internal and external testers to your app.

If you’re interested in knowing more about iTunes Connect in general, and beta testing in particular, read through Apple’s TestFlight Beta Testing Documentation. Apple’s Developer site also has a summary page for TestFlight, which includes links to all the relevant documentation as well as a video outlining the TestFlight process.

You can also check out iOS 8 by Tutorials; the final chapter What’s New with iTunes Connect showcases everything you need to know to manage your testing effort.

If you want to take your app deployment to the next level, take a look at our fastlane tutorial, which covers a set of tools that you can use to automate managing iTunes Connect and submitting apps.

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

The post TestFlight Tutorial: iOS Beta Testing appeared first on Ray Wenderlich.

Introducing videos.raywenderlich.com – Discount and Giveaway!

$
0
0

Videos-feature

For the past two years, we’ve been working hard creating a ton of high quality video tutorials.

In fact, we’ve been spending so much time making the content, that we didn’t have much time to focus on the website itself. But we admit it – a massive text list of courses isn’t very user-friendly. :]

Today, we have some good news. We’ve completely redesigned the video section of our site: videos.raywenderlich.com.

Whether you’re a subscriber or not, there’s lots in store for you in this launch, including a special discount and giveaway. Read on to see how you can enjoy our launch party!

What’s New?

The first thing you’ll notice about videos.raywenderlich.com is that it’s been completely redesigned:

1-new-design

The new design makes it easy to find the course or screencast you’re looking for:

2-courses

In addition to the visual design, there are tons of new features to improve your learning experience.

First of all, you asked for it, and you got it. You can now play videos at 1.5x or 2x speed!

3-2xspeed

You can now easily see your progress working through a course:

4-courseprogress

It’s also easy to continue from where you left off watching videos last time:

5-last-watched

Please check out the new design and let us know what you think! :]

Remember even if you’re not a subscriber, there’s still plenty for you to do over on the new site:

  • You can check out our huge range of videos
  • You can easily find and watch our free video tutorials
  • You can even track those you’ve watched as long as you’ve got a raywenderlich.com account!

Or if you want to be more involved, check out the launch discount and giveaway below.

Launch Discount and Giveaway

The entire team at Razeware has been working hard on this over the past few months, so we wanted to do something extra special to celebrate.

Launch Discount

Betamax-discount-1

To celebrate the launch, we’re offering a special 50% discount off your first month – w00t!

To get the 50% off your first month discount: Simply sign up now for a monthly subscription and enter the following coupon code at checkout: RW1MV (expires next Tuesday, Aug 23)

If you’ve ever been on the fence about subscribing, now is the time. In addition to the 50% discount on your first month, you’ll enjoy all the usual subscriber benefits:

  • Enjoy all the new features of videos.raywenderlich.com
  • Get access to our entire catalog of 45 courses and 452 videos
  • Enjoy new videos and updates that we release to this site on a regular basis, including our new iOS 10 Screencasts
  • Get free access to iOS 10 by Tutorials – the first 3 chapters are available now, and 3 more chapters will be coming this week or next
  • Be eligible to enter the launch giveaway mentioned below!

Launch Giveaway

Already a subscriber? Enter our massive launch giveaway:

Betamax-giveaway-1

One lucky grand prize winner will get a 1-year raywenderlich.com all-access pass. This includes:

  • A free 1-year subscription to raywenderlich.com ($179.88 value)
  • A free copy of all books currently for sale on raywenderlich.com ($494.91)
  • A free copy of three secret books that are in progress, once they are released ($164.97 value)
  • A free copy of the RWDevCon 2016 Vault ($199.99 value)

This represents over $1,000 in value – w00t!

But that’s not all. In addition to the grand prize, 10 lucky second prize winners will receive 1 free PDF book of their choice.

To enter the giveaway, simply comment on this post and answer the following question:

What do you like about the video tutorials at raywenderlich.com?

We will select random winners who answer this question by next Tuesday, Aug 23. Note you must be an active subscriber to be eligible for the giveaway.

Where To Go From Here?

Here’s how to check out the new site:

  • If you’re a raywenderlich.com subscriber, comment on the post and answer the question above to enter the giveaway, and enjoy the new features on videos.raywenderlich.com!
  • If you’re not a raywenderlich.com subscriber yet, subscribe now to get free access to iOS 10 by Tutorials and 50% off your first month, with the following coupon code: RW1MV

Remember – the launch discount and giveaway expires next Tuesday, Aug 23 – so take advantage of them while you still can.

The entire Razeware team and I hope you enjoy videos.raywenderlich.com – and thanks again to all of our subscribers for supporting what we do on this site and making this possible.

The post Introducing videos.raywenderlich.com – Discount and Giveaway! appeared first on Ray Wenderlich.

iOS 10 Screencast: Visual View Debugging

Pattern Matching in Swift

$
0
0
It's the perfect pattern match!

It’s the perfect pattern match!

Pattern matching is one of the most powerful features of any programming language, because it enables you to design rules that match values against each other. This gives you flexibility and simplifies your code.

Apple makes pattern matching available in Swift, and today you’ll explore Swift’s pattern matching techniques.

The tutorial covers the following patterns:

  • Tuple pattern
  • Type-casting patterns
  • Wildcard pattern
  • Optional pattern
  • Enumeration case pattern
  • Expression pattern

To show how useful pattern matching can be, in this tutorial you’ll adopt a unique perspective: that of the editor-in-chief at raywenderlich.com! You’ll use pattern matching to help you schedule and publish tutorials on the site.

Note: This tutorial requires Xcode 8 and Swift 3 and assumes you already know the basics of Swift development. If you’re new to Swift, check out some of our other Swift tutorials first.

Getting Started

Welcome aboard, temporary editor-in-chief! Your main duties today involve scheduling tutorials for publication on the website. Start by downloading the starter playground and open starter project.playground in Xcode.

The playground contains two things:

  • The random_uniform(value:) function, which returns a random number between zero and a certain value. You’ll use this to generate random days for the schedule.
  • Boilerplate code that parses the tutorials.json file and returns its contents as an array of dictionaries. You’ll use this to extract information about the tutorials you’ll be scheduling.
Note: To learn more about JSON parsing in Swift, read our tutorial.

You don’t need to understand how all this works, but you should know the file’s structure, so go ahead and open tutorials.json from the playground’s Resources folder.

Each tutorial post you’ll be scheduling has two properties: title and scheduled day. Your team lead schedules the posts for you, assigning each tutorial a day value between 1 for Monday and 5 for Friday, or nil if leaving the post unscheduled.

You want to publish only one tutorial per day over the course of the week, but when looking over the schedule, you see that your team lead has two tutorials scheduled for the same day. You’ll need to fix the problem. Plus, you want to sort the tutorials in a particular order. How can you do all of that?

If you guessed “Using patterns!” then you’re on the right track. :]

pattern matching all the patterns!

Pattern Matching Types

Let’s get to know the kinds of patterns you’ll be working with in this tutorial.

  • Tuple patterns are used to match values of corresponding tuple types.
  • Type-casting patterns allow you to cast or match types.
  • Wildcard patterns match and ignore any kind and type of value.
  • Optional patterns are used to match optional values.
  • Enumeration case patterns match cases of existing enumeration types.
  • Expression patterns allow you to compare a given value against a given expression.

You’ll use all of these patterns in your quest to be the best editor-in-chief the site has ever seen!

Our editor in chief

Putting this guy out of a job!

Tuple Pattern

First, you’ll create a tuple pattern to make an array of tutorials. In the playground, add this code at the end:

enum Day: Int {
  case monday, tuesday, wednesday, thursday, friday, saturday, sunday
}

This creates an enumeration for the days of the week. The underlying raw type is Int, so the days are assigned raw values from 0 for Monday through 6 for Sunday.

Add the following code after the enumeration’s declaration:

class Tutorial {
 
  let title: String
  var day: Day?
 
  init(title: String, day: Day? = nil) {
    self.title = title
    self.day = day
  }
}

Here you define a tutorial type with two properties: the tutorial’s title and scheduled day. day is an optional variable because it can be nil for unscheduled tutorials.

Implement CustomStringConvertible so you can easily print tutorials:

extension Tutorial: CustomStringConvertible {
  var description: String {
    var scheduled = ", not scheduled"
    if let day = day {
      scheduled = ", scheduled on \(day)"
    }
    return title + scheduled
  }
}

Now add an array to hold the tutorials:

var tutorials: [Tutorial] = []

Next, convert the array of dictionaries from the starter project to an array of tutorials by adding the following code at the end of the playground:

for dictionary in json {
  var currentTitle = ""
  var currentDay: Day? = nil
 
  for (key, value) in dictionary {
    // todo: extract the information from the dictionary
  }
 
  let currentTutorial = Tutorial(title: currentTitle, day: currentDay)
  tutorials.append(currentTutorial)
}

Here, you iterate over the json array with the for-in statement. For every dictionary in this array, you iterate over the key and value pairs in the dictionary by using a tuple with the for-in statement. This is the tuple pattern in action.

You add each tutorial to the array, but it is currently empty—you are going to set the tutorial’s properties in the next section with the type-casting pattern.

Type-Casting Patterns

To extract the tutorial information from the dictionary, you’ll use a type-casting pattern. Add this code inside the for (key, value) in dictionary loop, replacing the placeholder comment:

// 1
switch (key, value) {
  // 2
  case ("title", is String):
    currentTitle = value as! String
  // 3
  case ("day", let dayString as String):
    if let dayInt = Int(dayString), let day = Day(rawValue: dayInt - 1) {
      currentDay = day
  }
  // 4
  default:
    break
}

Here’s what’s going on, step by step:

  1. You switch on the key and value tuple—the tuple pattern reloaded.
  2. You test if the tutorial’s title is a string with the is type-casting pattern and type-cast it if the test succeeds.
  3. You test if the tutorial’s day is a string with the as type-casting pattern. If the test succeeds, you convert it into an Int first and then into a day of the week with the Day enumeration’s failable initializer init(rawValue:). You subtract 1 from the dayInt variable because the enumeration’s raw values start at 0, while the days in tutorials.json start at 1.
  4. The switch statement should be exhaustive, so you add a default case. Here you simply exit the switch with the break statement.

Add this line of code at the end of the playground to print the array’s content to the console:

print(tutorials)

As you can see, each tutorial in the array has its corresponding name and scheduled day properly defined now. With everything set up, you’re ready to accomplish your task: schedule only one tutorial per day for the whole week.

Wildcard Pattern

You use the wildcard pattern to schedule the tutorials, but you need to unschedule them all first. Add this line of code at the end of the playground:

tutorials.forEach { $0.day = nil }

This unschedules all tutorials in the array by setting their day to nil. To schedule the tutorials, add this block of code at the end of the playground:

// 1 
let days = (0...6).map { Day(rawValue: $0)! }
// 2
let randomDays = days.sorted { _ in random_uniform(value: 2) == 0 }
// 3
(0...6).forEach { tutorials[$0].day = randomDays[$0] }

There’s a lot going on here, so let’s break it down:

  1. First you create an array of days, with every day of the week occurring exactly once.
  2. You “sort” this array. The random_uniform(value:) function is used to randomly determine if an element should be sorted before or after the next element in the array. In the closure, you use an underscore to ignore the closure parameters, since you don’t need them here. Although there are technically more efficient and mathematically correct ways to randomly shuffle an array this shows the wildcard pattern in action!
  3. Finally, you assign the first seven tutorials the corresponding randomized day of the week.

Add this line of code at the end of the playground to print the scheduled tutorials to the console:

print(tutorials)

Success! You now have one tutorial scheduled for each day of the week, with no doubling up or gaps in the schedule. Great job!

Best EIC ever!

Optional Pattern

The schedule has been conquered, but as editor-in-chief you also need to sort the tutorials. You’ll tackle this with optional patterns.

To sort the tutorials array in ascending order—first the unscheduled tutorials by their title and then the scheduled ones by their day—add the following block of code at the end of the playground:

// 1
tutorials.sort {
  // 2
  switch ($0.day, $1.day) {
    // 3
    case (nil, nil):
      return $0.title.compare($1.title, options: .caseInsensitive) == .orderedAscending
    // 4
    case (let firstDay?, let secondDay?):
      return firstDay.rawValue < secondDay.rawValue
    // 5
    case (nil, let secondDay?):
      return true
    case (let firstDay?, nil):
      return false
  }
}

Here’s what’s going on, step-by-step:

  1. You sort the tutorials array with the array’s sort(_:) method. The method’s argument is a trailing closure which defines the sorting order of any two given tutorials in the array. It returns true if you sort the tutorials in ascending order, and false otherwise.
  2. You switch on a tuple made of the days of the two tutorials currently being sorted. This is the tuple pattern in action once more.
  3. If both tutorials are unscheduled, their days are nil, so you sort them in ascending order by their title using the array’s compare(_:options:) method.
  4. To test whether both tutorials are scheduled, you use an optional pattern. This pattern will only match a value that can be unwrapped. If both values can be unwrapped, you sort them in ascending order by their raw value.
  5. Again using an optional pattern, you test whether only one of the tutorials is scheduled. If so, you sort the unscheduled one before the scheduled one.

Add this line of code at the end of the playground to print the sorted tutorials:

print(tutorials)

There—now you’ve got those tutorials ordered just how you want them. You’re doing so well at this gig that you deserve a raise! Instead, however … you get more work to do.

No more trophies??

Enumeration Case Pattern

Now let’s use the enumeration case pattern to determine the scheduled day’s name for each tutorial.

In the extension on Tutorial, you used the enumeration case names from type Day to build your custom string. Instead of remaining tied to these names, add a computed property name to Day by adding the following block of code at the end of the playground:

extension Day {
 
  var name: String {
    switch self {
      case .monday:
        return "Monday"
      case .tuesday:
        return "Tuesday"
      case .wednesday:
        return "Wednesday"
      case .thursday:
        return "Thursday"
      case .friday:
        return "Friday"
      case .saturday:
        return "Saturday"
      case .sunday:
        return "Sunday"
    }
  }
}

The switch statement in this code matches the current value (self) with the possible enumeration cases. This is the enumeration case pattern in action.

Quite impressive, right? Numbers are cool and all, but names are always more intuitive and so much easier to understand after all! :]

Expression Pattern

Next you’ll add a property to describe the tutorials’ scheduling order. You could use the enumeration case pattern again, as follows (don’t add this code to your playground!):

var order: String {
  switch self {
    case .monday:
      return "first"
    case .tuesday:
      return "second"
    case .wednesday:
      return "third"
    case .thursday:
      return "fourth"
    case .friday:
      return "fifth"
    case .saturday:
      return "sixth"
    case .sunday:
      return "seventh"
  }
}

But doing the same thing twice is for lesser editors-in-chief, right? ;] Instead, take a different approach and use the expression pattern. First you need to overload the pattern matching operator in order to change its default functionality and make it work for days as well. Add the following code at the end of the playground:

func ~=(lhs: Int, rhs: Day) -> Bool {
  return lhs == rhs.rawValue + 1
}

This code allows you to match days to integers, in this case the numbers 1 through 7. You can use this overloaded operator to write your computed property in a different way.

Add the following code at the end of the playground:

extension Tutorial {
 
  var order: String {
    guard let day = day else {
      return "not scheduled"
    }
    switch day {
      case 1:
        return "first"
      case 2:
        return "second"
      case 3:
        return "third"
      case 4:
        return "fourth"
      case 5:
        return "fifth"
      case 6:
        return "sixth"
      case 7:
        return "seventh"
      default:
        fatalError("invalid day value")
    }
  }
}

Thanks to the overloaded pattern matching operator, the day object can now be matched to integer expressions. This is the expression pattern in action.

Putting It All Together

Now that you’ve defined the day names and the tutorials’ order, you can print each tutorial’s status. Add the following block of code at the end of the playground:

for (index, tutorial) in tutorials.enumerated() {
  guard let day = tutorial.day else {
    print("\(index + 1). \(tutorial.title) is not scheduled this week.")
    continue
  }
  print("\(index + 1). \(tutorial.title) is scheduled on \(day.name). It's the \(tutorial.order) tutorial of the week.")
}

Notice the tuple in the for-in statement? There’s the tuple pattern again!

Whew! That was a lot of work for your day as editor-in-chief, but you did a fantastic job—now you can relax and kick back by the pool.

Good job!

Just kidding! An editor-in-chief’s job is never done. Back to work!

...for pattern matching

Where to Go From Here?

Here’s the final playground. For further experimentation, you can play around with the code in the IBM Swift Sandbox.

If you want to read more about pattern matching in Swift, check out Greg Heo’s Programming in a Swift Style video at RWDevCon 2016.

I hope you find a way to use pattern matching in your own projects. If you have any questions or comments, please join the forum discussion below! :]

The post Pattern Matching in Swift appeared first on Ray Wenderlich.


Building macOS apps for profit, and iTC subscription changes – Podcast S06 E06

$
0
0
macOS apps

Can you build a sustainable business developing macOS apps? Find out in the episode!

Join Mic, Jake, and Andrew as they discuss whether you can build a sustainable business developing macOS apps, and what tools are available to support you. The team then move on to looking at the changes to the App Store subscription model that were announced just before WWDC and what benefits they deliver to both consumers and developers.

[Subscribe in iTunes] [RSS Feed]

Our Sponsor

Hired is the platform for the best iOS developer jobs.

Candidates registered with Hired receive an average of 5 offers on the platform, all from a single application. Companies looking to hire include Facebook, Uber and Stripe.

With Hired, you get job offers and salary and/or equity before you interview, so you don’t have to waste your time interviewing for jobs you might not end up wanting, and it’s totally free to use!

Plus you will receive a $2000 bonus from Hired if you find a job through the platform, just for signing up using the show’s exclusive link.

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

Show Notes

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 Building macOS apps for profit, and iTC subscription changes – Podcast S06 E06 appeared first on Ray Wenderlich.

iOS 10 Screencast: Live Speech Recognition

iOS 10 by Tutorials: First 6 Chapters Now Available!

$
0
0

Good news – the second early access release of iOS 10 by Tutorials is now available!

This release has 6/14 chapters ready:

  • Chapter 2: Xcode 8 Debugging Improvements (NEW!): Learn about the powerful new debugging tools in Xcode 8, including the new Thread Sanitizer and Memory Graph Debugger.

malloc-example

  • Chapter 4: Beginning Message Apps: Learn how to create your own sticker pack for Messages – with a custom user interface.

Custom Sticker Packs

  • Chapter 5: Intermediate Message Apps: Learn how to send custom, updatable messages, by creating a simple picture drawing and guessing game integrated into Messages.

Custom Message App

  • Chapter 8: User Notifications: Learn how to use the new iOS 10 User Notifications framework, and create Notification Content extensions and Notification Service app extensions.

content-extension-presented

  • Chapter 9: UIView Property Animator (NEW!): Learn about a new way of animating in iOS 10, which allows you to easily pause, reverse, and scrub through animations part-way through.

Animalation3

  • Chapter 10: Measurements and Units (NEW!): Learn about some new Foundation classes that help you work with measurements and units in an easy and type-safe way.
let cycleRide = Measurement(value: 25, unit: UnitLength.kilometers)
let swim = Measurement(value: 3, unit: UnitLength.nauticalMiles)
let marathon = Measurement(value: 26, unit: UnitLength.miles)
    + Measurement(value: 385, unit: UnitLength.yards)

This is the second of many early access releases for the book – stay tuned for some more early access releases soon!

iOS 10 by Tutorials Screencasts

As you probably know, in addition to making the book this year, we are also covering the content in screencast form! That way, you can choose how you prefer to learn: either written or video form.

To celebrate the second early access release of the book, we’re releasing another free iOS 10 screencast so you can see what they’re like.

This free screencast is on Measurements and Units, which covers the new classes in Foundation that make working with measurements much easier and less error prone. Enjoy!

Where to Go From Here?

Here’s how you can get your hands on the early access release of the book:

  • If you’re a raywenderlich.com subscriber, good news – you get free access while you are subscribed! Just visit your My Loot page to download the second early access release of the book (v0.2) immediately.
  • If you haven’t subscribed to raywenderlich.com yet, you should subscribe! You will get access to the book, the screencasts, and access to our entire video tutorial library.

    Now’s a great time to subscribe because we’re currently running a special launch celebration for our new videos site. Subscribe for a monthly subscription by next Tuesday, Aug 23 to get 50% off your first month with the following coupon code: RW1MV

  • If you just want the book, you can buy the book separately. This includes permanent access to the book, including early access versions and updates (but no screencasts or videos).

Thanks again to all raywenderlich.com subscribers – you are what makes this site possible. We hope you enjoy the iOS 10 book and screencasts – and stay tuned for more early access releases soon! :]

The post iOS 10 by Tutorials: First 6 Chapters Now Available! appeared first on Ray Wenderlich.

Screencast: Beginning C# Part 8: Conditionals

How To Be a Better Developer with Programming Challenges

$
0
0

Programming Challenges

If you’ve ever tried a programming challenge, then you know they are fun and addicting.

But they’re more than just fun – they also help you become a better developer.

Over the past few years, I’ve done hundreds of programming challenges. I’ve noticed the regular practice has made me a smarter, faster, and stronger developer.

In this article, I’ll explain how you can do the same:

  1. First, I’ll explain why programming challenges help you become a better developer.
  2. Next, I’ll recommend how you can get started with programming challenges.
  3. Finally, I’ll wrap up with some tips and tricks.

Get ready to get challenged!

Why Programming Challenges Work

To understand why programming challenges work, first you need to understand muscle memory.

Muscle Memory

Think back to when you were first learning how to drive. At first, it required your complete focus. You had to think about how fast you were going, worry when you were parking or merging into traffic, and so on. But now, you can drive while talking with someone and even singing your favorite song!

Driving while talking and singing

At first, performing an unfamiliar action takes focus. But if you practice enough, you can preform the action almost without thinking.

That’s muscle memory: knowing how to perform an action without conscious effort. And you can develop muscle memory for programming tasks too!

Programming as a Muscle Memory

Think back to when you first started programming on a new platform. It took a lot of effort at first, right? Often you needed to look up method names, read documentation, and so on.

But after a while, you developed muscle memory, and are now able to write code off the top of your head.

Muscle Memory

Consider a few other common programming tasks:

  • Creating a singleton
  • Using reduce to transform an array into a scalar
  • Handling errors and exceptions

When you first try these things, it can often be time consuming or confusing. But if you practice it enough, you will build a muscle memory with the solution.

At this point, you won’t need to think about how to solve the problem anymore. it will just become a normal routine when writing code.

This explains why programming challenges work. They give you opportunities to build muscle memory, via practice on common development challenges.

That way, the next time you need to solve a similar challenge, you’ll have a solution ready! This helps you be efficient and allows you to focus on larger problems, rather than the small details.

image-03-challenges

How To Get Started with Programming Challenges

Ready to start building some muscle memories? Luckily, there are some great sites out there offering programming challenges.

Here’s what I consider the best. I recommend you pick one that sounds interesting and give it a shot!

Note: These are not listed in any particular order.

HackerRank

HackerRank

HackerRank, formerly known as Interview Street, is a platform offering coding challenges, usually in the form of algorithms to implement. I love its slogan: “Your most productive distraction“.

On HackerRank, you’ll find:

  • Domains: A selection of problems to solve, categorized by type (algorithms, mathematic, AI, and more) or language.
  • Contests: Time-limited challenges where you’re challenged by a set of problems grouped by a common subject that must be solved within a predefined timeframe.
  • Rank & leaderboard statistics: See how you’re progressing compared to others and which achievements you’ve earned. A nice feature in the leaderboard is the ranking, grouped by complexity level (O(1), O(logn), O(n), and so forth), which helps with figuring out the average complexity of each user’s solutions.

Big O notation: What is it? It measures the complexity of an algorithm, and it’s used to figure out the expected processing time depending from the problem size.

It usually makes sense when the algorithm performs one or more loops, where the number of iterations is in strict relation with the input size.

For more details, check out our Collection Data Structures in Swift article.

Employers use time-limited challenges on HackerRank to evaluate potential candidates’ programming skills and problem-solving abilities with any of its available languages.

Note that employers can choose to reduce the list of available languages — I presume that a company looking for an Android developer wouldn’t be interested in a candidate who excels in Swift development. Well, at least not today. Tomorrow, who knows? :]

I recently participated in a screening process after getting an invite from Amazon — yes, that Amazon. :] The coding experience was pretty good and the available time was reasonable; I finished it in 1:58, just two minutes shy of the two-hour time limit.

Although the environment includes a web-based editor where you can write code and test, I always prefer a local, desktop-class IDE. In this case, I opted for CodeRunner, a coding editor that supports several languages and capable of compiling and running directly from the IDE.

To some extent, it’s similar to Swift playgrounds. The list of available languages and environments is pretty long — 45 in total — which includes new, old, OO, functional, imperative, shell, DB, and so forth. Just to name a few:

  • Swift
  • Objective-C
  • Pascal
  • Cobol
  • C#
  • F#
  • Haskell
  • Go
  • OCaml
  • R

Math Fights

MathFights

Among all the services reviewed in this article, MathFights is the only one where you don’t code. Actually, it’s not even about programming. As its name suggests, it’s about math challenges that are usually served as 1:1 fights.

Why mathematics? Well, this article is about keeping your brain sharp, and solving math problems does that. Practicing mathematics gives your brain elasticity.

Moreover, you use math daily as a developer, so being able to do calculations quickly can help in your daily life.

How it Works

You start a fight with a click of a button, then you’re matched with a random opponent and the fight begins!

You and your opponent are presented with one question at a time along with a list of potential answers. Your challenge is to determine the correct answer in the shortest possible time, staying within the predefined time limit.

Each question has a winner and loser; the winner is whomever chooses the right answer in the least amount of time. For each round, you and your opponent get a score. At the end of the fight, the player with the highest total score wins.

Pro tip: Keep some paper, a pencil and maybe a calculator nearby because you will have to calculate.

Math problems come in different shades of complexity, so MathFights uses divisions to group questions by difficulty. Division 1 hosts the simplest problems and is where you start. After a certain number of wins, you’re promoted to the next division. Look out: you’ll get a downgrade if you lose too many fights.

You can also create public or private tournaments, which is very handy when you and some friends want to engage in some friendly, intelligent competition.

Lastly, there’s a practice section where you can just solve problems without the pressure of a real opponent. It’s just you against yourself and a clock.

In my personal opinion, MathFights is undeniably addictive and remarkably useful. I used to spend a lot of time on it. One day I realized that it was becoming a distraction, so I decided to stop. This was after reaching division 7. Incidentally, I don’t know that I could have progressed much further. Staying there without getting a downgrade was pretty hard.

TopCoder

TopCoder

TopCoder was the one of the first (if not the first) service to offer coding challenges.

Whereas similar services offer explicit recruitment services to customers, or don’t have a business model at all, Topcoder has a few models that are probably unique in this area.

You, as a developer, can solve challenges, but can also participate in events that are somewhere between a paid gig and a contest. In fact, companies can create an event if they need fresh ideas for development projects, such as:

  • UI/UX design
  • Application development
  • Algorithms

Candidates compete to win a payment from the company. As you might expect, there’s a lot of competition, and usually only one winner per project. On the bright side, it’s absolutely an excellent way to test your capabilities on a real, tangible project.

The list of companies you might potentially work for are respectable names, such as:

  • NASA
  • IBM
  • eBay
  • Honeywell

There are also recurring tournaments, single-round matches and other contests, some of which allow or require teams. If you opt for a team contest, you collaborate with others in a hackathon-like format to solve a problem.

There’s a lot more to TopCoder than can reasonably be discussed here — covering it all would monopolize this article. Have a look, explore, then feel free to talk about what you find in our forums!

CodinGame

CodinGame

CodinGame is about coding games, but it’s not a freeform blank sheet of paper where you have to invent and draw your game.

Don’t let the presence of the word “Game” fool you into thinking this is a casual site — it’s not. It is, however, a unique way to stimulate your brain. In coding game you’re given:

  • A game plot
  • A scenario
  • Some actors
  • A goal

Your task is to write the AI. Pretty awesome and interesting, eh?

The site provides all the graphics, animations, effects, scenography, etc. CodinGame is a bit like being on a movie set where you’re the director; you write your script to control your actors, and then you watch them execute that script.

The list of languages is pretty long — 25 in total. For you Apple Developers, there’s Objective-C and Swift.

How does it work? You have a browser-based IDE, and it’s a full featured build that includes a:

  • Code editor
  • Console output
  • Help panel that has a description of the problem to solve
  • List of test cases
  • Action area, with buttons to run tests, start the simulator, submit your solution, etc.

Codingame IDE

The editor comes prepopulated with some skeleton code and a clear indication of where to write yours. Once you’re done coding you start running test cases.

When running a test case, the simulator actually shows the game with the AI-controlled actor following the orders you gave with your code. By the end of the simulation you know whether the test passed or not. If not, most likely your actor was killed. :]

CodinGame provides you with a rare opportunity to watch your code come to life — and it’s as amusing as it is stimulating. If you like games and coding, then this is the place to be.

Following an established pattern for coding challenge platforms, CodinGame also offers services that are designed for companies that want to hire candidates.

Now tell me: when you’re looking for your next job, which of the following two would you choose to show your expertise?

  1. An option to write code to implement a linked list on a “cold” white board
  2. An option to write AI for a bot whose goal is to kill its enemies that lets you use your browser for your IDE

The choice is clear. Killer AI bots are always the better choice for showing off your skills. :]

CodeFights

CodeFights

As soon as you land to the CodeFights, you immediately notice the appealing superhero avatars. Disappointingly, you can’t use them for your own profile — they’re just there for looks.

However, the site is not about cool avatars; it’s about coding and debugging.

Once you’ve registered, you’ll get an invite to a 1:1 fight with a bot. It’s pretty easy — any developer with 1 day of experience should be able to win the fight.

Each challenge consists of a three-round fight, and there are three types of challenges you need to solve:

  • Debug: you’re given some code and must locate and fix the bug
  • Recovery: you’ve given some incomplete code and must fill the missing part
  • Code writing: you implement a function from scratch

Each round comes with a description of the problem to solve.

One downside of this otherwise useful service is the restricted list of languages. There’s also no Swift or Objective-C, so iOS and macOS developers may feel some disappointment.

On the upside, you have its browser-based editor that sports autocompletion and smart navigation — you can use CTRL + left or right arrow to move to the previous/next word, even with camel case identifiers.

Besides battling bots, what else can you do on CodeFights?

  • Fight against real people — either friends you invite or random opponents
  • Join marathons
  • Participate in tournaments
  • Challenge company bots (Dropbox, Uber, Asana, Quora, and more), which can help you get noticed and maybe even hired
  • Create and submit your own challenge

CodeEval

CodeEval

CodeEval seems like a front end for a recruitment business. While that’s not entirely a negative thing, it is the feeling I got after registering and accessing to the dashboard. But that’s just my subjective take.

Once in the dashboard, I spent some time wondering what to do next. Unlike the other services reviewed here, there’s no guidance and no “check this” nor “do that” kind of UI. You have to explore on your own.

The number of available languages is 26. You won’t find Swift, but Objective-C made the cut. Besides the dashboard, which looks very nice, the rest of the experience is a little spartan.

The editor is suitable. It has auto-complete, but the comment font color is a little difficult to read. Copying and pasting into an external editor is highly recommended.

At CodeEval, there is only one type of challenge: you versus yourself. There are three lists of challenges that are divided by difficulty.

Another potentially useful section is the “Jobs & Offers” page. Here you can find job offers, some of which require you to solve a problem in order to apply — most likely, it’ll require coding. The rest of the posts are more traditional, static job ads.

Advent of Code

Advent Of Code

There are two things that I really love about Advent of Code:

  • Interface: it looks like an old, green phosphor monitor
  • Challenge result: you don’t have to submit your code — you just write the solution

Rather than having an IDE, a list of available languages, complexity, Big O notation, and so forth, Advent of Code just asks you to provide an answer to a question.

How you find the solution does not matter. Nobody cares what language your work in or how efficient your algorithm is. Advent of Code offers complete freedom of choice.

Alternatives to Online Challenges

Challenges are fun and fulfilling but not the only way to keep your brain sharp. There are other ways to stimulate your brain! Here are some of the best:

  • Hackathons: Sure, you’re solving problems, but you’re also fine-tuning your collaboration skills, which is vital for success. While you’re at it, you’ll probably also compete with your colleagues in subtle ways and pick up some new tricks. You might even find your next employer this way! A word of advice: they burn hot and fast and can be quite exhausting. I don’t recommend doing a hackathon every day — or week for that matter.
  • StackOverflow: Real people are very creative when it’s time to solve real problems. Not only can you get help when you’re stuck, but you can help others when they’re stuck. By participating, you’ll learn a lot and increase your fluency with the language(s) of your choice.
  • GitHub: What is there to say about this really? There’s just too much to discuss here in this review. To learn and challenge yourself, just pick a project and start coding.


Tips and Tricks

I’d like to wrap up with a few tips and tricks.

Competition and You

As you may have noticed, many of these programming challenge sites are competitive.

As humans, we’re naturally competitive. We compete on almost everything:

  • Catching the eyes of a special somebody before your friend does
  • Landing a job
  • Sitting in the front seat of a car
  • Having the TV remote

Competition often drives us to try harder than we would otherwise. This can be great when you’re trying to improve your coding skills.

But there are a few gotchas about competition I’d like to point out.

Competition is Not for Bragging

Competition is a tool to improve yourself, what you’re working on, and the people around you. It is not a way to prove you’re superior.

Having this attitude can cause significant problems in the workplace, as Sarah Mei notes:

135789_tweet-people-competing

So remember to stay focused on self-improvement, not superiority. As Swift team member Gemma Barlow said, “…friendly rivalry is always good as long as you’re striving to create a better product for your users”.

Competition has a Time and Place

image-04-devsfighting

Another thing to note is competition isn’t always the proper solution.

Unity team member Barbara Reichart said that she prefers the following:

  • When learning new things, she prefers to use cooperative environments. This way, when you’re learning you can be in a low-risk environment and can take your time.
  • When trying to become great at things you already know, she prefers competitive environments. This way, you can have a fire lit under you to drive you to the next level.

Finally, Gemma points out that competition isn’t for everyone. “It’s good to acknowledge that not all personality types thrive in a competitive environment, and there are other ways to keep your brain sharp.”

So remember – competition is a tool, and deploy it only when appropriate!

Take some Rest

These programming challenge sites can often be addicting, as I know from experience!

But be sure not to overdo it – your brain can only take in so much at a time. It’s better to be consistent and space it out.

Gemma put it well: “I would prefer to be getting some sunshine and resting my brain rather than continuing to stress it”.

That’s a good piece of advice. Don’t expect too much from your brain after you use it all day long. Would you expect your legs to run all day or your arms to do pushups nonstop?

Give it a break and let it relax, from time to time. Just don’t abuse it.

image-05-devcat

Where To Go From Here?

I hope that I’ve convinced you to give programming challenges a try!

Note there are more great places for programming challenges beyond what I’ve covered here. This article focused on those that I’ve used so that I could speak from experience.

I asked our readers what other sites they recommend, and they gave the following list:

Remember, although traditional learning and a challenging workplace are valuable tools, they’re not enough.

To be the best developer you can be, you want to build your muscle memory. You should look outside your comfort zone and work with unfamiliar tools and problems. That’s what programming challenges are all about!

I recommend you take a site mentioned in this article and give it a shot! Whatever you choose, what’s most important is that you do it regularly.

That’s it for now. If you have any questions, comments or suggestions, please join the discussion below!

Note: Special thanks to these wonderful people for the invaluable input they shared to help create this article:

raywenderlich.com tutorial team members:

raywenderlich.com readers:

I may not have quoted everybody, but trust me when I say that their input helped me a lot shaping and giving this article a direction!

The post How To Be a Better Developer with Programming Challenges appeared first on Ray Wenderlich.

Viewing all 4373 articles
Browse latest View live


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