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

Top 5 Parse Alternatives

$
0
0

parse-alternatives-feature

Recently, Facebook’s Parse (an extremely popular Backend-as-a-Service provider) announced they are shutting down, and the news took the development community by storm.

This is a huge deal because a huge amount of iOS apps use Parse as their backend, including EventBrite, Vevo, and even the White House. We were fans ourselves, and even wrote several tutorials about it.

But now – everyone who used Parse has to scramble to find an alternative.

In addition, that Parse has shut down, it has everyone thinking. Since Parse was one of the biggest and most popular BAAS providers, if it shut down, what else may shut down in the future? Is anything safe? Maybe we should think more carefully about the cost of taking shortcuts.

Fortunately, there are many alternatives to Parse. In this article, we’ve navigated the field, narrowing it down to what we personally consider the top five Parse alternatives.

Let’s dig in!

5) Custom Backend

1-database

What is it: Developing and hosting custom code

Website: N/A

Building a custom backend can be a daunting task, but if you have a bit of experience with a server-side programming language and know a thing or two about servers, this avoids having a dependency on a company that may shut down.

In addition, since you have full control, you can build handy some custom features. For example, if you wanted to do some fancy image processing or optical character recognition you have free reign to do whatever you need.

As Uncle Ben said, with great power comes great responsibility. A custom backend takes a lot of time to build, and afterwards requires regular maintenance – and for many small apps, this cost may not be worth the benefit. You also need to take the standard security precautions like getting an SSL Certificate, protecting database access, etc.

Rather than maintaining your own infrastructure, I’d recommend using a service like Heroku or Microsoft Azure to make it easier. Writing some some of your own code can introduce server-side bugs, which in addition to client-side bugs, can be a lot to handle.

In short, rolling out a custom backend is a rewarding experience and a great learning opportunity that gives you tons of power and flexibility, but in return costs a ton of work.

Pros:

  • Highly customizable and flexible
  • Can choose almost any language or framework

Cons:

  • Need to use/learn another programming language
  • Managing infrastructure like database, servers, etc. requires maintenance
  • Scaling can become an issue without prior experience
  • Can get costly quickly

4) Parse Server

2-parse-git

What is it: Open source server released by Parse/Facebook to replicate functionality of Parse

Website: Link

On the same day that Facebook announced they were shutting down Parse, they also released an open-source replacement called Parse Server, which you can download for free on Github. The lead developer of the project, Fosco Marotto, wrote that he doesn’t think of the recent news as Parse shutting down; he thinks of it as Facebook Open-Sources Parse.

Migration from Parse to Parse Server is supposed to be the most seamless of all the options, and there are many step-by-step guides that take you through the process. Since Parse models, users, functions, and more are supported, client side code doesn’t need to be changed all that much.

With many notable Parse features missing, it’s definitely not a perfect substitute. The developer community seems to be embracing Parse Server, and I would imagine that much of the missing functionality from Parse will soon be replicated in Parse Server. Although none of that is a definite at this point, but you can even create some additional features yourself, if you feel comfortable with Javascript.

Running Parse Server still requires you to maintain a server and a Mongo database, both of which can be challenging without some DevOps experience or a willingness to learn. Again, to make this a bit easier I’d recommend deploying Parse Server to an infrastructure-as-a-service like Heroku or Microsoft Azure.

Pros:

  • Will not require major changes client-side, since you can still use the Parse SDKs
  • Open-source – will always have access to it and the community will continue to build features
  • Can be hosted in almost any environment

Cons:

  • Many notable Parse features are missing including the Dashboard, Webhooks, Push delivery, Jobs, Analytics and Config
  • Requires provisioning a server, since it’s self-hosted

3) CloudKit

4-cloudkit

What is it: Apple Framework to help save data and store assets

Website: Link

In iOS 8, Apple introduced CloudKit – a new remote data storage service for apps based on iCloud. It provides a low-cost option to store and share data using users’ iCloud accounts as a back-end storage service.

CloudKit is great if data persistence is the top priority. The already generous usage limits increase as your app gets more users, which means that CloudKit will likely be free for most applications. The built-in subscriptions/notifications can be useful for social or other content-sharing applications. Your app can subscribe to changes on certain objects, and CloudKit will send the app a notification when those records are changed.

Although CloudKit is definitely iOS focused, Apple has released CloudKit JS to build simple web apps and recently released Server-side tokens, which allow your server to communicate with CloudKit services via a REST API.

One drawback is users are required to be signed into iCloud when saving any data, which can be a hinderance if some of your users are not logged in.

Pros:

  • Simple to start using – use Objective-C or Swift and built-in APIs
  • Subscriptions/Notifications when specific data is created, updated, or deleted
  • Generous limits that grow as your user base grows
  • User-friendly CloudKit Dashboard to manage data
  • Server-to-Server tokens
  • Tutorials and video tutorials on our site

Cons:

  • Limited to iOS (with the exception of CloudKit JS)
  • Users required to use iCloud

2) AWS Mobile Hub (DynamoDB, Lambda, API Gateway, Cognito)

3-aws

What is it: Integrated console that helps you create, build, test, and monitor your mobile apps that leverage AWS services

Website: Link

You can’t go far in the engineering world without someone mentioning “AWS” – Amazon Web Services.

Mobile Hub integrates many AWS services that handle user-related tasks like authentication, data storage, backend logic, push notifications, and more in one convenient dashboard. At a high level, API Gateway exposes (via URLs) code that’s written in Lambda. Lambda functions can then use many other services, including DynamoDB (a database) and Cognito (used for authentication).

The different components within AWS tend to play nice with each other. For example, it would be easy to upload files to Amazon S3 (Simple Storage Solution) and have a Lambda function process that image automatically. Wrapping your head around all these services and how they work is definitely challenging. Since AWS is ubiquitous, it may be worth the investment because it’s likely that you’ll encounter these services at another point in the future.

AWS’s generous limits and reasonable pricing mean that for a small app you may not have to pay at all, and as your app grows you won’t have to pay much more. Mobile Hub also has a handy feature that can generate custom client SDKs for iOS or Android based on what you have set up.

Mobile Hub and its components are very scalable and can handle almost any amount of users you can throw at it. AWS is growing rapidly and Amazon continues to invest in it, so I cannot imagine it will disappear anytime soon.

Pros:

  • Can replace almost every Parse feature from cloud code to analytics to push notifications
  • Works well with many of Amazon’s services
  • Very scalable
  • Best in-class pricing with generous limits

Cons:

  • Need to use another programming language (Java, Python, or Node.js)
  • Somewhat steep learning curve

1) Firebase

5-firebase

What is it: Cross platform realtime database, with authentication and static hosting

Website: Link

Firebase is one of the most popular replacements for Parse and for good reason. Their SDK is simple to use and you can start saving data in no time. Authentication with Facebook, Google, Twitter, Github, or email is a breeze with Firebase, especially since there is no additional backend needed.

Dedicated Parse users will also appreciate anonymous users, which is a Parse favorite. Also, similar to Parse is offline storage: Firebase can also serve as a replacement to Core Data–something that can save you hours of development time. The realtime database is great for something like a chat app, or any other use case where data transmission is time sensitive. The JSON tree data architecture is a bit different than traditional data architecture and definitely takes some getting used to.

One of the main things Firebase is missing is built-in push notifications. To fix that problem, you can use a service like Batch as a supplement. Instead of a built-in way to add “Cloud Functions” (custom server-side code) like there is in Parse, you must provision your own server and add additional logic there when using Firebase. Although there are third-party libraries for many of the more common languages such as PHP, Python, and Ruby, it is not as straightforward.

Although it might seem like Firebase is missing some key features, its blend of ease of use and being great at what it does makes it our number one Parse replacement. Google has said that they will continue to support Firebase indefinitely, but you never know!

Pros:

  • Multi-platform: iOS, Android, JS, REST
  • Authentication with many different providers without server code
  • Works offline
  • Asset hosting
  • May act as a Core Data replacement
  • Realtime database
  • Tutorial on our site

Cons:

  • No push notifications (can use Batch to supplement)
  • JSON tree data architecture has a learning curve
  • No simple way to add “Cloud Code”

Where To Go From Here?

You don’t want your backend to be a bottleneck for your app, so you should definitely choose carefully. One additional risk to consider using any service is longevity, or lack of. If the service is not around in a year or two, you’ll have to find another alternative and migrate again. Also keep in mind how easy it is to migrate data away from a specific platform/stack.

Some of these options require more server and DevOps knowledge than others, which can add a significant amount of complexity. Looking at costs upfront is important, but also take a look at how those costs will scale as your app scales. The most important thing to keep in mind is to use technology you either are looking forward to learning or are already comfortable with.

Not sure which to choose yet? Here’s our advice based on your situation:

  • If you want a lot of flexibility and have some experience maintaining your own server, building a custom backend is a great option.
  • If you want to change as little client code as possible, Parse Server will get the job done.
  • If you want a straight-forward way to store data and are iOS only, CloudKit is probably the best option.
  • If you want a lot of flexibility but don’t want to manage infrastructure, AWS Mobile Hub is a great option.
  • If you really liked the idea of Parse, and want something similar, Firebase is the best bet.

For more discussion on the Parse shutdown, check out our recent podcast episode on the topic.

And that’s it – best of luck with your decision! We know there are many other Parse alternatives out there, so don’t forget to chime in with what you consider the best Parse alternatives, by joining the forum discussion below.

The post Top 5 Parse Alternatives appeared first on Ray Wenderlich.


Video Tutorial: Beginning iOS Animation Part 9: Intermediate View Controller Transitions

Firebase Tutorial: Real-time Chat

$
0
0
firebase tutorial

Hey! Let’s chat.

It seems like every major app out there has a chat feature — and yours should be no different!

However, creating a chat tool can seem like a daunting task. There’s no native UIKit controls designed specifically for chat, and you’ll need a server to coordinate the messages and conversations between users.

Fortunately, there’s some great frameworks out there to help you: Firebase lets you synchronize real time data without writing a line of server code, while JSQMessagesViewController gives you a messaging UI that’s on par with the native Messages app.

In this Firebase tutorial you’ll build an anonymous chat app named ChatChat that looks like the following:

firebase tutorial

Along the way, you’ll learn how to do the following:

  • Set up the Firebase SDK and JSQMessagesViewController with CocoaPods.
  • Synchronize data in real time with the Firebase database.
  • Authenticate anonymously with Firebase.
  • Leverage JSQMessagesViewController for a complete chat UI.
  • Indicate when a user is typing.

Enough chit-chat — it’s time to get started! :]

Getting Started

To get started with this Firebase tutorial, download the starter project here; at present, it contains a simple dummy login screen.

You’ll use CocoaPods to install both the Firebase SDK and JSQMessagesViewController. If you’re new to CocoaPods, check out our Cocoapods with Swift tutorial to get up and running.

Open Terminal at the project’s folder location. Create an empty Podfile at the project’s root folder, then inside the Podfile declare the Firebase SDK and JSQMessagesViewController as dependencies like so:

platform :ios, "9.0"
use_frameworks!
target 'ChatChat' do
  pod 'Firebase'
  pod 'JSQMessagesViewController'
end

Save the Podfile and run the following command to install your dependencies:

pod install

Once the packages have installed, open the newly created ChatChat.xcworkspace and build and run. You should see the following:

firebase tutorial

Note: For the remainder of this Real time Chat tutorial, you’ll see this view each time you build and run. Tap Login anonymously each time to move to the next view. At present, the button does nothing, but you’ll fix that shortly.

If you’re new to Firebase you’ll need to create an account. Don’t worry – this is easy and totally free, as in credit-card free.

Note: For a detailed walkthrough on setting up Firebase, see the Getting Started with Firebase tutorial.

Create a Firebase Account

Head to the Firebase signup site, create an account, and then create a Firebase app. For this Real time Chat tutorial, you’ll use the real-time database and authentication services of your new app.

Enabling Anonymous Authentication

Firebase lets users login through email or social accounts, but it can also authenticate users anonymously, which gives you a unique identifier for a user without knowing any information about them.

Anonymous authentication is like saying, “I don’t know who you are, but I know you’re there.” It’s great for situations like guest accounts and trial runs. It also fits this tutorial perfectly, because ChatChat is all about anonymity.

To set up anonymous authentication, open the Firebase App Dashboard, select the Login & Auth tab, click Anonymous, and tick the Enable Anonymous User Authentication checkbox:

firebase tutorial

Just like that, you’ve enabled super secret stealth mode! Okay, so it’s really just anonymous authentication, but hey — it’s still cool. :]

firebase tutorial

Logging In

Open LoginViewController.swift and add the following import:

import Firebase

To login to chat, the app will need to open a connection to the Firebase database. Add the following code to LoginViewController.swift:

class LoginViewController: UIViewController {
 
  // MARK: Properties
  var ref: Firebase! // 1
 
  override func viewDidLoad() {
    super.viewDidLoad()
    ref = Firebase(url: "https://<my-firebase-app>.firebaseio.com") // 2
  }
}

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

  1. First, you specify a Firebase database reference as a property.
  2. Then, using your Firebase App URL, you initialize the property and create a connection to the Firebase database.

If you’re not sure what your Firebase App URL is, you can find it in your Firebase App Dashboard:

firebase tutorial

To log a user in, you call authAnonymouslyWithCompletionBlock(_:) on your database reference.

Add the following code to loginDidTouch(_:):

@IBAction func loginDidTouch(sender: AnyObject) {
  ref.authAnonymouslyWithCompletionBlock { (error, authData) in // 1
    if error != nil { print(error.description); return } // 2
    self.performSegueWithIdentifier("LoginToChat", sender: nil) // 3
  }
}

Here’s a run-down of what you’re doing in this code:

  1. From the ref, call authAnonymouslyWithCompletionBlock(_:) to log a user in anonymously.
  2. Check for an authentication error.
  3. Inside of the closure, trigger the segue to move to ChatViewController.

You might be wondering why this code ignores authData. While this callback parameter contains a unique identifier for the user, you don’t need to worry about passing it around. After you’ve authenticated a user, you’ll have access to authData as a property on any Firebase database reference in the following way:

// if authenticated, it will print the current user information
print(ref.authData)

Creating the Chat Interface

JSQMessagesViewController is a souped up UICollectionViewController that’s customized for chat.

This Firebase tutorial will focus on the following five things:

  1. Creating message data
  2. Creating colored message bubbles
  3. Removing avatar support
  4. Changing the text color of a UICollectionViewCell
  5. Indicating when a user is typing

Almost everything you’ll need to do requires that you override methods. JSQMessagesViewController adopts the JSQMessagesCollectionViewDataSource protocol, so you only need to override the default implementations.

Note: For more information on JSQMessagesCollectionViewDataSource, check out the documentation here.

Open up ChatViewController.swift and import Firebase and JSQMessagesViewController as shown below:

import Firebase
import JSQMessagesViewController

Change the subclass from UIViewController to JSQMessagesViewController:

class ChatViewController: JSQMessagesViewController {

Now that ChatViewController extends JSQMessagesViewController, you’ll need to set initial values for senderId and senderDisplayName so the app can uniquely identify the sender of the messages — even if it doesn’t know specifically who that person is.

In LoginViewController, you can use ref.authData to populate the user’s specific data on the ChatViewController as the segue is being prepared.

Add the following method to LoginViewController:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
  super.prepareForSegue(segue, sender: sender)
  let navVc = segue.destinationViewController as! UINavigationController // 1
  let chatVc = navVc.viewControllers.first as! ChatViewController // 2
  chatVc.senderId = ref.authData.uid // 3
  chatVc.senderDisplayName = "" // 4
}

Here’s what you’re doing in the code above:

  1. Retrieve the destination view controller from segue and cast it to a UINavigationController.
  2. Cast the first view controller of the UINavigationController as ChatViewController.
  3. Assign the local user’s ID to chatVc.senderId; this is the local ID that JSQMessagesViewController uses to coordinate messages.
  4. Make chatVc.senderDisplayName an empty string, since this is an anonymous chat room.

Note that you only get one anonymous authentication session per app session. Each time you restart the app, you’ll get another, unique, anonymous user. As you start and stop the simulator, you’ll see different user IDs.

Build and run to take a look at your app in super-secret stealth mode:

firebase tutorial

By simply inheriting from JSQMessagesViewController you get a complete chat UI. Fancy chat UI win!

firebase tutorial

Setting Up the Data Source and Delegate

Now that you’ve seen your new awesome chat UI, you’re probably excited to start displaying messages. But before you do that, you have to take care of a few things first.

To display messages, you need a data source to provide objects that conform to the JSQMessageData protocol and you need to implement a number of delegate methods. You could create your own class that conforms the JSQMessageData protocol, but you’ll use the built-in JSQMessage class that is already provided.

At the top of ChatViewController, define the following property:

// MARK: Properties
var messages = [JSQMessage]()

messages is an array to store the various instances of JSQMessage in your app.

Still in ChatViewController, implement the two delegate methods below:

override func collectionView(collectionView: JSQMessagesCollectionView!, 
    messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
  return messages[indexPath.item]
}
 
override func collectionView(collectionView: UICollectionView, 
    numberOfItemsInSection section: Int) -> Int {
  return messages.count
}

You’re probably no stranger to the two types of delegate methods above. The first is much like collectionView(_:cellForItemAtIndexPath:), but for message data. The second is the same old collectionView(_:numberOfItemsInSection:).

You’ll also need to implement the required delegate methods for message data, message bubble images, and avatar images. The message data delegates have been taken care of, so you’ll tackle the bubble and avatar images next.

Message Bubble Colors

The messages displayed in the collection view are simply images with text overlaid. There are two types of messages: outgoing and incoming. Outgoing messages are displayed to the right and incoming messages on the left.

In ChatViewController, add the following properties:

var outgoingBubbleImageView: JSQMessagesBubbleImage!
var incomingBubbleImageView: JSQMessagesBubbleImage!

Then add the following method:

private func setupBubbles() {
  let factory = JSQMessagesBubbleImageFactory()
  outgoingBubbleImageView = factory.outgoingMessagesBubbleImageWithColor(
      UIColor.jsq_messageBubbleBlueColor())
  incomingBubbleImageView = factory.incomingMessagesBubbleImageWithColor(
      UIColor.jsq_messageBubbleLightGrayColor())
}

JSQMessagesBubbleImageFactory has methods that create the images for the chat bubbles. There’s even a category provided by JSQMessagesViewController that creates the message bubble colors used in the native Messages app.

Using the methods bubbleImageFactory.outgoingMessagesBubbleImageWithColor() and bubbleImageFactory.incomingMessagesBubbleImageWithColor(), you can create the images for outgoing and incoming messages respectively.

Add the following call to setupBubbles() in viewDidLoad():

override func viewDidLoad() {
  super.viewDidLoad()
  title = "ChatChat"
  setupBubbles()
}

And with that, you have the image views needed to create outgoing and incoming message bubbles! Before you get too excited, you’ll need to implement the delegate methods for the message bubbles.

Setting the Bubble Images

To set the colored bubble image for each message, you’ll need to override a method of JSQMessagesCollectionViewDataSource.

collectionView(_:messageBubbleImageDataForItemAtIndexPath:) asks the data source for the message bubble image data that corresponds to the message data item at indexPath in the collectionView. This is exactly where you set the bubble’s image.

Add the following to ChatViewController:

override func collectionView(collectionView: JSQMessagesCollectionView!, 
    messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {
  let message = messages[indexPath.item] // 1
  if message.senderId == senderId { // 2
    return outgoingBubbleImageView
  } else { // 3
    return incomingBubbleImageView
  }
}

Taking the above code step-by-step:

  1. Here you retrieve the message based on the NSIndexPath item.
  2. Check if the message was sent by the local user. If so, return the outgoing image view.
  3. If the message was not sent by the local user, return the incoming image view.

The final steps before you build and run are to remove avatar support and close the gap where the avatars would normally get displayed.

In ChatViewController add the following method:

override func collectionView(collectionView: JSQMessagesCollectionView!, 
    avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
  return nil
}

Next, find viewDidLoad() and add the following:

// No avatars
collectionView!.collectionViewLayout.incomingAvatarViewSize = CGSizeZero
collectionView!.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero

JSQMessagesViewController does provides support for avatars, but you don’t need (or want) avatars in your anonymous ChatChat app. To remove the avatar image, you simply return nil for each message’s avatar display and tell the layout to size each avatar at CGSizeZero, which is “no size”.

Build and run your app. After logging in, you’ll see a blank chat screen:

firebase tutorial

Time to start the conversation and add a few messages!

Creating Messages

Create the following method in ChatViewController:

func addMessage(id: String, text: String) {
  let message = JSQMessage(senderId: id, displayName: "", text: text)
  messages.append(message)
}

This helper method creates a new JSQMessage with a blank displayName and adds it to the data source.

Add a few hardcoded messages in viewDidAppear(_:) to see things in action:

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
  // messages from someone else
  addMessage("foo", text: "Hey person!")
  // messages sent from local sender
  addMessage(senderId, text: "Yo!")
  addMessage(senderId, text: "I like turtles!")
  // animates the receiving of a new message on the view
  finishReceivingMessage()
}

Build and run you app; you’ll see the messages appear in the conversation view:

firebase tutorial

Hm, the text is a bit hard to read on the incoming messages. It should probably be black.

Message Bubble Text

As you’ve realized by now, to do almost anything in JSQMessagesViewController, you just need to override a method. To set the text color, use the good old fashioned collectionView(_:cellForItemAtIndexPath:).

Add the following method in ChatViewController:

override func collectionView(collectionView: UICollectionView, 
    cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
  let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath) 
      as! JSQMessagesCollectionViewCell
 
  let message = messages[indexPath.item]
 
  if message.senderId == senderId {
    cell.textView!.textColor = UIColor.whiteColor()
  } else {
    cell.textView!.textColor = UIColor.blackColor()
  }
 
  return cell
}

If the message is sent by the local user, the text color is white. If it’s not sent by the local user, the text is black.

Build and run; you should see incoming messages in black text:

firebase tutorial

Boom — that’s one nice looking chat app! Time to make it work (for real) with Firebase.

Firebase Data Structure

Before you get going on the realtime data synchronization, take a moment and think about the data structure first.

The Firebase database is a NoSQL JSON data store. Essentially, everything in the Firebase database is a JSON object, and each key of this JSON object has its own URL.

Here’s a sample of how your data could look as a JSON object:

{
  // https://<my-firebase-app>.firebaseio.com/messages
  "messages": {
    "1": { // https://<my-firebase-app>.firebaseio.com/messages/1
      "text": "Hey person!", // https://<my-firebase-app>.firebaseio.com/messages/1/text
      "senderId": "foo" // https://<my-firebase-app>.firebaseio.com/messages/1/senderId
    },
    "2": {
      "text": "Yo!",
      "senderId": "bar"
    },
    "2": {
      "text": "Yo!",
      "senderId": "bar"
    },
  }
}

The Firebase database favors a denormalized data structure, so it’s okay to include senderId for each message item. A denormalized data structure means you’ll duplicate a lot of data, but the upside is faster data retrieval. Tradeoffs — we haz them! :]

Setting Up the Firebase Reference

Add the following properties to ChatViewController.swift:

let rootRef = Firebase(url: "https://<my-firebase-app>.firebaseio.com/")
var messageRef: Firebase!

In viewDidLoad(), initialize messageRef as follows:

override func viewDidLoad() {
  super.viewDidLoad()
  title = "ChatChat"
  setupBubbles()
  // No avatars
  collectionView!.collectionViewLayout.incomingAvatarViewSize = CGSizeZero
  collectionView!.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero
  messageRef = rootRef.childByAppendingPath("messages")
}

Creating rootRef creates a connection to the Firebase database. Then to create messageRef, you use childByAppendingPath(), which is simply a helper method for creating a child reference.

In case you’re wondering, creating another reference doesn’t mean you’re creating another connection. Every reference shares the same connection to the same Firebase database.

Sending Messages

You may have been a bit eager and tapped the “Send” button already; if so, you probably saw the app crash. Now that you’re hooked up to the Firebase database, you can send a few messages for real.

First, delete ChatViewController‘s viewDidAppear(_:) to remove the stub test messages.

Then, override the following method to make the “Send” button save a message to the Firebase database.

override func didPressSendButton(button: UIButton!, withMessageText text: String!, senderId: String!, 
    senderDisplayName: String!, date: NSDate!) {
 
  let itemRef = messageRef.childByAutoId() // 1
  let messageItem = [ // 2
    "text": text,
    "senderId": senderId
  ]
  itemRef.setValue(messageItem) // 3
 
  // 4
  JSQSystemSoundPlayer.jsq_playMessageSentSound()
 
  // 5
  finishSendingMessage()
}

Here’s what’s going on:

  1. Using childByAutoId(), you create a child reference with a unique key.
  2. Create a dictionary to represent the message. A [String: AnyObject] works as a JSON-like object.
  3. Save the value at the new child location.
  4. Play the canonical “message sent” sound.
  5. Complete the “send” action and reset the input toolbar to empty.

Build and run; open up your Firebase App Dashboard and click on the Data tab. Send a message in the app and you should see the messages appear in the dashboard in real time:

firebase tutorial

High five! You’re saving messages to the Firebase database like a pro. The messages don’t appear on the screen, but you’ll take care of that next.

Real Time Data Synchronization with Firebase

Every time you update data in the Firebase database, the database pushes the update to every connected app. Data synchronization in Firebase works in three parts: a URL, an event, and a snapshot.

For example, here’s how you can observe for new messages:

let ref = Firebase(url: "https://<my-firebase-app>.firebaseio.com/messages") // 1
ref.observeEventType(.ChildAdded) { (snapshot: FDataSnapshot!) in { // 2
  print(snapshot.value) // 3
}

Here’s what’s going on:

  1. Using your Firebase App URL, you create a Firebase database reference. The URL you pass points to the data to read.
  2. Call observeEventType(_:FEventType:), with FEventType.ChildAdded. The child-added event fires off for every item at the URL’s location.
  3. The closure receives a FDataSnapshot (the snapshot) that contains the data and other helpful methods.

Synchronizing the Data Source

Now that you’ve seen how easy it is to synchronize data with Firebase, wire up the data source.

Add the following to ChatViewController:

private func observeMessages() {
  // 1
  let messagesQuery = messageRef.queryLimitedToLast(25)
  // 2
  messagesQuery.observeEventType(.ChildAdded) { (snapshot: FDataSnapshot!) in
    // 3
    let id = snapshot.value["senderId"] as! String
    let text = snapshot.value["text"] as! String
 
    // 4
    self.addMessage(id, text: text)
 
    // 5
    self.finishReceivingMessage()
  }
}

Taking each numbered comment in turn:

  1. Start by creating a query that limits the synchronization to the last 25 messages.
  2. Use the .ChildAdded event to observe for every child item that has been added, and will be added, at the messages location.
  3. Extract the senderId and text from snapshot.value.
  4. Call addMessage() to add the new message to the data source.
  5. Inform JSQMessagesViewController that a message has been received.

Next, call observeMessages() in viewDidAppear(_:):

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
  observeMessages()
}

Build and run your app; you should see any messages sent earlier along with any new ones you enter:

firebase tutorial

Congrats! You have a real time chat app! Now it’s time to do some even fancier things, such as detecting when a user is typing.

Knowing When a User is Typing

One of the coolest features of the Messages app is seeing the “user is typing” indicator. When the little bubble pops up, you know another user is typing into the keyboard. This is indicator is super-important, because it keeps us from sending those awkward “Are you still there?” messages.

There are many ways of detecting typing, but textViewDidChange(_:textView:) is a great place to check. For example:

override func textViewDidChange(textView: UITextView) {
  super.textViewDidChange(textView)
  // If the text is not empty, the user is typing
  print(textView.text != "")
}

To determine whether the user is typing, you check the value of textView.text. If the value is anything other than the empty string, you know that the user has entered text.

Using Firebase, you can update the Firebase database when a user is typing. Then, in response to the database getting updated with this indication, you can display the “user is typing” indicator.

To do this, first add the following properties to ChatViewController:

var userIsTypingRef: Firebase! // 1
private var localTyping = false // 2
var isTyping: Bool {
  get {
    return localTyping
  }
  set {
    // 3
    localTyping = newValue
    userIsTypingRef.setValue(newValue)
  }
}

Here’s what you need to know about these properties:

  1. Create a reference that tracks whether the local user is typing.
  2. Store whether the local user is typing in a private property.
  3. Using a computed property, you can update userIsTypingRef each time you update this property.

Add the following method to ChatViewController:

private func observeTyping() {
  let typingIndicatorRef = rootRef.childByAppendingPath("typingIndicator")
  userIsTypingRef = typingIndicatorRef.childByAppendingPath(senderId)
  userIsTypingRef.onDisconnectRemoveValue()
}

This method creates a reference to the URL of /typingIndicator, which is where you’ll update the typing status of the user. You don’t want this data to linger around after users have logged out, so you can delete it once the user has left using onDisconnectRemoveValue().

Update viewDidAppear(_:) to call observeTyping():

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
  observeMessages()
  observeTyping()
}

Now add textViewDidChange(_:textView:) to ChatViewController and set isTyping for each update:

override func textViewDidChange(textView: UITextView) {
  super.textViewDidChange(textView)
  // If the text is not empty, the user is typing
  isTyping = textView.text != ""
}

Finally, add the following code at the end of didPressSendButton(_:withMessageText:senderId:senderDisplayName:date:) function to reset the typing indicator:

isTyping = false

Build and run your app; pull up the Firebase App Dashboard to view the data. When you type a message, you should see the typingIndicator record update for the user:

firebase tutorial

Wahoo! You now know when a user is typing! Now it’s time to work on displaying the indicator.

Querying for Typing Users

The “user is typing” indicator should display every time any user is typing, with the exception of the local user. You can safely assume that the local user knows when they’re typing.

Using a Firebase query, you can retrieve all of the users that are currently typing. Add the following property to ChatViewController:

var usersTypingQuery: FQuery!

This property holds an FQuery, which is just like a Firebase reference, except that it’s ordered by an order function.

Next, modify observeTyping() like so:

private func observeTyping() {
  let typingIndicatorRef = rootRef.childByAppendingPath("typingIndicator")
  userIsTypingRef = typingIndicatorRef.childByAppendingPath(senderId)
  userIsTypingRef.onDisconnectRemoveValue()
 
  // 1
  usersTypingQuery = typingIndicatorRef.queryOrderedByValue().queryEqualToValue(true)
 
  // 2
  usersTypingQuery.observeEventType(.Value) { (data: FDataSnapshot!) in
 
    // 3 You're the only typing, don't show the indicator
    if data.childrenCount == 1 && self.isTyping {
      return
    }
 
    // 4 Are there others typing?
    self.showTypingIndicator = data.childrenCount > 0
    self.scrollToBottomAnimated(true)
  }
 
}

Here’s what’s going on:

  1. You initialize the query by retrieving all users who are typing. This is basically saying, “Hey Firebase, go to the key /typingIndicators and get me all users for whom the value is true.”
  2. Observe for changes using .Value; this will give you an update anytime anything changes.
  3. You need to see how many users are in the query. If the there’s just one user, check to see if the local user is typing. If so, don’t display the indicator.
  4. If there are more than zero users, and the local user isn’t typing, it’s safe to set the indicator. Call scrollToBottomAnimated(_:animated:) to ensure the indicator is displayed.

Before you build and run, grab a physical iOS device, as testing this situation takes two devices. Use the simulator for one user, and your device for the other.

Now, build and run your app on both the simulator and the device. When one user types you should see the indicator appear:

firebase tutorial
Kaboom! You just made a big, bad, real time, user-typing-indicating, chat app. Go grab yourself your favorite beverage, you earned it!

Where To Go From Here?

You can download the completed project with all of the code you’ve developed in this Firebase tutorial.

You now know the basics of Firebase and JSQMessagesViewController, but there’s plenty more you can do, including one-to-one messaging, social authentication, and avatar display.

To take this app even further, you could take a look at the Firebase iOS documentation.

If you’re interested in authenticating users via social accounts, check out the guide for Firebase user authentication, as it covers Twitter, Google, Facebook, and GitHub.

I hope you’ve enjoyed this Firebase tutorial; if you have any questions feel free to leave them in the (non-anonymous yet avatar-enabled) discussion below! :]

The post Firebase Tutorial: Real-time Chat appeared first on Ray Wenderlich.

A Special Surprise Next Monday!

$
0
0

This is just a quick heads up that a special surprise is coming to raywenderlich.com next Monday, Feb 15.

Can you guess what it is?

teaser

Happy guessing, and be sure to check back on Monday! :]

The post A Special Surprise Next Monday! appeared first on Ray Wenderlich.

Announcing the tvOS Apprentice Week!

$
0
0

tvOS-week

Ever since the tvOS SDK was first released, the Tutorial Team has been working on the definitive book on Apple TV development: the tvOS Apprentice.

Today, we have some exciting news – the book is now 100% complete and available today!

To celebrate the book launch, we’ll be posting some free tvOS tutorials this week, and giving away some free copies of the book – and even a brand new Apple TV.

Keep reading to find out more about the tvOS Apprentice, how to enter the giveaway, and how to get your launch discount.

Introducing the tvOS Apprentice

The tvOS Apprentice teaches you everything you need to know to develop great apps for the Apple TV – whether you’re a seasoned iOS pro, or a web developer looking to leverage your skills to a new platform.

The book covers both of the ways you can make tvOS apps:

  • TVML apps: The first way to make apps is via TVML and TVJS – a new markup language and programming language created specifically for tvOS apps. Web developers will rejoice, and even native iOS developers will discover this is quite powerful, and can save a lot of development time.
  • Traditional apps: The second way to make apps is the traditional approach – coding apps in Swift or Objective-C, using frameworks from iOS like UIKit, AVFoundation, StoreKit, and more. iOS developers will discover this leverages your existing expertise and code, and allows you to make a fully custom user interface.

This book is a whopping 28 chapters and 538 pages, covering all aspects of tvOS development from beginner to advanced. Let’s take a look at what’s ahead.

Section I: Architecture

TVMLDiagram2

This section contains just one chapter, designed to give you a birds-eye view of how tvOS works and help you decide what to read next.

  1. Chapter 1, Architecture: The architecture chapter is the introduction to the technology behind Apple TV apps. This chapter will be your guide to help you decide your path through the rest of the book.

Section II: TVML Apps

22_playback

This section covers the basics for creating an app via the TVML approach. From the basics of Hello World through a real world example, by the end of this section you’ll know everything you need to create client / server apps for Apple TV.

  1. Chapter 2, Hello, TVML: Shows you how to set up a basic Hello World app using TVML and Javascript.
  2. Chapter 3, Beginning TVML: You’ll use basic TVML templates to manipulate the UI in a simple application.
  3. Chapter 4, Intermediate TVML: Building off of chapter 3, you’ll learn more complicated interfaces and templates.
  4. Chapter 5, TVJS: Start working in Javascript and learn to manipulate the TVML DOM.
  5. Chapter 6, Exploiting Native Functionality from TVML: Learn how to take advantage of native libraries and integrate them with your TVML app.
  6. Chapter 7, Harnessing the Server: Now that you’ve got all the basics down, this chapter will walk you through a real world example with industry standard server technologies.

Section III: Traditional Apps

HeaderView

This section covers the basics for creating apps via the traditional approach. You’ll learn the new libraries created for Apple TV, and how the ported libraries from iOS can be used.

  1. Chapter 8, Hello, Traditional App: Learn how to set up a basic “Hello World” app using native libraries in Swift.
  2. Chapter 9, Basic Controls: Learn the basic controls your users can use to interact with your apps.
  3. Chapter 10, Stack Views: Stack Views are the backbone to the layout of your app – learn how to use them here.
  4. Chapter 11, Collection Views: See how easy it is to display a list of items in an engaging layout.
  5. Chapter 12, Navigation: Learn how to set up different forms of screen to screen navigation.
  6. Chapter 13, Focus: Apple TV uses a whole new Focus paradigm to show the user what control is currently selected – learn how this works and what it means for your apps.
  7. Chapter 14, Animation: Get ready to add some delightful animation to your tvOS apps.
  8. Chapter 15, Networking: Learn how to download content, video, and other assets over the network.

Section IV: Advanced Frameworks

shuffle

This section covers some of the more advanced frameworks you’ll need for many TV app use cases. Whether you took the TVML approach or the Traditional approach, these frameworks will be important to understand to make your app stand out.

  1. Chapter 16, User Input and the Controller: Learn how your app can interact with the new Apple TV remote.
  2. Chapter 17, Beginning Video Playback: One of the most common requirements for Apple TV apps will be to play video – learn how to do that here.
  3. Chapter 18, Advanced Video Playback: Learn about some of the more advanced topics in playing videos.
  4. Chapter 19, On Demand Resources: Learn how to use Apple’s easy to use storage system, so your app can download assets on the fly.
  5. Chapter 20, Beginning CloudKit: Learn how to use CloudKit on tvOS to store your app’s data.
  6. Chapter 21, Advanced CloudKit: Go further in depth with CloudKit with user specific storage and error handling.
  7. Chapter 22, In App Purchase: Monetize your app by allowing users to purchase digital goods.
  8. Chapter 23, Native UI in TVML Apps: Learn how to augment the TVML-to-UIKit engine to create custom resources, TVML tags, and styling properties.

Section V: Design

layersMixup

This chapter covers new design concepts introduced in tvOS. For your app to stand apart from the rest, you’ll need to understand these new design concepts well.

  1. Chapter 24, tvOS Design: Learn how to design your apps to fit in well with the tvOS ecosystem.
  2. Chapter 25, Creating Layered Images: Shows how to create a new kind of image specifically for the TV.
  3. Chapter 26, The Top Shelf: The Top Shelf is a new design concept that allows your app to show off specific content – learn how to use this in your apps.

Bonus Chapters

And that’s not all – on top of the above, we have some bonus chapters for you.

  1. Chapter 27, Javascript Crash Course: Developing TVML apps for tvOS requires some Javascript knowledge. If you’re new to Javascript, check here for a quick crash course.
  2. Chapter 28, Server Deployment: Similarly, developing TVML apps for tvOS requires some knowledge for being able to deploy servers. We have a crash course on that for you too. :]

tvOS Apprentice Week and Giveaway

calendar-tvos

Today, we are launching the book, and from Tuesday to Thursday, we’ll be releasing 3 select chapters from the book as free tutorials on this site. This will give you a chance to check out the book – we’re confident you’ll love it! :]

On Friday, we’ll round out our week of celebration with a special giveaway.

  • 4 lucky winners will win a free copy of the tvOS Apprentice PDF version (or a book of your choice if you already have the tvOS Apprentice)
  • 1 lucky winner will win a brand new Apple TV!

Note the winner of the Apple TV must reside in the US for shipping purposes (sorry international folks). If someone outside the US ends up winning, you can choose a free PDF book of your choice instead.

To enter into this giveaway, simply leave a comment on this post, or any of the tutorials that come out this week. We’ll choose winners randomly and announce the results on Friday.

Where To Go From Here?

As mentioned, the tvOS Apprentice is now 100% complete and available today.

  • If you preordered the tvOS Apprentice, you can download the book immediately on your My Loot page.
  • If you don’t have the tvOS Apprentice yet, we have some good news. To celebrate the launch week, we are extending our current $10 off discount until this Friday. So if you want the discount, be sure to order now.

We hope you enjoy the tvOS Apprentice Week, and look forward to seeing some amazing Apple TV apps from you.

The post Announcing the tvOS Apprentice Week! appeared first on Ray Wenderlich.

tvOS Tutorial: Using TVML Templates

$
0
0
Note: This is an abbreviated chapter from the tvOS Apprentice, to give you a sneak peek of what’s inside the book, released as part of the tvOS Apprentice Week. We hope you enjoy!

tvml-templates-feature

In our beginning tvOS development tutorial, you created your first-ever TVML app. You saw how simple it can be to start developing for the Apple TV, and how easy it is to play video in a fully-featured player. However, the UI design of your app left a bit to be desired.

In this tutorial, you’ll learn how to use the plethora of TVML templates that Apple has provided to make some stunning interfaces. You’ll use these templates to build a comprehensive screen for RWDevCon 2015 videos, which will include a wide range of information about the video and display it in an appealing and recognizable manner.

In the process, you’ll learn how to use TVML templates to make great looking user interfaces, and you’ll learn how to use a templating engine to populate pages (rather than hard-coded data). Let’s get started!

Getting Started

The app you’ll build in this tutorial is called wenderTV; it lets you browse and watch raywenderlich.com video content on your Apple TV, so you can enjoy a vast quantity of knowledge – and bad jokes – from the comfort of your sofa.

I’ve prepared a starter project for you that includes the resources you’ll need for this tutorial. Download the starter project, unzip, and build and run from Xcode.

You’ll notice the screen is completely blank. This is because there aren’t any TVML documents in wenderTV yet. Before you can turn your attention to creating some TVML documents, you have a little housekeeping to do.

Note: Although you can use Xcode to write all the code you need for a TVML-based app, it can be quite a painful experience. Xcode is good for editing Swift or Objective-C, but has only rudimentary support for XML and JavaScript. It’s definitely worth using Xcode when you need to, and then switching to a more capable editor such as Sublime Text, Atom, Visual Studio Code or MacVim to work with TVML documents and JavaScript files.

Loading Scripts

In the previous tutorial, you learned how to split your JavaScript code across several files. The project for wenderTV already has a starter file to help you load app resources (ResourceLoader.js), so you need to import this into the Javascript file you load in application(_:didFinishLaunchingWithOptions:) (main.js).

Remember that TVJS provides the evaluateScripts() function which takes an array of URLs of JavaScript files and a callback. The function reads each URL in turn, attempts to parse it and adds any contained functions and object definitions to the context’s global object. Finally, it invokes the supplied callback with a boolean denoting success or failure.

The AppDelegate contains code that provides the JavaScript application with a list of URLs to the required JavaScript files as part of the launch options object. Open main.js and add the following code to the App.onLaunch() function:

// 1:
evaluateScripts(options.initialJSDependencies,
  function(success){
    if (success) {
      // 2:
      resourceLoader =
        new ResourceLoaderJS(NativeResourceLoader.create());
      var initialDoc = loadInitialDocument(resourceLoader);
      navigationDocument.pushDocument(initialDoc);
    } else {
      // 3:
      var alert = _createAlert("Evaluate Scripts Error",
        "Error attempting to evaluate the external JS files.");
      navigationDocument.presentModal(alert);
 
      throw ("Playback Example: unable to evaluate scripts.");
    }
  });

Taking this new function body step-by-step:

  1. The options object is prepared in Swift and then passed to the JavaScript app in the app delegate, while the initialJSDependencies property is an array of URLs for the different JavaScript files that need to be loaded as the app starts. evaluateScript() performs this action and then invokes the callback indicating whether it was successful.
  2. If the JavaScript sources evaluated successfully, create a ResourceLoaderJS object (from the helper file provived), before using it to load the initial document and then pushing this TVML document onto the navigation stack. loadInitialDocument() is currently a stub method you’ll populate in a bit.
  3. If the JavaScript files failed to load, there is nothing more that the app can do. Therefore it uses _createAlert(), defined at the bottom of main.js, to build and present an alert document and then throw an error.

Add the following to loadInitialDocument():

return resourceLoader.getDocument("video.tvml");

This uses the resource loader helper to get the TVML file from the app’s resource bundle and return it as a DOM object.

Next up, you’ll need to create the file your app is trying to load: video.tvml.

Head into Xcode, and right-click on the layouts group in the project navigator. Select New File…:

01_layouts_group

Navigate to tvOS\Other\Empty and hit Next. Name the file video.tvml and ensure that the wenderTV target is checked:

02_video_tvml

If you get a prompt that says video.tvml already exists, choose Replace.

Open the new file in either your favorite XML editor (or Xcode, if you insist) and add the following lines:

<?xml version="1.0" encoding="UTF-8" ?>
<document>
  <productTemplate>
  </productTemplate>
</document>

This defines a simple TVML document using a new type of template: productTemplate.

Build and run the app to see how things look so far:

03_bar_01

Hm. The screen is still blank. Although you’ve created the file and provided the template, you haven’t provided any content. You’ll fix that shortly, but first we should review a bit of background on on TVML templates.

TVML Templates

Remember that a TVML document is just an XML (eXtentible Markup Language) document with a specific schema defined by Apple. If you’ve used HTML in the past, XML will look familiar. HTML isn’t actually XML (despite some failed efforts with XHTML), but the syntax and structure is fairly similar.

Since TVML documents are XML they should start with the following line:

<?xml version="1.0" encoding="UTF-8" ?>

This is known as the XML prologue; it notes this file is an XML document and which character encoding it uses.

The TVML document has a root <document> element, which is a single element at the top level of the document and the parent (or ancestor) of all other elements. The <document> element has a single direct descendant, which can be one of 18 possible template tags.

A template tag specifies the top-level layout tvOS should use to render the document on screen. In addition to specifying the appearance on-screen, template tags also convey some semantic information about the content they contain. Templates might look similar, but have entirely different purposes.

TVML templates can be divided into the following categories:

  • Informational: Shows a small amount of information to the user, and optionally requests input from the user. It’s not designed for browsable content. Includes alertTemplate and loadingTemplate.
  • Data Entry: The user experience of entering data on TVs is pretty horrendous, and Apple TV is no different. However, there are a few templates for requesting data from the user, including searchTemplate and ratingTemplate.
  • Single Item: Displays information or content about a single product or item, such as a film or episode in a TV series. Includes productTemplate, oneupTemplate, compilationTemplate and showcaseTemplate.
  • Collections: Displays a collection of products, such as a TV series, a genre of films or tracks on an album. Includes stackTemplate, listTemplate and productBundle.
  • Other: Includes menuBarTemplate, which hosts a set of other templates, and divTemplate, which is a completely clean slate upon which you draw.

This tutorial will cover a few of the templates, and then you should have enough of an understanding to use any templates you’d like in your apps.

Note: The Apple reference is a great resource for getting the low-down on the different templates, their capabilities and layouts: apple.co/1PJuOAV.

The Product Template

The first document you’ll create uses <productTemplate>, which is designed to display all information relating to a specific product — in this case, a video.

Open video.tvml and add the following code between the <productTemplate> tags:

<banner>
  <infoList>
    <info>
      <header>
        <title>Presenter</title>
      </header>
      <text>Ray Wenderlich</text>
    </info>
    <info>
      <header>
        <title>Tags</title>
      </header>
      <text>development</text>
      <text>teams</text>
      <text>business</text>
    </info>
  </infoList>
</banner>

This code snippet introduces a lot of new element types. Taking them one-by-one:

  • <banner>: Displays content across the top of a page.
  • <infoList>: Displays a list of <info> elements, arranged in a vertical list.
  • <info>: A container for the content to appear as an item in an <infoList> or an <infoTable>.
  • <header>: Serves as a description of the content of the section in which it resides.
  • <title>: Contains the text of a short title.
  • <text>: Displays text.

Build and run the app to see what your new TVML looks like:

04_bar_02

You can almost make out the new entries down the left-hand side, but the current background color makes it difficult to see the white text.

Update the opening tag of <productTemplate> to match the following:

<productTemplate theme="light">

The theme attribute can either be dark or light and can be used on many TVML templates. It controls the visual effect applied to the background and the colors used in the foreground fonts.

Build and run again; you’ll see the content clearly:

05_bar_03

This page represents a video, but it currently lacks a title. Time to change that.

Add the following inside the <banner> tags, just after the </infoList> closing tag:

<stack>
  <title>Teamwork</title>
  <row>
    <text>17m 54s</text>
    <text>Inspiration</text>
    <text>2015</text>
    <badge src="resource://nr" />
    <badge src="resource://cc" />
    <badge src="resource://hd" />
  </row>
</stack>

This section introduces more TVML elements:

  • <stack>: Stacks lay out their content vertically down the screen in a manner similar to <infoList>. There’s a wider range of tags that can be in a Stack.
  • <row>: A row is like a stack, but with a horizontal orientation instead of vertical.
  • <badge>: Displays a small inline image. The URL is provided by the src attribute.

Notice that the URL of the two badge images begin with resource://. This is a special URL scheme that points to images that exist within tvOS itself. These images include common action icons, such as “play”, rating images for different countries and video information such as HD.

Note: For a full list of the resource images available within tvOS, check out Apple’s documentation at apple.co/1T930o9.

Build and run again to see how the page is shaping up:

06_bar_04

It’s starting to look good, but there’s still a long way to go. Before continuing with the template coding, you first need to consider the separation of data and view.

Data Injection

As your video document currently stands, all the data is hard-coded. To show information about a different video, you’d have to create a whole new page. If you wanted to reformat the video page once you’ve created all the pages, you’d have to go back through and edit every single one of them.

A much better approach is to use a templating engine, where you build the video page as a template and specify where the data should be injected. At runtime, the template engine takes the page template along with the data and generates the TVML page for tvOS to display.

Note: The word “template” is now being used for two different purposes: TVML templates are the layouts provided by tvOS that render your documents on the screen, whereas a templating engine uses template documents combined with data to generate complete TVML documents. Don’t worry too much about the distinction; it’ll be much more clear once you’ve used them both.

Mustache.js is a popular simple templating engine for JavaScript. You might recognize the templating syntax which is based around curly-braces:

{{property-name}}

The Mustache.js library is already part of wenderTV, but you need to build the mechanisms to use it. This presents you with several tasks to accomplish:

  • The data is stored as JSON files in the app bundle. The JavaScript app needs the ability to request them.
  • When a document is loaded, it now requires data, and this should be combined with the document string using Mustache.js.
  • Images that are present in the app bundle need their complete URL substituted.
  • The video document should be updated to turn it into a templated document.

You’ll address each of these in order.

Reading JSON from the app bundle

Open ResourceLoader.js and add the following method to ResourceLoaderJS:

getJSON(name) {
  var jsonString = this.nativeResourceLoader
    .loadBundleResource(name);
  var json = JSON.parse(jsonString);
  return json;
}

This function uses the native resource loader to pull the JSON file from the app bundle before parsing it into a JavaScript object.

Note: It would be relatively simple to replace this functionality with a method that calls a remote server for data instead of finding static data inside the app bundle. The rest of this templating approach would continue to work as it stands.

Injecting data into the document string

Now that you can obtain the data for a given page, you need to combine it with the document template itself. Update getDocument() in ResourceLoaderJS to match the following:

getDocument(name, data) {
  data = data || {};
  var docString = this.nativeResourceLoader
    .loadBundleResource(name);
  var rendered = Mustache.render(docString, data);
  return this.domParser.parseFromString(rendered,
    "application/xml");
}

Here you’ve added an additional data argument to the method, and used the render method on Mustache to convert the template and data to a completed document. As before, you use a DOMParser to convert the document string to a DOM object.

Resolving image URLs

For simplicity’s sake, your sample data stores images as the names of files in the app bundle, which need to be converted to URLs before you can display them. The utility functions to do this are already in the resource loader, so you just need to call them. You’ll do this at the same time as you update the initial document loading to use the templating engine.

Open main.js and update loadInitialDocument() to match the following:

function loadInitialDocument(resourceLoader) {
  var data = resourceLoader.getJSON("teamwork.json");
  data["images"] = resourceLoader
    .convertNamesToURLs(data["images"]);
  data = resourceLoader
    .recursivelyConvertFieldsToURLs(data, "image");
  data["sharedImages"] = _sharedImageResources(resourceLoader);
  return resourceLoader.getDocument("video.tvml", data);
}

First, you load the data using the new getJSON() method. Then you use the utility functions to perform the image name-to-URL conversion. These convert three different image name sources:

  • Each value in the images object on the data array.
  • Every value associated with a key of image anywhere within the JSON data structure.
  • A set of shared images that are useful for all documents in wenderTV.

That takes care of the plumbing underneath; you’re ready to use this powerful new functionality.

Using the Mustache.js templates

Open teamwork.json and take a look at the data you’ll use to populate the video page. There’s quite a lot of data, but it’s a standard JSON object and fairly easy to understand. You should spot some fields such as title, presenter and duration that you’ve already hard-coded into video.tvml. You’re now going to swap these out.

Open video.tvml and find the title tag that contains Ray Wenderlich. Replace the name with {{presenter}}, so that the first <info> section now looks like this:

<info>
  <header>
    <title>Presenter</title>
  </header>
  <text>{{presenter}}</text>
</info>

The syntax for Mustache.js is really simple; it will replace {{presenter}} with the value of presenter in the data object supplied to it.

Now that you’ve got the hang of that, you can replace the following content with the respective template tags:

  • Teamwork{{title}}
  • 17m 54s{{duration}}
  • Inspiration{{category}}
  • 2015{{year}}
  • "resource://nr""resource://{{rating}}

Build and run; you shouldn’t see any difference, which is exactly what you want. The page is now data-driven, and even better, you didn’t break anything. Bonus! :]

There are still some parts of the template you haven’t touched: closed-captions, HD and tags. These use some slightly more advanced parts of the Mustache.js templating engine.

Template sections

Remove the three <text> tags in the Tags section and add the following in their place:

{{#tags}}
  <text>{{.}}</text>
{{/tags}}

This new syntax defines a template section. Look at teamwork.json and you’ll see that tags is an array of strings. The Mustache.js syntax here loops through the array, with {{.}} rendering the content of the current index.

Finally, you need to handle the two boolean badges. Replace the cc and hd badges with the following:

{{#closed-captions}}
  <badge src="resource://cc" />
{{/closed-captions}}
{{#hd}}
  <badge src="resource://hd" />
{{/hd}}

Once again you’re using sections, but this time they’re structured like an if-statement. If the specified property exists and has a true value, then render this section; otherwise, ignore it.

Build and run again; check out your newly templated video page.

To confirm that the data injection is actually working, open main.js and change the data file loaded in loadInitialDocument() from teamwork.json to identity.json. Build and run again to see the data change:

07_bar_05

You can now see details of Vicki’s talk on identity — sweet!

Filling out the TVML Template

The video page is still looking a little barren. It’s time to double-down on adding some content.

Open video.tvml and add the following inside the <stack>, just below the existing <row>:

<description allowsZooming="true"
  moreLabel="more">{{description}}</description>
<text>{{language}}</text>
<row>
  <buttonLockup type="play">
    <badge src="resource://button-play" />
    <title>Play</title>
  </buttonLockup>
  <buttonLockup type="buy">
    <text>$9.99</text>
    <title>Buy</title>
  </buttonLockup>
</row>

Once again, this introduces some new TVML elements:

  • <description>: Displays a larger amount of text that’s used to describe content. If the text is too long for the display area then a label will be displayed with a title defined by the moreLabel attribute.
  • <buttonLockup>: A lockup is a class of element that joins its children together as a single element. A button lockup can contain text and a badge and will appear as a button.

Remember that these elements are all contained within a <stack>, so they’ll appear on top of each other.

Before checking your work, you need to add one more element to the top banner. Add the following line immediately after the </stack> closing tag:

<heroImg src="{{images.hero}}" />

A heroImg element is a large image that defines the content of this document. It appears inside the <banner> and tvOS uses it to define the blurred page background.

Build and run to see the completed top banner:

08_bar_06

It’s starting to look really cool! Now that you’ve provided a hero image for tvOS to use when it generates the background, you can investigate the effects of the theme attribute.

Find the opening <productTemplate> tag and change the theme attribute from light to dark. Build and run again to see the difference:

09_bar_07

The visual effect on the background has changed along with the foreground font colors.

Adding Shelves

The remainder of the productTemplate is made up of “shelves”. A shelf is a horizontal section of the page with content elements scrolling on and off the screen.

Add the following below the closing </banner> tag, towards the bottom of video.tvml:

<shelf>
  <header>
    <title>You might also like</title>
  </header>
  <section>
    {{#recommendations}}
      <lockup>
        <img src="{{image}}" width="402" height="226" />
        <title>{{title}}</title>
      </lockup>
    {{/recommendations}}
  </section>
</shelf>

This shelf displays a set of other videos that the user might enjoy as defined in the recommendations property of the data model. Each recommendation has an image and a title, each of which you use in the code above.

There are two other elements introduced in this code segment:

  • <section>: Defines a set of related content that should all be laid out together. A section can contain a title and multiple lockup elements.
  • <lockup>: You saw <buttonLockup> before; lockup is a more general type of lockup. It provides layout for an image, a title, a badge and a description.

Now add another shelf below the one you just created:

<shelf>
  <header>
    <title>Production</title>
  </header>
  <section>
    {{#people}}
      <monogramLockup>
        <monogram firstName="{{firstname}}"
          lastName="{{lastname}}"/>
        <title>{{firstname}} {{lastname}}</title>
        <subtitle>{{role}}</subtitle>
      </monogramLockup>
    {{/people}}
   </section>
</shelf>

This shelf displays a list of people associated with the production; it’s stored in the people property in the data model.

This introduces the <monogramLockup> and <monogram> elements, which let you represent a person when an avatar isn’t available. Like the other lockup elements, a monogram lockup simply locks its content together.

A monogram has firstName and lastName attributes, from which it generates a monogram (initials) and places it in a large circle.

Build and run to see how your shelves are taking shape (use the Apple TV remote to scroll):

10_bar_08

Take a look at the description for the Identity talk. Notice that the more label has appeared, because there is too much text to display in the available space. Navigate to the label and you’ll see you can focus on the description and press select to trigger an action. This action doesn’t currently do anything, but wouldn’t it be nice if it would display the full text?

Time for another TVML template.

Handling Text Overflow

The descriptive alert template provides space for an extended area of text and buttons. It sounds ideal for this purpose. You’ll use this template and a spot of JavaScript to wire it up.

In the Xcode project right-click on the layouts group and select New File…. Choose tvOS\Other\Empty and name the file expandedDetailText.tvml. Choose Replace if prompted. Open the new file and add the following:

<?xml version="1.0" encoding="UTF-8" ?>
<document>
  <descriptiveAlertTemplate>
    <title>{{title}}</title>
    <description>{{text}}</description>
    <button action="dismiss">
      <text>Dismiss</text>
    </button>
  </descriptiveAlertTemplate>
</document>

This should be quite straighforward to understand. There’s the usual XML prologue, the <descriptiveAlertTemplate> tag and some elements you’ve used before. Notice that the button tag has an action attribute; this is a user-defined attribute that’s not part of the TVML specification.

You can define any attributes that you want (provided they don’t clash with existing attributes) and then read them from your JavaScript app. You’ll write some code to handle this dismiss action in just a bit.

Open video.tvml and find the <description> tag. Update the element to match the following:

<description allowsZooming="true"
  moreLabel="more"
  action="showOverflow"
  title="{{title}}">{{description}}</description>

You’ve added two new attributes: action and title. You’ll use both of these in the event handler to create the expanded detail text document.

Event handling

Now that the document templates are ready to go you can turn your attention to the JavaScript that wires everything up.

Open main.js and add the following function:

function _handleEvent(event) {
  // 1:
  var sender = event.target;
  var action = sender.getAttribute("action");
  // 2:
  switch(action) {
    case "showOverflow":
      // 3:
      var data = {
        text: sender.textContent,
        title: sender.getAttribute("title")
      };
      // 4:
      var expandedText = resourceLoader
        .getDocument("expandedDetailText.tvml", data);
      expandedText.addEventListener("select", _handleEvent);
      navigationDocument.presentModal(expandedText);
      break;
    case "dismiss":
      // 5:
      navigationDocument.dismissModal();
      break;
  }
}

Taking this piece-by-piece:

  1. The target property of the event argument represents the DOM object that fired the event. The getAttribute() method of a DOM object will return the value for the specified attribute. Here you’re using it to find the value of the action attribute you added above.
  2. Switch on the action attribute to invoke the appropriate code.
  3. If the action is showOverflow, then you have a description field with too much content. Construct an object with the data required by the expanded detail text document. Once again you’re using getAttribute() along with textContent, which returns the content of the tag itself.
  4. Load the expandedDetailText.tvml document in the usual way, add an event listener and use the presentModal() method on NavigationDocument to display the new document on top of the current document.
  5. If the action is set to dismiss then use the dismissModal() method on NavigationDocument to perform the dismissal.

Now that you’ve created this event handler, you need to wire it up to the initial document. Add the following line to App.onLaunch, just after you call loadInitialDocument():

initialDoc.addEventListener("select", _handleEvent);

As you saw in the previous tutorial, this registers the _handleEvent function as a listener for the select event, and uses event-bubbling to handle all events triggered within the document.

Build and run the app, navigate down to the over-full description and hit the select button. You’ll see your new expanded detail text page:

11_bar_09

You can use the dismiss button to return to the video screen.

Now that is one swell-looking – and extensible – interface.

Where To Go From Here?

Here is the example code from this TVML tutorial.

TVTThumb

In this tutorial, you accomplished a lot – you created a great-looking TVML app using TVML templates, and integrated a Javascript templating engine to separate the UI from the data.

If you’d like to learn more, you should check out our book the tvOS Apprentice. The chapter in the book goes into further detail and show you how to make the TVML to allow users to rate videos from 1-5 stars. You also might enjoy the other 27 chapters and 500+ pages in the book! :]

In the meantime, if you have any questions or comments about using TVML templates, please join the forum discussion below!

The post tvOS Tutorial: Using TVML Templates appeared first on Ray Wenderlich.

On-Demand Resources in tvOS Tutorial

$
0
0
Note: This is an abbreviated chapter from the tvOS Apprentice, to give you a sneak peek of what’s inside the book, released as part of the tvOS Apprentice Week. We hope you enjoy!

on-demand-feature

When I got my first iPod Touch several years ago, I excitedly opened the App Store and started downloading the first ten games from the Top Charts. It wasn’t long before I came to the sad realization that my iPod storage wasn’t infinite: the alert telling me I didn’t have enough storage to download all the apps quashed my initial enthusiasm.

iOS 9 and tvOS introduced On-Demand Resources (ODR) as a way to manage the size of your apps. The idea behind ODR is that your app only retrieves the resources it’s needed up to that point. When the app needs additional resources, it downloads them on-demand.

There are two main reasons to take advantage of ODR in your apps:

  1. Faster initial download: The faster the user can download the app, the faster they can start falling in love with it.
  2. Smaller app size: When storage is limited, the biggest apps are usually the first ones that users will delete. You want to keep your app’s storage footprint well under the radar!
Note: tvOS apps have a maximum initial download size of 200 MB, and any additional resources must be available through ODR. Not only is ODR recommended, it is a requirement for many apps!

Time to size things up – and dive right into adding ODR to an existing app.

Getting Started

First download these two files:

Put both files in a folder somewhere (I called mine ODR) and unzip both files. The resulting directory structure should look like this:

DirStructure

Open RWHomeTheater in Xcode and build and run. You’ll see the following:

RWHomeTheater

In this app, you can pick from a collection of remarkable, entertaining videos that range from a cow eating grass to water boiling. Currently the app has 14 videos, which take up nearly 200 MB by themselves — looks like a case for some ODR!

After you play around with the app a bit, back in Xcode open Main.storyboard and zoom in on the top-right of the RW Home Theater Scene. Notice there’s a UIProgressView that’s hidden by default; later on, you’ll use this to show the user the status of their downloads.

Note: The starter project for this tutorial comes from our book, the tvOS Apprentice. If you’d like to learn how to make this project and learn about video playback in tvOS along the way, check out the book!

NSBundleResourceRequest and Tags

To work with ODR, you’ll need a basic understanding of NSBundle and how it handles files.

NSBundle represents a group of files on the device. In the case of ODR, these files will include resources such as videos, images, sounds, 3D models, and shaders; the main exception is that you can’t include Swift, Objective-C or C++ source code in ODR.

Most of the time, you’ll use NSBundle.mainBundle() as your main bundle. By default, all the resources downloaded in your app are included in the main bundle. Think of the main bundle as a big box that holds all of your app’s “stuff”.

diagram_1

However, when you use ODR, the resources you download aren’t in the main bundle; instead, they’re in a separate bundle that contains all the resources of a given tag. The OS only downloads a tag’s resources when needed.

When you request a tag, the OS downloads all resources for that tag and stores it in an NSBundle. Then, instead of using the main bundle to find the resource, you simply look inside this alternative bundle.

diagram_2

You request a tag using an instance of NSBundleResourceRequest. This resource request takes strings that represent the tags as parameters and lets you know when your resources are available. Once the resource has been loaded, you can use the resource request’s bundle property to access the files in the bundle.

Once you’re done with an NSBundleResourceRequest, you can call endAccessingResources() on the request and let it become deallocated. This lets the system know you’re done with the resources and that it can delete them if necessary.

Now that you understand the foundations of ODR, you can get started on the coding!

Adding Tags

In the project navigator, expand the videos group and the Animals subgroup under the Resources folder and select cows_eating_grass.mp4:

CowsEatingGrassLocation

Show the File Inspector using the Utilities menu. Notice the section named On Demand Resource Tags:

ShowingResourceTagField

To add a tag to a file, you simply type the name of the tag in this text box and press Enter.

In order to make things easier to discern from code, you’ll add the video’s name as its tag. Be careful – if you don’t name the tag exactly the same as the video, then ODR won’t work properly.

For cows_eating_grass.mp4, add “cows_eating_grass” to the On Demand Resource Tags text field and press Enter:

ResourceTagFieldNameAdded

Select the project in the project navigator, select the target, and go into the Resource Tags tab; you’ll see the Resource Tags menu. The app has a tag named “cows_eating_grass” with a single associated file:

ResourceTagTable

Next up – adding the tags for every single video file. Oh, come on – it’ll be fun!

If you don’t want to go through the laborious task of adding these tags – good news! You can simply download an alternative version of the starter project that has the tags pre-filled for you.

Once you’ve added all of the tags – whichever way you chose to do it – the Resource Tags menu should look like the following:

ResourceMenuAfterFilesAdded

Build and run your app; when the app loads, open the debug navigator in Xcode and select Disk. This will show you the status of all tags in the app:

DiskDebug

The app won’t work at the moment since you haven’t downloaded the files to the Apple TV yet: every tag says “Not Downloaded”. Time to fix that problem!

Resource utility class

In order to keep all your ODR code organized, you’ll create a class to manage your on-demand resources. Select File\New\File\Swift File, and name it ResourceManager.

Add the following class declaration to the file:

class ResourceManager {
  static let sharedManager = ResourceManager()
}

This code creates a new class named ResourceManager and creates a class variable for a shared instance.

Now, add the following code to ResourceManager:

// 1
func requestVideoWithTag(tag: String,
  onSuccess: () -> Void,
  onFailure: (NSError) -> Void) -> NSBundleResourceRequest {
 
    // 2
    let videoRequest = NSBundleResourceRequest(tags: [tag])
    videoRequest.loadingPriority
      = NSBundleResourceRequestLoadingPriorityUrgent
 
    // 3
    videoRequest.beginAccessingResourcesWithCompletionHandler {
      error in
      NSOperationQueue.mainQueue().addOperationWithBlock {
        if let error = error {
          onFailure(error)
        } else {
          onSuccess()
        }
      }
    }      
    // 4
    return videoRequest
}

There’s a lot of new stuff going on here, so taking it piece by piece:

  1. Create a method to easily request a new video in your app. This method takes the tag name as a parameter, as well as two closures – one to call if the download succeeds, and one to call if the download fails.
  2. Instantiate a new NSBundleResourceRequest with the given tag. By setting loadingPriority of the request to NSBundleResourceRequestLoadingPriorityUrgent, the system knows that the user is waiting for the content to load and that it should download it as soon as possible.
  3. To start loading the resources, call beginAccessingResourcesWithCompletionHandler. This completion handler is called on a background thread, so you add an operation to the main queue to respond to the download’s result. If there is an error, the onFailure closure is called; otherwise, onSuccess is called.
  4. Return the bundle request so that the requestor can access the bundle’s contents after the download finishes.

Before you can add this to the project, you need to make a small change to the video struct. Open Video.swift and find the current declaration of videoURL:

var videoURL: NSURL {
  return NSBundle.mainBundle().URLForResource(videoName,
    withExtension: "mp4")!
}

Replace that declaration with the following:

var videoURL: NSURL!

Also, change the implementation of videoFromDictionary to match the following:

static func videoFromDictionary(dictionary: [String: String]) -> Video {
  let previewImageName = dictionary["previewImageName"]!
  let title = dictionary["videoTitle"]!
  let videoName = dictionary["videoName"]!
 
  return Video(previewImageName: previewImageName,
    title: title, videoName: videoName, videoURL: nil)
}

In the original code, videoURL pointed to a location in the main bundle for the file. However, since you’re now using ODR, the resource is now in a different bundle. You’ll set the video’s URL once the video is loaded – and once you know where the video is located.

Requesting tags on selection

Open VideoListViewController.swift and add the following property to VideoListViewController:

var currentVideoResourceRequest: NSBundleResourceRequest?

This property will store the NSBundleResourceRequest for the most recently requested video.

Next, you’ll need to request this video when the user selects one of the videos in the collection view.

Find didSelectVideoAtIndexPath(_:) and replace its implementation with the following:

func didSelectVideoAtIndexPath(indexPath: NSIndexPath) {
  // 1
  currentVideoResourceRequest?.progress.cancel()
  // 2
  guard var video = collectionViewDataSource
    .videoForIndexPath(indexPath),
    let videoCategory = collectionViewDataSource
      .videoCategoryForIndexPath(indexPath) else {
        return
  }
  // 3
  currentVideoResourceRequest = ResourceManager.sharedManager
    .requestVideoWithTag(video.videoName,
      onSuccess: { [weak self] in
 
      },
      onFailure: { [weak self] error in
 
      }
  )
}

The code breaks down as follows:

  1. If there’s a video request in progress, cancel that resource request and let the new video request take priority.
  2. This is the same code from didSelectVideoAtIndexPath(_:); it’s how you find the video and category of the selected cell.
  3. Set currentVideoResourceRequest equal to a new NSBundleResourceRequest created by ResourceManager. The resource tag passed as a parameter is the name of the video – this is why you followed that strict naming scheme earlier.

The next step is to handle the failure case. Add the following method to the VideoListViewController extension:

func handleDownloadingError(error: NSError) {
  switch error.code{
  case NSBundleOnDemandResourceOutOfSpaceError:
    let message = "You don't have enough storage left to download this resource."
    let alert = UIAlertController(title: "Not Enough Space",
      message: message,
      preferredStyle: .Alert)
    alert.addAction(UIAlertAction(title: "OK",
      style: .Cancel, handler: nil))
    presentViewController(alert, animated: true,
      completion: nil)
  case NSBundleOnDemandResourceExceededMaximumSizeError:
    assert(false, "The bundle resource was too large.")
  case NSBundleOnDemandResourceInvalidTagError:
    assert(false, "The requested tag(s) (\(currentVideoResourceRequest?.tags ?? [""])) does not exist.")
  default:
    assert(false, error.description)
  }
}

handleDownloadingError(_:) handles all the possible errors from a resource request.

The main three error cases occur when either the device is out of storage, the resource is too large, or you’ve requested an invalid tag. If the device is out of storage, you alert the user of the problem. You’ll need to catch the other two issues before you deploy your app; at that point, it’s too late to make changes. So that they don’t go unnoticed in your testing phase (you are testing, right?), you crash the app with an error message.

The default assertion catches any other errors that could occur, such as network loss.

Now, call your new method in the onFailure(_:) closure:

self?.handleDownloadingError(error)

In the onSuccess closure, add the following code to handle the successful download:

guard let currentVideoResourceRequest =
  self?.currentVideoResourceRequest else { return }
video.videoURL = currentVideoResourceRequest.bundle
  .URLForResource(video.videoName, withExtension: "mp4")
let viewController = PlayVideoViewController
  .instanceWithVideo(video, videoCategory: videoCategory)
self?.navigationController?.pushViewController(viewController,
  animated: true)

Here you set the URL of the selected video to the downloaded resource within the requested bundle. Then, you present a new instance of PlayVideoViewController with the video as a parameter.

Run your app; select video to play and you’ll notice there’s a bit of a delay before the video starts. This is because the video is being downloaded from the server – or in this case, from your computer.

To check that your app is using the on-demand bundle, open the debug navigator and select Disk; the Status column of your chosen video will now show “In Use”.

If you press Menu on your remote, you’ll notice the tag still shows as “In Use”. That’s not quite right, is it? The resource should change to “Downloaded” since you’re no longer using the resource. You’ll fix this in the next section.

Purging Content

Responsible management of your resources includes releasing them when you’re done. This takes two steps:

  1. Call endAccessingResources() on the NSBundleResourceRequest.
  2. Let the resource request deallocate.

The best time to let ODR know you no longer need the video is once the user’s finished watching the video. This happens when you dismiss PlayVideoViewController and VideoListViewController reappears on-screen.

Add the following method to VideoListViewController.swift:

override func viewWillAppear(animated: Bool) {
  super.viewWillAppear(animated)
 
  currentVideoResourceRequest?.endAccessingResources()
  currentVideoResourceRequest = nil
}

This code first checks that VideoListViewController reappears once you’ve dismissed a different view controller from the navigation stack. It then calls endAccessingResources() on the resource request and sets the property to nil, which lets the resource request deallocate.

Build and run your app; watch the Resource Tags menu as you play a video, then press Menu to go back. The Resource Tags menu now shows the requested resource as “Downloaded”. Perfect! You won’t delete the resource until the system needs the space. As long as the device has room, the resources will remain in storage.

Progress Reporting

At present, the user has no way to see the progress of the download. Is the video almost completely downloaded? Or is it not downloading at all?

In order to indicate the progress of the download, you’ll use a progress bar to observe the progress of the NSBundleResourceRequest.

Back in VideoListViewController.swift, add the following line to the beginning of didSelectVideoAtIndexPath(_:):

progressView.hidden = false

At the beginning of both the onSuccess and onFailure closures, add the following line – which does the exact opposite as the previous line:

self?.progressView.hidden = true

This code shows the progress bar when the download begins, and hides it when the download ends.

Key-Value Observing

To connect the progress bar with the NSBundleResourceRequest, you need to use Key-Value Observing.

Open ResourceManager.swift and add the following to the top of the file, above the class declaration:

let progressObservingContext = UnsafeMutablePointer<Void>()

Next, you need to change requestVideoWithTag to accept the progress observer as a parameter.

Replace the declaration of requestVideoWithTag with the following:

func requestVideoWithTag(tag: String,
  progressObserver: NSObject?,
  onSuccess: () -> Void,
  onFailure: (NSError) -> Void) -> NSBundleResourceRequest {

This method now has a new progressObserver parameter that will make it easier to use KVO with your custom view controller and progress bar.

Within this method, add the following code before the return statement:

if let progressObserver = progressObserver {
  videoRequest.progress.addObserver(progressObserver,
    forKeyPath: "fractionCompleted",
    options: [.New, .Initial],
    context: progressObservingContext)
}

Here, you add the argument as an observer to the request’s progress.

Just like you added the observer before the resource was loaded, you’ll need to remove the observer once it’s loaded. Add the code below to the beginning of the NSOperationQueue.mainQueue().addOperationWithBlock block:

if let progressObserver = progressObserver {
  videoRequest.progress.removeObserver(progressObserver,
    forKeyPath: "fractionCompleted")
}

Xcode will respond with an error in VideoListViewController; this is because you changed the method signature of requestVideoWithTag.

Open VideoListViewController.swift and change the line with the error to the following:

currentVideoResourceRequest = ResourceManager.sharedManager
  .requestVideoWithTag(video.videoName, progressObserver: self,
  onSuccess: { [weak self] in
    ...
  },
  onFailure: { [weak self] error in
    ...
  }
)

The only change here is that you added the progressObserver parameter and passed self as the observer.

In order to respond to changes as the download progresses, you’ll need to implement observeValueForKeyPath in the view controller – your observer.

Add the following method to VideoListViewController:

override func observeValueForKeyPath(keyPath: String?,
  ofObject object: AnyObject?, change: [String : AnyObject]?,
  context: UnsafeMutablePointer<Void>) {
 
    if context == progressObservingContext
      && keyPath == "fractionCompleted"{
 
        NSOperationQueue.mainQueue().addOperationWithBlock {
          self.progressView.progress
            = Float((object as! NSProgress).fractionCompleted)
        }
    }
}

When the value of the download’s progress changes, you reflect this change in the progress bar on the main thread.

Build and run your app; select a video to watch and you’ll see the progress bar at the top-right corner of the screen. Once the progress bar has filled, it will disappear and the video will play:

ProgressBarScreenshot

w00t – videos on demand!

Where To Go From Here?

Here is the example code from this On-Demand Resources in tvOS tutorial.

TVTThumb

You now have all the details you need to bring On-Demand Resources into your tvOS apps. ODR lets you create large, resource-intensive apps that still fit within the 200MB initial download requirement.

If you want to learn more, you should check out our book the tvOS Apprentice. The chapter in the book goes into further detail about anticipating the users actions and the different types of resource tags that are available. You also might enjoy the other 27 chapters and 500+ pages in the book! :]

In the meantime, if you have any questions or comments about using TVML templates, please join the forum discussion below!

The post On-Demand Resources in tvOS Tutorial appeared first on Ray Wenderlich.

tvOS Top Shelf Tutorial: Static and Interactive

$
0
0
Note: This is an abbreviated chapter from the tvOS Apprentice, to give you a sneak peek of what’s inside the book, released as part of the tvOS Apprentice Week. We hope you enjoy!

top-shelf-feature

A true Apple TV enthusiast can be identified by the plethora of installed apps on their Apple TV. But among the numerous apps installed to your user’s Apple TV are five apps that hold an elevated standing. The user explicitly chooses these apps to reside in a place of privilege on their Apple TV screen: the top shelf.

This space gives you, the developer, an opportunity to showcase what your app’s all about. Think of the top shelf as a billboard to show exceptional content from your app. When one of the top shelf apps in the top row gains focus, the entire top half of your user’s TV populates with one or more banners to charm your users.

A good top shelf is visually appetizing, while a great top shelf is visually appetizing and functionally appealing. In this tutorial, you’ll learn how to add both static and interactive content into the top shelf, and give your future tvOS blockbuster app a decisive edge over other apps in the marketplace!

Getting Started

First download the starter project for this tutorial. Build and run your app, and you’ll see the following:

newsApp

Imagine it’s the year 2340, and that the Apple TV and Swift are so popular they’re still in use despite over 300 years of technological advancement. The project in this chapter is a news app that showcases the latest news in the galaxy. Like other news apps, there are a variety of topics sectioned into their own tabs. At launch, the app shows the user the top news from every category, and subsequent tabs showcase all the news attributed with the topic:

martianFeaturedNews

Press Command+Shift+H to bring your tvOS simulator back to the home page. You’ll begin by putting your news app into your top row of apps to expose it in the top shelf.

Bring the focus to your news app, press and hold Enter until the app icon starts wiggling, then bring your cursor up to the highest row of apps and press Enter. Your app should now reveal its top shelf when you bring it in focus. Right now, it will appear as a blank canvas:

blankCanvas

That wouldn’t win over any galactic news fans, in any universe! A good logo and good branding go a long way; in the case of the Apple TV, that extends beyond the app icon. In fact, Apple enforces this: you must provide a top shelf image before you can export your app to production servers. A top shelf image is a 1920 x 720 widescreen graphic you’ll need to add to the assets catalog.

Adding a Static Image

Later in this tutorial, you’ll learn how to create an interactive top shelf, but it’s baby steps for now. You’ll start by implementing the minimum acceptable top shelf: a high quality 1920 x 720 png image relevant to your app.

Download the resources for this tutorial and locate StaticTopShelf.png. Drag and drop this image into your Assets.xcassets folder in the Top Shelf Image compartment:

settingStaticTopShelf

Ensure your app is still within the top row of apps, then build and run your project. Press Command+Shift+H to return to the home screen, then navigate to your app and you should see your top shelf image in all its glory:

staticTopShelf

Right now, your top shelf consists of a single banner that acts as a symbol for your app. While that’s great and all, the usability of the top shelf extends far beyond being a “second app icon”. In the following section, you’ll learn how to develop for the interactive top shelf.

An Interactive Top Shelf

There are currently two different interactive top shelf layouts: the sectioned top shelf, and the inset top shelf.

Sectioned Top Shelf

The sectioned top shelf is, as its name implies, a top shelf where the content is divided into sections. If you’ve worked with table and collection views before, this layout should look familiar to you:

sectionedTopShelfExample

The sectioned top shelf is perfect for displaying information that makes sense when it’s grouped together; this makes it a great choice to showcase the top news articles for each news topic. In general, if the purpose of your app is to feed information to the user as quickly as possible, the sectioned layout is a great choice.

Inset Top Shelf

The inset top shelf is great for displaying the overarching themes of your app, particularly if your app is a game. Each item is given the full width of the screen to showcase the features in store for your users:

insetTopShelf

Both layouts let the user scroll and browse through the your content – and they’re surprisingly easy to implement.

Setting Up The Interactive Top Shelf

The process of setting up an interactive top shelf is relatively straightforward. In technical terms, you’ll add a target – a TV Services Extension – and configure the ServiceProvider to use one of the two layouts.

On the top bar, select File/New/Target…:

newTarget

For the template, choose TV Services Extension located within tvOS/Application Extension and select Next:

tvServicesExtension

Name the extension TopShelf and select Finish:

namingExtension

At this point, you may be presented with the following dialog:

schemeDialog

Select Activate. This lets the simulator test your extension. With that bit of setup done, you’re ready to begin writing code. Hurrah!

TVTopShelfProvider

When you create the new TV Services Extension target, Xcode automatically generates the new target accompanied by a new file named ServiceProvider.swift. This file contains the ServiceProvider class, which is where you’ll define the interface for your interactive top shelf.

The topShelfStyle computed variable defines the type of top shelf you’d like to present to the user: either the sectioned layout, or the inset layout. In this chapter, you’ll use the sectioned layout.

Linking Up the Sectioned Layout

In ServiceProvider.swift, make sure the topShelfStyle variable is returning .Sectioned (it should be returning .Sectioned by default):

var topShelfStyle: TVTopShelfContentStyle {
  return .Sectioned
}

Modifying the return value for this computed variable lets the app define an inset or sectioned layout.

The topShelfItems computed variable, as the name implies, will define the UI elements in the top shelf for a given layout.

Modify the topShelfItem computed variable as follows:

var topShelfItems: [TVContentItem] {
  // 1
  let breakingNewsIdentifier = TVContentIdentifier(identifier:
    "Breaking News", container: nil)!
  let breakingNewsSection = TVContentItem(contentIdentifier:
    breakingNewsIdentifier)!
  breakingNewsSection.title = "Breaking News"
 
  // 2
  let martianRiotIdentifier = TVContentIdentifier(identifier:
    "Martians Riot", container: nil)!
  let martianRiotItem = TVContentItem(contentIdentifier:
    martianRiotIdentifier)!
 
  // 3
  breakingNewsSection.topShelfItems = [martianRiotItem]
 
  return [breakingNewsSection]
}

Here’s what you did above:

  1. First you defined a section where your “Breaking News” items will reside.
  2. Next you defined a single item for your section.
  3. Finally you set the topSelfItems property of the breakingNewsSection to an array that contains the item.

To test your top shelf, you can use the schema generated for you when you created the TV Services Extension. Beside the run/stop button on the top left corner of Xcode, select the TopShelf schema:

schemaSelection

Build and run your app; choose Top Shelf from the “Choose an app to run:” dialog and press Run:

chooseAnAppToRun

You should see a single cell with a section title above it:

sectionedTopShelfOneCell

Okay, that takes care of the section title. Now you’ll need an image to go along with it.

Drag sectionedMartians.png from this resources you downloaded earlier and drop it into your project in the Top Shelf group. Make sure Copy items if needed is checked, and the target is set to TopShelf:

dragAndDrop

With the asset safely in your project, change to ServiceProvider.swift.

Add the following code just below the line that initializes martianRiotItem:

martianRiotItem.imageURL = NSBundle.mainBundle().URLForResource(
  "sectionedMartians", withExtension: "png")

This tells TVContentItem to look inside your project files to find the image.

Build and run your app; you should see a nice image accompanying your top shelf item in the breaking news category:

martiansAreRioting

Look out, the Martians are rioting! :]

Adding More News Items

A comet in the Milky Way is misbehaving, and an Asteroid is traveling at the speed of light, breaking all laws of physics! While these two pieces of news are super-exciting, they don’t quite belong in the “Breaking News” category. You’ll create a new category to house these two pieces of news.

Drag and drop comet.png and asteroid.png from the resources you downloaded earlier to the Top Shelf group, making sure Copy items if needed is checked and the target set to TopShelf.

In the topShelfItems computed variable, add the following before the return statement:

// 1
let milkyWayNewsIdentifier = TVContentIdentifier(identifier:
  "Milky Way News", container: nil)!
let milkyWaySection = TVContentItem(contentIdentifier:
  milkyWayNewsIdentifier)!
milkyWaySection.title = "Milky Way"
 
// 2
let cometIdentifier = TVContentIdentifier(identifier:
  "An odd comet", container: nil)!
let cometItem = TVContentItem(contentIdentifier:
  cometIdentifier)!
cometItem.imageURL = NSBundle.mainBundle().URLForResource(
  "comet", withExtension: "png")
 
// 3
let asteroidIdentifier = TVContentIdentifier(identifier:
  "Asteroid Light Speed", container: nil)!
let asteroidItem = TVContentItem(contentIdentifier:
  asteroidIdentifier)!
asteroidItem.imageURL = NSBundle.mainBundle().URLForResource(
  "asteroid", withExtension: "png")
 
// 4
milkyWaySection.topShelfItems = [cometItem, asteroidItem]

Take some time to admire the beauty of what you’ve written:

  1. You create a new TVContentItem intended as a new section; hence you also give it a title.
  2. You then create cometItem with the intention of adding it to milkyWaySection.
  3. You also create asteroidItem to add to milkyWaySection as well.
  4. Finally, you made cometItem and asteroidItem part of the milkyWaySection by adding them to its topShelfItems property.

You’ve created a new section and placed two items inside. Now you need to add this section next to the “Breaking News” section.

Update the return statement to return both the breakingNewsSection and the milkyWaySection:

return [breakingNewsSection, milkyWaySection]

Build and run your app; select any top shelf item:

cometAndAsteroid

Hm – nothing happens! Well, the sections look good, but you haven’t yet provided the code to handle events. You’ll do that in the next section.

Adding User Interaction

You have a visually appealing top shelf, so your next step is to make it functional. A top-of-the-line top shelf provides shortcuts to the advertised content, so you’ll need to find a way for the app to recognize that a user has tapped on a given top shelf item. Unfortunately, you can’t use IBAction event handling here.

So what can you do? How does event handling work for the top shelf?

Event Handling

AppDelegate.swift will call application:openURL:options when a user selects anything in the top shelf – provided that the item has a non-nil displayURL or playURL. The top shelf can listen to two events on the remote: a press on the touch screen, and a press on the play button.

You’ll start by adding a new value to your app’s Info.plist file. Make sure you’ve opened the plist that’s part of your NewsApp target, not your TopShelf target. Right-click and select Add Row:

addPlistRow

Name the row URL types. As you’re typing, Xcode may help you out by offering you an autocomplete. Expand the row you’ve just added and you should see another row named Item 0. Expand that as well. Click the + button next to Item 0 to add another row within the Item 0 dictionary. Name it URL Schemes:

addButtonInPlist

Your new rows should look like this:

unfinishedURLSchemes

Set the value of Item 0 of URL Schemes to newsapp, and URL identifier to NewsApp URL. Your finalized plist entry should look like this:

finalizedPlist

Hooking up the AppDelegate

You haven’t provided TVContentItems with either of these properties yet – that’s your next job.

Adding the URLs

For your news app, you’ll only supply displayURL. Open ServiceProvider.swift and add the following private method to the bottom of the class:

private func urlForIdentifier(identifier: String) -> NSURL {
  let components = NSURLComponents()
  components.scheme = "newsapp"
  components.queryItems = [NSURLQueryItem(name: "identifier",
    value: identifier)]
 
  return components.URL!
}

You’ll use this private helper method to generate a URL for displayURL. Your top shelf has three items, so there are three corresponding displayURL properties you must fill in.

Inside the topShelfItems computed variable, find where you’ve declared martianRiotItem. Below that, add the following line:

    martianRiotItem.displayURL = urlForIdentifier("martianRiot")

Similarly, find cometItem and asteroidItem and add the following code below the points where you instantiate each of those objects:

    cometItem.displayURL = urlForIdentifier("comet")
    asteroidItem.displayURL = urlForIdentifier("asteroid")

Build and run your app; navigate to your app’s top shelf, select any item, and lo and behold, your app launches!

awwYeahMoney

Right now, your app launches to its initial view controller when any of the top shelf items are selected. What you really want is the items to act as a shortcut to their respective categories. It’s these shortcuts that provide a pleasurable – and convenient – user experience.

Differentiating Between Items

Open AppDelegate.swift and add the following:

func application(app: UIApplication, openURL url: NSURL,
  options: [String: AnyObject]) -> Bool {
    print(url)
    return true
}

This method will be called whenever your user selects a top shelf item with a displayURL, passed in as an argument in the method.

Before you can build and run, you’ll have to switch back to the NewsApp scheme:

selectNewsAppScheme

Build and run your app; once the app launches press Command+Shift+H to bring your tvOS simulator back to the home screen. Navigate to your top shelf and select the Martian Riot news item. You should see the following output in your console:

    newsapp:?identifier=martianRiot

Next, navigate back to your top shelf and select the Comet item. This time, your console should show the following:

    newsapp:?identifier=comet

Hey! Those are the identifiers you’ve added to the displayURL property earlier! w00t! Now you have a distinguishing feature you can rely on.

For this app, you’ll simply bring the user to the associated tab related to the theme of the content. You currently have four tabs in your app. You’ll define their indexes using a few variables.

Add the following variables to AppDelegate.swift, right below the var window: UIWindow? statement:

let newsTab = 0
let martianTab = 1
let earthTab = 2
let milkyWayTab = 3

Next, update application(_:openURL:options:) to the following:

func application(app: UIApplication, openURL url: NSURL,
  options: [String: AnyObject]) -> Bool {
    guard let initialViewController = window?.rootViewController
      as? UITabBarController else { return false }
 
    switch url.absoluteString {
    case "newsapp:?identifier=martianRiot":
      initialViewController.selectedIndex = martianTab
    case "newsapp:?identifier=comet",
    "newsapp:?identifier=asteroid":
      initialViewController.selectedIndex = milkyWayTab
    default:
      return false
    }
    return true
}

Here, you’ve set out the code to handle the select event for each of the three items. For the Martian Riot news item, you’ve directed the user to the news tab for Mars. For the Comet and Asteroid news items, you’ve directed the user to the Milky Way tab.

Build and run your app; select any of the news category items to ensure you’re launched into the proper spot in your app. You’re ready to assume your spot as the biggest galactic news mogul this side of Saturn! :]

awwYeahMoney

Where To Go From Here?

Here is the example code from this tvOS top shelf tutorial.

TVTThumb

You’ve covered a lot of ground in this tutorial. You’ve learned all about the top shelf and the two layouts associated with it.

If you’d like to learn more, you should check out our book the tvOS Apprentice. The book teaches you everything you need to know to develop great apps for the Apple TV – whether you’re a seasoned iOS pro, or a web developer looking to leverage your skills to a new platform.

In the meantime, if you have any questions or comments about working with the Top Shelf in tvOS, please join the forum discussion below!

The post tvOS Top Shelf Tutorial: Static and Interactive appeared first on Ray Wenderlich.


tvOS Apprentice Giveaway Winners – And Last Day for Discount!

$
0
0

tvt-giveaway-feature

Thank you for being a part of the tvOS Apprentice Week!

During the tvOS Apprentice week, we released three free tvOS tutorials, and the definitive book on tvOS development, the tvOS Apprentice. But now, it’s time to say goodbye.

But first, there’s two important pieces of news!

tvOS Apprentice Week Giveaway Winners

To celebrate the tvOS Apprentice Week, we had two giveaways: one for a free copy of the tvOS Apprentice, and one for a brand new Apple TV. All you had to do to enter was comment on the respective posts.

Across all posts, we had over 200 applicants, and we’ve selected some random winners from among them.

And now it’s time to announce the 5 lucky winners… drum roll please!

Book Winners

The 4 lucky book winners are: Jbammi, Njt2812, dan1eln1el5en, and chuck jay. Congratulations! :]

Each winner will receive a free PDF copy of the tvOS Apprentice (or a PDF of their choice if they already have a copy). I will be in touch with the winners directly via email.

Apple TV Winner

The 1 lucky Apple TV winner is: vleekxiong!

vleekxiong will receive a brand new Apple TV, if they live in the US. Otherwise, they will receive a free PDF of their choice. I will be in touch directly via email.

Last Day for Discount!

Finally I’d like to remind everyone that today is the last day for the current discounted price for the tvOS Apprentice.

Starting tomorrow, the book will be raised to its normal price ($10 more). So be sure to grab the discount while you still can!

Thanks to everyone who entered the tvOS Apprentice giveaway, bought the book, or simply read these posts. We really appreciate each and every one of you, and thank you for your support and encouragement – it is so amazing being a part of this community.

We wish you all the best with your tvOS adventures, and can’t wait to see your apps on the big screen! :]

The post tvOS Apprentice Giveaway Winners – And Last Day for Discount! appeared first on Ray Wenderlich.

Video Tutorial: Beginning iOS Animation Part 10: Troubleshooting Animations Gone Wrong

Video Tutorial: Beginning iOS Animation Part 11: Conclusion

iOS App Extensions: Series Introduction

WTF is… Nuke?

$
0
0
Note: This is the first of a new series of articles aimed to give you a quick overview of various interesting open source libraries that are out there. The name of this series is in honor of a YouTube gamer that we really like, TotalBiscuit. Enjoy! :]

NukeThumb

Downloading and caching images efficiently has long been a challenge for iOS developers.

Objective-C has lots of popular libraries to aid in this task, such as SDWebImage, AFNetworking, DFImageManager and more. It’s taken some time for comparable Swift libraries to show up, but one of the newest is Nuke!

Nuke is an open source Swift framework for loading, processing, caching, displaying, and preheating images. It is written by Alexander Grebenyuk, an experienced developer who also wrote DFImageManager.

In this article, I’ll give you a quick overview of installing Nuke and how to use it, and then outline the situations where you might find it useful in your apps. Let’s get started!

Getting Started

Installing Nuke is easy – it supports both CocoaPods and Carthage.

CocoaPods

If you use CocoaPods, simply add the following lines to your Podfile:

pod "Nuke"
pod "Nuke-Alamofire-Plugin" # optional
pod "Nuke-AnimatedImage-Plugin" # optional

Carthage

If you use Carthage, simply add the following lines to your Cartfile:

github "kean/Nuke"
github "kean/Nuke-Alamofire-Plugin" # optional

Currently, there is no Carthage support for the Nuke-AnimatedImage-Plugin.

What Nuke Does

Nuke helps you do 6 main things:

  1. Download Images
  2. Resize Images
  3. Cache Images
  4. Process Images
  5. Deserialize and Decode Images
  6. Preheat Images

Let’s look at each in turn.

1) Download Images

The primary goal of Nuke is to make downloading and using images in your app quick, easy, and efficient.

For example, the following snippet fetches an image for you:

Nuke.taskWithURL(url) { response in
    switch response {
    case let .Success(image, responseInfo):
        //do something with your image
    case let .Failure(error):
        //handle the error case
    }
}.resume()

Here, you simply pass in an instance of NSURL then call resume. Nuke will download your image in the background and call your response closure when it’s done.

response is an enum that describes the task’s outcome either as a success or a failure. responseInfo provides useful information to the caller, such as fastResponse, which tells you if the fetched image is from the network or the cache.

Note: Astute readers will notice a similarity between this and NSURLSessionTask. In Nuke’s case, you’re using ImageTask instead of NSURLSessionTask.

Although ImageTask doesn’t descend from NSURLSessionTask, ImageTask offers similar API methods such as resume, suspend, and cancel for managing your network calls.

2) Resize Images

So far, this is no different than what you can do with NSURLSession or other networking libraries. But you can also pass some image-specific parameters to your download task, by passing an ImageRequest instead of an NSURL, as in the example below:

var imageRequest = ImageRequest(URL: imageURL)
request.targetSize = CGSize(width: 250, height: 250)
request.contentMode = .AspectFit
 
Nuke.taskWithRequest(request) { response in
   // Handle the response
    switch response {
    case let .Success(image, responseInfo):
        let image = image
    case let .Failure(error):
        let error = error
    }
}.resume()

This lets you specify elements such as the target size to resize the image to, and how to do so via contentMode (AspectFill or AspectFit). Nuke will download and resize the image for you in the background.

Note: Resizing an image can be useful when you need to scale an image to fit a defined space in your view, such as a 100×100 avatar image view. It’s wasteful to pass images through to UIView that are considerably larger than what you need.

Couldn’t you just hand UIImageView a large image and let the resizing happen behind the scenes? You could do this, and UIImageView would internally resize the image depending on the the image view’s contentMode property. However, it’s better to resize the image yourself before handing it off to UIImageView so you can keep memory usage at a minimum. That’s where Nuke comes in handy.

3) Cache Images

If you use Nuke, the images you download will be cached automatically. To understand how this works, check out the following quote from Nuke’s caching mechanism guide:

“Many third-party libraries are trying to reinvent caching. Nuke doesn’t, it relies on HTTP cache as defined in HTTP specification and an excellent caching implementation provided by Foundation. If you are trying to implement your own HTTP caching methodology you are probably doing it wrong.”

Rather than reinventing caching, Nuke relies on two built-in caching mechanisms offered by Apple:

  • NSURLSession‘s caching mechanism via NSURLCache
  • NSCache

NSURLSession provides both disk and in-memory caching; it’s controlled primarily by the HTTP headers sent back in response to your request. NSCache is an in-memory cache that sits on top of the URL loading framework’s caching mechanism to make things even faster.

The added benefit of using NSURLCache is that it’s completely transparent to the user. After requesting an image, you can verify its existence in the cache by checking the default NSURLCache singleton like so:

let cachedResponse = NSURLCache.sharedURLCache().cachedResponseForRequest(imageRequest)

4) Process Images

Besides downloading and caching the image, ImageRequest also allows you define custom filters to apply to the fetched image. Yes, you could technically do this by yourself, but it’s still a nice touch.

The code below shows how easy it can be to add a blur effect to your retrieved image:

let blurringImageFilter : ImageProcessing = MyFilters.blurringFilter()
 
var imageRequest = ImageRequest(URL: imageURL)
imageRequest.processor = blurringImageFilter
 
Nuke.taskWithRequest(request) { response in
    switch response {
    // Handle the response
    case let .Success(image, responseInfo):
        let image = image
    case let .Failure(error):
        let error = error
    }
}.resume()

The key element in the code above is Nuke’s ImageProcessing protocol. It defines several methods you must comply with; the most important one is this:

func processImage(image: UIImage) -> UIImage?

You pass this method an instance of UIImage and it returns an UIImage optional. If the filter operation succeeds, you get a new image with the filter already applied. If Nuke can’t apply the filter for whatever reason, it returns nil. It’s quite straightforward!

5) Deserialize & Decode Images

Once you request an image from the network, there are two things that must happen before iOS can display it on the screen: image deserialization, and image decoding.

Image Deserialization

The first is image deserialization, which translates a binary blob to the image file.

UIImage can handle deserialization for you, but this potentially expensive operation usually happens on the main thread and can affect your UI. Nuke helps you maintain a buttery smooth UI by handling deserialization in the background. This occurs in Nuke’s ImageDecoder class, with the important bit as follows:

return UIImage(data: data, scale: UIScreen.mainScreen().scale)

Note: There isn’t anything in Apple’s official documentation stating init?(data data: NSData, scale scale: CGFloat) is thread-safe. Nevertheless, from an empirical point of view, and mostly agreed upon in the development community at large, init?(data data: NSData, scale scale: CGFloat) works outside the main thread.

Image Decoding

The step after deserialization is image decoding. An image always comes to you encoded in a particular image format, usually denoted by the file’s extension, such as .JPG or .PNG. Image decoding takes the encoded file and uses image standards to translate the file into a 2-D grid of colors to show on the screen.

The good news is that UIImage and UIImageView handle image decoding for you automatically. The bad news is that, like deserialization, decoding usually happens on the main thread, which again can degrade UI performance.

Nuke handles image decoding off the main thread as well. Nuke’s ImageDecompressor class internally forces early decompression into a Core Graphics context in the background. Very cool! :]

6) Preheat Images

The most exciting feature in Nuke is probably the ability to preheat images.

If you’re an expert at preheating food but don’t know how to preheat images, here’s what it means: you make the image request at some time well before you need to display the image, download it and store it in the application’s network cache.

Preheat

Later when you need to display the image, the response to your request will come back from the cache instead of the network, which is much faster and more reliable than making a network request and hoping it will succeed and download in enough time before your user notices the delay.

Imagine you have have a screen that displays an article with an image at the bottom; you know there’s a good chance the user will eventually scroll down to see the image. With Nuke, you can preheat the image as soon as the user opens the article; as soon as she scrolls down the image will load so quickly as to give the impression it was there all along.

Here’s how you preheat an image with Nuke:

let articleImagesRequests = article.imagesRequests() // get the article's images requests
Nuke.startPreheatingImages(articleImagesRequests)    // start the oven

Stopping the operation is just as easy:

Nuke.stopPreheatingImages(articleImagesRequests)

The great thing about this approach is that explicit image requests are of a higher priority than preheating requests. Grebenyuk wrote a comprehensive explanation of this feature in the Nuke repo’s wiki.

Preheating and UICollectionView

Nuke also extends its preheating functionality to work seamlessly with UICollectionViews by way of ImagePreheatingControllerForCollectionView and the ImagePreheatingControllerDelegate protocol, which defines a single method:

func preheatingController(controller: ImagePreheatingController,
    didUpdateWithAddedIndexPaths addedIndexPaths: [NSIndexPath],
    removedIndexPaths: [NSIndexPath])

This delegate method passes in two important index path arrays:

  • addedIndexPaths: The index paths to preheat.
  • removedIndexPaths: The index paths to remove from preheating.

How does ImagePreheatingControllerForCollectionView know which index paths to start and stop preheating? Basically, it observes the UICollectionView‘s UIScrollView contentOffSet and figures out which cells are coming in and out of the view port, taking into consideration the scrolling direction and the device orientation.

If you want to use this feature with UITableView, you can use ImagePreheatingControllerForCollectionView‘s superclass ImagePreheatingController. This class observes UIScrollView directly, which UITableView subclasses. However, a little bird told me that full support for UITableView is coming soon! :]

To see a small demo of preheating in action, check out the example in Nuke’s repository here and the PreheatingDemoViewController.swift class.

not_bad

When Should You Use Nuke?

You should always ask the following two questions before you adopt a third party library:

  • Is it being maintained?
  • Does it do what it’s supposed to do?

You can answer the first question by checking the frequency of commits and if open issues are being dealt with in a timely fashion. In this case, I think Grebenyuk is doing an excellent job on both fronts! You can check the commit history and the issues list of the repo to see for yourself.

The second question isn’t trivial to answer; determining whether it’s true or false depends on your project. The easiest way is to start using the library see if it does exactly what it says on the tin. You can do this using Instruments and see how it behaves in different scenarios. In this case, Allocations, Time Profiler and Leaks would be your best bets. Once you’ve checked that it behaves as expected in your particular use case, you’re good to go.

In my day to day experience with Nuke, it’s worked as promised; as a standard image fetcher and cacher, Nuke does a flawless job.

Alternatives to Nuke

There are other interesting libraries out there that are comparable to Nuke; one of them is Kingfisher. Although Kingfisher is a perfectly valid option, the preheating feature offered by Nuke was something I really needed, so having it work out of the box made it an easy decision to use Nuke.

On the other hand, if you’re already using something like Alamofire, you could probably just use its companion library AlamofireImage for image handling. It’s difficult to justify the use of Nuke in this case, just for the sake of preheated images.

Note: Nuke does come with an optional plugin that provides Alamofire integration. This makes Alamofire.Manager comply with Nuke’s ImageDataLoading protocol; this means you can use either Nuke’s default image loader, or the Alamofire loader if you choose.

Why is this useful? If you’re already using Alamofire in your project and decide to leverage Nuke as well, this plugin passes the network tasks of image loading to Alamofire, while preserving Nuke’s caching, processing and decoding abilities. It’s the best of both worlds!

If you need more powerful image processing than Nuke can provide, you could make a combo with Alamofire and Path’s popular FastImageCache to solve your particular problem.

Where to Go From Here?

All in all, Nuke is a great library. Its advanced features and constant updates make it an easy choice for many projects. For more information check out the official Nuke Github repository.

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

Note: Please let us know if you’d like to see more of these “WTF is…” articles in the future – this one is an experiment to see if you guys and gals like it.

The post WTF is… Nuke? appeared first on Ray Wenderlich.

Video Tutorial: iOS App Extensions Part 1: Photo Extensions: Getting Started

Freelance Software Development: Is It For You?

$
0
0

Are you tired of a normal 9-5 office development job?

You might be tempted to throw in the towel and become a freelance software developer. For many, freelancing conjures the allure of working when you want to, where you want to, on what you want to, and all for more than you might make in a regular job.

But what would you really be getting yourself into? Would the advantages of going on your own outweigh the many disadvantages that come with it?

In this article, you’ll get some straight talk from developers with freelancing experience, all of them Tutorial Team members or readers like yourself. We’ll share what we consider the benefits and drawbacks of freelance software development, to help you decide if it’s for you.

Freelancer or Consultant?

Although in some cases, the terms freelancer and consultant are used interchangeably, in this article we are making a distinction:

  • Consulting: long-term, contract-based work for a single company that is usually, but not always, performed on-site.
  • Freelancing: short-to-medium-term work for one or more companies that is usually, but not necessarily, performed from home or some other location of the freelancer’s choosing, such as a coworking space—or the beach!

While consulting can be a great way to earn a living as a developer, this article focuses exclusively on freelancing.

The Benefits of Freelancing

Freelance_01_time_with_family

I asked our pool of freelancers what they considered the main benefits of freelancing, and they mentioned the following:

  • Earning more money: Personally, I earn about two to three times more than I would as an employee here in Poland, and I am pretty sure proportions would be not much different in a few other European countries. But such difference can be lower in other countries, where salaries are much higher, such as the UK and US.

    However it’s not always about absolute numbers. For example, Richard Hancock noticed that he earns as much as some of his friends, but whereas they spend on average 40-60 hours per week, he works 20-30 hours. Jean-Philippe Cyr says that the real profitability lies on the fact the freelancer has more time (no commuting, no office hours, etc.), and he’s the real owner and master of it.

  • Choosing projects: For Andy Donnelly and Ignacio Nieto, one big benefit is the the ability to choose what projects to work on.

    When Ignacio finishes a project, he usually find himself with several other offers to choose from. He considers himself lucky for being able then to choose the project he likes more, and/or the one having the higher challenge factor.

  • Choosing what technologies to learn and work with: Since you can choose your projects, you’re also free to switch to different technologies at any time. Kuba Suder was a Ruby on Rails developer, but he wanted to learn Mac and iOS development, so he took a freelancing job to develop a Bitcoin wallet app for the Mac and learned, while getting paid. As a freelancer you can also have more time for learning new things, because you don’t necessarily have to work all week.

    I took advantage of that ability several times: when I wanted to learn, say JEE (but also C#, Python, and more). I simply started searching for projects requiring that technology, and strategically chose the next project to work on based on what I wanted to learn next.

  • Choosing clients: For Spencer Muller Diniz, another big benefit is having no formal attachment to an employer. Jake Gundersen agrees: “I can fire a client if I feel like the deal isn’t working for me.” This can be important because there’s a huge difference between clients that are easy to work with, and clients from hell.

    Can you spot the parallel? As an employee, you can be fired. As a freelancer, you can fire a client. :]

  • Choosing schedule: To Pierre Rochon, one big benefit is having lots of flexibility in his schedule, such that he can escape from “the office” at virtually any time. Combined with being able to work from home, this means he gets to spend more time with his family.

    This can also be helpful because you can decide to take off one day or work on a weekend if you’d like – it doesn’t matter as long as you get your work done.

  • Choose work environment: Finally, Edward Gilmore relishes his freedom from the cubicle, which he considers a soul-sucking, creative wasteland. He says, “If you want to inspire someone to become an entrepreneur, put him in a cube.” :]

    I usually work in a dedicated office room in my house, but I often spend a few hours in the living room-not to mention that I can virtually work anywhere (coffee house, train, airport, beach, you name it), provided that I have my macbook and an internet connection.

    You can also travel to exciting locations while you work! Andy Donnelly, primarily based in the UK, managed to work on projects while in Australia and the Netherlands. Digital nomads take that to the next level, by combining freelancing with nomadic lifestyle-a great way to explore the world, while still being able to work.

  • Be your own boss: Paul Jones likes the fact that he gets to be his own boss—though I have to warn you, as a freelancer, your spouse can become your boss! :]

The Drawbacks of Freelancing

Freelance_04_diving_in

Although the benefits listed earlier may sound pretty sweet, freelancing comes with some significant drawbacks as well. Before jumping into a major life change, you should carefully consider these items as well.

I asked our pool of freelancers about the drawbacks they’ve encountered working independently, and here are their answers:

  • Don’t have a secure salary: To Ignacio Nieto, the #1 drawback is not having a fixed, secure salary as one would normally enjoy in a conventional job. In Spain, where he lives, if you are a freelancer, you have no sick leave at all. The social security will not pay you like it would if you had a regular job. If you have a bad year, for whatever reason, you are on your own.

    And I presume that’s a recurring problem, regardless of the country where you happen to live.

  • Don’t have paid vacation: Additionally, Pawel Krakowiak regrets the loss of paid vacation. You might be tempted to avoid or take shorter vacations, because you know you’ll lose money twice: the amount spent for the vacation itself, and the missing income for the non-working break.

  • Find the next project: According to to Gary Riches and Malhar Ambekar, the looming need to find the next project is a recurrent problem and source of stress. Depending on the size of the projects you take, that can be as frequent as every two to three months.

    My biggest concern as a freelancer has been that I might not have a job tomorrow. Projects can (and, believe me, will) stop or freeze without any prior notice, for a variety of reasons.

  • Don’t always get to pick projects: Since jobs aren’t guaranteed, Richard Hancock notes that as a freelancer you sometimes have to take on jobs you may not want, just to pay the bills.

    At the beginning of my freelancing career, I took a project which was underpaid – but I couldn’t afford to wait longer for a better project, so I decided to take it.

    A few years later, a friend of mine proposed me a project on a technology that I didn’t (and still don’t) like much, but the client was great, the pay rate was good, and I needed a new project asap. So, despite the lack of interest in the technology, I took the project. In case you are wondering, it was MS Access. :]

  • Don’t have co-workers: Pawel Krakowiak also experiences loneliness, a feeling that is common among those who work from home. To many, the major thing employment offers that is practically absent in freelancing is daily exposure to colleagues.

    Kuba Suder misses all of the routine interactions with his coworkers, such as chats in the office kitchen, asking and being asked for help, going out for lunch and attending office parties.

  • High pressure: Christopher Hawkins warns about the constant pressure he experiences as a freelancer. This can come from many different sources, including project deadlines, mistakes in cost estimates for fixed-price projects, bugs that are hard to track down and late payments.

  • Have to wear many hats: Robin Hayward reminds us that since you’re running your own business as a freelancer, you have to deal with things that in employment are handled by someone else, and at which you might not excel: accounting, invoicing, expenses, taxes and so forth.

  • Hard to disconnect from work: Another disadvantage I’ve experienced is that when one freelances from home, there’s a real risk of never disconnecting from work.

    Julio Carrettoni experienced that feeling on his first national holiday as a freelancer, which fell on a Monday. His fiancé insisted in taking a mini vacation, but in the end he didn’t fully enjoy it because distracted by the money he was losing by not working on a Monday.

    Kuba Suder‘s advice is to learn how to manage your own time. Without discipline or a learned routine, you can easily end up working too much for your well-being, or working too little and getting into trouble.

  • Risk of not being paid: So far nobody, including me, has mentioned a problem that everybody fears: not being paid. You do your work, you put all your pride and dedication into it, you let your skills do their magic, and when all is said and done—you don’t get paid.

    It does happen. And it can happen more easily when the involved parties are in different corners of the world. It’s sad that, in my case, the only two times I didn’t get paid, it was when working for people I trust and consider friends.

    Note that I am not recommending to not do business with friends. I just want to warn that it can happen when you least expect it.

Wearing Many Hats

Freelance_03_many_hats

Another thing to consider beyond benefits and drawbacks is that being a successful freelancer requires you to wear many hats. This isn’t for everyone – some people find they don’t like freelancing because they prefer to focus just on programming, and not all the other stuff like sales or working with clients.

Here are some roles you should be prepared to play as a freelancer:

  • Salesman: You’re going to be selling a product, and that product is you.
  • Requirement analyst: This means being able to translate vague business ideas you receive from clients into developer-friendly requirements for yourself.
  • Software architect: Your clients may depend on you to design software architectures, and choose things like hardware, software, technologies and languages.
  • Technical writer: Your clients may expect you to be able to provide good technical documentation of your work.
  • System administrator: You should have a minimum of proficiency in administering the hardware and the operating system on which you’ll work and for which you’ll provide solutions.
  • Business owner: As a freelancer you are effectively running a 1-person business, so you’ll need to arrange some legal work (such as setting up your business and writing contracts), accounting work (like invoicing, bookkeeping, and yearly taxes), HR work (like arranging private health insurance), and other business work (like setting up a company web page and Twitter account). We recommend you hire a lawyer and accountant and don’t try to do this all on your own – it will be the best in the long term.

The fact that freelancing requires you to were many hats can be either a benefit or a drawback – it depends on what you personally like to do!

Where to Go From Here?

Let’s be real: Freelancing isn’t for everyone. Now that you’ve heard from some freelancers about the benefits and drawbacks they’ve experienced, try answering these questions. This isn’t a test; there is no score to calculate. Just answer and draw your own conclusions:

  • Am I willing to take on additional stress?
  • Can I afford to have a period of time with no income?
  • Am I willing to have an irregular income?
  • Am I willing to work irregular hours?
  • Am I willing to work more hours than I would in a regular job?
  • Can I spend most of my working time alone?
  • Can I work with little or no supervision or structure?
  • Am I willing to always be in “job search” mode?
  • Am I willing to take on or delegate the extra responsibilities of self-employment, such as accounting and marketing?
  • Am I good at solving problems and fixing bugs?
  • Am I good at finding pointers to what I need to know to get things done?
  • Is there a particularly cool/unique job opportunity that I’d be missing out on for this?

Here are some final pieces of advice for those considering freelancing:

  • Try a demo first. If you already have a regular job and you don’t want to jump ship yet, or you’re not sure whether freelancing is for you, take on a project in your spare time and see how it goes.
  • Talk to other freelancers. If you have any friends who freelance, ask them about their experiences. Otherwise, attend local meetups to connect with freelancers. Or do that online (slack communities, forums, etc.)
  • Do your “homework”. Consider the implications of working from home – there are some pros and cons of that as well. You might find my article on staying motivated as a work-from-home developer helpful.

Best of luck with your decision! If you end up deciding freelancing is for you, check out my next article on how to become a software developer freelancer (available on 02/25).

If you have any questions, comments or suggestions, please join the discussion below. We’d love to hear from those of you who have made this decision already, or who are looking for help on making it!

Note: Special thanks to our pool of freelancers for the invaluable input they shared with us: raywenderlich.com Tutorial Team members Jake Gundersen and Ryan Poolos, and raywenderlich.com readers Gary Riches, Andy Donnelly, Christopher Hawkins, Spencer Muller Diniz, Matthew Cave, Pierre Rochon, Jean-Philippe Cyr, Kuba Suder, Robin Hayward, Chris Cornelis, Julio Carrettoni, Paul Jones, Malhar Ambekar, Ignacio Nieto, Richard Hancock, Amit Ranjan, Edward Gilmore and Pawel Krakowiak.

The post Freelance Software Development: Is It For You? appeared first on Ray Wenderlich.


Video Tutorial: iOS App Extensions Part 2: Photo Extensions: Saving Data

Swift Evolution, and fastlane

$
0
0
fastlane

Learn how to make sense of the Swift Evolution mailing list in this episode!

Join Mic, Jake, and Greg as they chat about Swift evolution, before moving onto talk about fastlane, Mic’s favorite new developer tool!

[Subscribe in iTunes] [RSS Feed]

Our Sponsor

This episode was brought to you by the incredibly kind folks over at Hired.

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, our loyal audience, 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: hired.com/ray

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 Swift Evolution, and fastlane appeared first on Ray Wenderlich.

How To Become a Freelance Software Developer

$
0
0

02-feature-how-to-become-freelancer

Welcome back to our 3-part freelance software developer series!

In the first part of the series, we outlined some benefits and drawbacks of becoming a freelance software developer so you could decide if it was for you.

In this second part of the series, we’ll explain how to become a freelance software developer.

In the third and final part of the series, we’ll share some tips and tricks we’ve learned being successful freelance software developers over the years.

Let’s get started!

How to Begin Freelancing

If you think freelancing is for you, there are two basic ways to begin freelancing:

  • Jump straight away into your new adventure;
  • Make a plan to become, or progressively turn into, a freelancer.

The first approach might launch you forward with a burst of momentum, but it can be risky, unless you already have the resources and contacts to start and you know what you’re doing.

The second approach is safer, and doesn’t usually require a sudden and drastic life change. In some cases, one becomes a freelancer without planning to; it happens as a result of doing more and more part-time work during spare time.

How we got started

Freelance_04_diving_in

Want to see some examples? Here’s how some of us got started:

  • Matthew Cave had a client approach him unexpectedly with a long-term contract, so he went for it. Slowly over time, it became a partnership, and later a company. But it wasn’t planned that way, it started with nothing more than Matthew being tired of his current job, and an opportunity that presented itself.
  • Pierre Rochon was less lucky. He had a full time job at the R&D division of a medical company, but he lost it three weeks before his twins were born. He spent a few weeks learning iOS development and then started working on his first project a few months later, for a real estate broker wanting an app to display his listings and allow buyers to contact him directly from within the app.
  • Kuba Suder was planning to become a freelancer, but could never seem to get around to it. He worked for a small company in Krakow, doing Ruby/Rails development, but he wanted to become a Mac and iOS developer, and start freelancing as well. Then one day, he was introduced to someone who was looking for developers, for a new project. He decided to quit his previous job and take advantage of the opportunity.
  • Ignacio Nieto was in a really well paid job, as solid and stable as one could get in Spain. His salary was great, but he just hated it. Working in a grey office, day after day, with the same faces, in un-creative work nobody cared about, the traffic jams, it was sucking his life. So he decided to take the leap, quit his job and started to work in creative projects, make better use of his time and to take control of his own life. And he never regrets his decision.
  • Julio Carrettoni had a day job when he started freelancing. He finally quit his job and decided to become a full time freelancer when he realized that he was making the same amount of money, without all the hassle of being an employee, attend mandatory and useless meetings not related to his projects, being constantly interrupted with tasks and deliverables not related to his work, etc. He just become aware that he wasn’t very productive at his office and the salary wasn’t good either.
  • Paul Jones instead reached an age where he had to choose whether to stay technical or become a manager, in order to earn more. He didn’t enjoy the managerial career path, but he noted that freelancers he worked with did the more interesting work.
  • Pawel Krakowiak was looking for a new job when a friend sent him a link to freelancing platform called RentACoder (now Freelancer). It looked interesting, so he gave it a try, even though he was still looking for a full-time job. After a couple of months, Pawel decided to try freelancing full time. Today he thinks it was the best decision he’s ever made.
  • Personally, I started that way myself in 2003, doing small projects on RentACoder during my spare time while maintaining a regular job. When I left the job at the end of that year, I started looking for other regular jobs, and in the meantime, I dedicated all of my time to freelancing. I worked on small fixed priced projects, and progressively moved to larger projects, until I realized I could turn that into a full time opportunity.

    Four months later, I made my freelancing career official by opening my sole proprietorship company. And 11 years later, here I am. :] One more thing: being a freelancer made moving from Italy to Poland just a trip by car, with zero hassles regarding finding a job etc.

Finding Projects

Freelance_05_finding_projects

Whether you decide to take an immediate plunge or build up slowly, one of the first things you need to do is find some projects to work on. Here’s the strategies we’ve found most effective in finding new projects, in no particular order:

  • Word of mouth: Among our pool, this was the most common source of new projects. As Matthew Cave says, “there’s no greater marketing than a happy client.” A good reputation is essential here, and I’ll talk more about that soon.
  • Twitter: This is similar to word of mouth. Let your followers know you are looking for new opportunities, and gently ask to retweet. Your tweet could be read by hundreds or thousands of people.
  • Networking at conferences and meetups: Another variation of word of mouth, you can meet other developers, potential clients, and more generally expand your network. It can happen quite easily that, by just talking, you get connected to people seeking developers. It’s what you would do, isn’t it? While discussing, one tells that he’s looking for a new project, and you know your old employer needs a freelancer; wouldn’t you connect the two of them?
  • LinkedIn: Keep your resume up to date, join groups relevant to your experience and/or preference, write articles, connect with people you know. People will start finding you when they seek developers. Despite I haven’t done many of the things I’m suggesting, I still receive offers via LinkedIn, from time to time.
  • Recruitment Agencies: you know, they connect you to employers, in many cases for regular full times positions, but many specialize in, or include in their offer, contract jobs, which can be performed remotely.
  • Freelancing platforms, such as Upwork, Freelancer and Elance
  • DAAS (developer as a service) platforms, such as Toptal, Alt Tab, X-Team and Crew. DAAS platforms are my personal favorite way to find jobs. As I mentioned, I started my freelancing career through RentACoder (now Freelancer), and later oDesk (now Upwork), and today I use many of these platforms, although in the last year, I’ve mostly worked with Toptal.
  • Micro-consulting platforms, such as Airpair, Codementor, Hackhands. Micro-consulting services are a case apart: They consist of providing help in one-on-one sessions, using video calls, screen-sharing and code-sharing. You probably won’t make a regular income through micro-consulting alone, but helping others and/or fixing bugs is one of the best ways to learn new things, and, moreover, you get paid for doing that.

Choosing Projects

Freelance_02_chasing_clients

If you’re using an online freelancing platform, you usually have access to many projects. Don’t make the mistake of applying to all of them. It’s better to choose a small set of the most compelling—say, five projects—and spend the proper amount of time applying to each of them.

As to how to choose projects, besides the obvious considerations of platform, technologies and languages, there are a few other things to take into account:

  • Client reputation: A difficult client can make a big difference in the success of a project and in your ability to do your best work.
  • Client hire rate: If a client has posted 100 projects, but never hired a candidate, writing a proposal is probably a waste of time.
  • Number of applicants: The more applicants, the smaller the chance you’ll be hired. On the other hand, projects with a low number of applicants could require very specific knowledge, or have ridiculously low budgets or other problems.
  • Feasibility: It seems obvious, but you have to be sure the project actually makes sense. There’s a distinction to make, though: there are cases which are not technically feasible (an app that is capable of intercepting your thoughts and translate into written text-no technology allows that, yet :]), and cases where it’s not technically advisable (an iOS app built using the Android SDK-probably feasible, but not a good choice)

Not all freelancing platforms offer statistics at client and project level, to figure out whether a project is a good deal or not. Basing on my own experience, Upwork is the one providing the most comprehensive data, such as:

  • the average client rating
  • the list of his previous projects
  • the number of hires vs number of projects ratio
  • the number of applicants to a project, and the average rate or bid for all applicants

I can’t say if other platforms provide the same data, but I think they should at least provide alternative ways to let you figuring out the quality of a project and the client.

However, when evaluating a project, if your instincts tell you it could be a source of problems, listen to them and keep looking. Same if you feel you are going to have problems with the client.

Also, be flexible and open to learning new things. Don’t bypass a project just because it doesn’t use your favorite technology. Think of what’s best for the project, not for yourself. Likewise, don’t be too quick to dismiss a project because you lack a specific requirement; see “Learning and Experience” below.

Tips for Writing a Cover Letter

Freelance_07_cover_letter

When you apply for a project, you’ll usually need to write something to explain to the client why she should choose you.

Avoid copying and pasting from one cover letter to another. When you use the same text for every letter, you often wind up talking about yourself rather than about the project. Clients care more about what you can do to solve their specific problems, rather than about your prior experiences. What you can do is more important than what you’ve done.

How weird would it be if you brought your car to a mechanic, and she started telling you how good she is at fixing Ferraris, or that she once changed the tires on a Lamborghini? All you want to know is whether she can fix your car, and possibly how much it would cost.

Your skillset and experience are, of course, important, but they probably won’t grab the client’s attention as much as a direct explanation of what you can contribute to the specific project. Therefore, I recommend you put your credentials at the end of your application.

Be sure that you meet most of the requirements set by the customer, at the least. If you don’t meet a requirement, it’s wise to explain why you would do a good job anyway, or emphasize other contributions you can make to the project that the client may not have considered.

Learning and Your Experience

Freelance_06_self_learning

When applying for a job, you often need to talk to clients about your experience in various areas.

Note that it isn’t knowledge of a specific language or framework that determines whether you are an experienced software engineer. Some technologies are more complicated than others and require more time to learn and master. And in your continuing education as a developer, generally you aren’t learning how to do something, you’re learning how to do that something in a different way.

As a freelancer in software development, what’s arguably more important than experience is the ability to learn quickly and find pointers to the knowledge you need to get something done.

So, when applying for a project, you may omit (avoiding an outright lie) that you don’t have experience that fits a specific requirement—if you know that you can quickly fill the gap.

Do you remember when I suggested writing about the project first in your application, rather than about yourself? The point is to demonstrate your level of competence, which goes far beyond knowledge of this framework or that language.

If you do that well, the client reading your proposal will realize that you know what you’re talking about. Given that positive impression, she may not notice or care that, at the end of your application, you’ve neglected to mention whether you have the desired five years of Swift experience.

Disclaimer: I’m not encouraging you to deceive your clients. It’s about omitting what for you is a minor detail, a discrepancy that, thanks to your experience, you can resolve in a short amount of time without impacting the quality or speed of your work.

In my first medium-large project as a freelancer, I worked on implementing an SMS messaging platform, combined with a simple CMS. The requirements for the project included (among several things) usage of ASP.NET.

The client chose me because I made a thorough analysis of how I was going to implement that system, what tools, which technical challenges I expected, etc.

I omitted mentioning that I didn’t have any previous experience with ASP.NET and C#, and he never asked me about that – I just knew I wanted to learn them both, and I was self aware of my ability to complete the project without problems.

The client never realized of such omission, until, one day, I told him.

How Much Should I Charge?

Freelance_08_money_question

Once you find a project, the next thing you’ll need to figure out is how much you should charge.

In freelancing networks, rates and reputation are in fairly strict relationship. If you have no reputation, your clients probably won’t accept high rates. If you have a bad reputation, you probably won’t be hired at all, regardless of your rates. But as your reputation gets higher and higher, so does the ceiling for your rates. More about reputation in the next article of the series (part 3).

The other important factor in pricing is the country in which you live. I started with cheap rates, about $15/hour, and these days charge an average of $60-70/hour, depending on the project. However, I live in Poland, a country where life doesn’t cost a lot. My clients are mostly located in the US, but in the past I’ve also worked with UK and Italy.

If I were living in the UK, I would probably be earning £60/hour on average, which is about $90. In the US, I could charge as much as $120/hour—or even more, in the right location. I might guess that an iOS developer in San Francisco could ask for two or three times that rate!

Many clients look for the lowest price—but not all of them. There’s a good percentage who understand that in life, you get what you pay for. I’ve frequently written to a prospective client, “I know I’m not the cheapest developer, but…” It’s up to you to decide what comes after “but”.

Where To Go From Here?

Once you’ve got a job, you’ll want to make sure that you complete it successfully and impress your client – that will make it easier for you to land your next one.

For tips on that, check out our next part of the series, where we’ll share some freelance software development tips we’ve learned over the years (available on 02/26).

In the meantime, if you have any questions or advice on getting started as a freelance software developer, please join the forum discussion below!

Note: Special thanks to our pool of freelancers for the invaluable input they shared with us: raywenderlich.com Tutorial Team members Jake Gundersen and Ryan Poolos, and raywenderlich.com readers Gary Riches, Andy Donnelly, Christopher Hawkins, Spencer Muller Diniz, Matthew Cave, Pierre Rochon, Jean-Philippe Cyr, Kuba Suder, Robin Hayward, Chris Cornelis, Julio Carrettoni, Paul Jones, Malhar Ambekar, Ignacio Nieto, Richard Hancock, Amit Ranjan, Edward Gilmore and Pawel Krakowiak.

The post How To Become a Freelance Software Developer appeared first on Ray Wenderlich.

Video Tutorial: iOS App Extensions Part 3: Photo Extensions: Loading Data

Freelance Software Development Tips

$
0
0

03-feature-freelance-tips

Welcome back to our 3-part freelance software developer series!

In the first part of the series, we outlined some benefits and drawbacks of becoming a freelance software developer so you could decide if it was for you.

In this second part of the series, we explained how to become a freelance software developer.

In the this third and final part of the series, we’ll share some tips and tricks we’ve learned being successful freelance software developers over the years.

We have three sets of tips to share: communicating with your client, protecting your reputation, and solving common freelancing problems. Let’s get started!

Communicating With Your Clients

Freelance_09_communicating

The first set of tips we’d like to share involves communicating with your client. As a freelancer, this one of the most important things to get right! I find clients appreciate the following practices:

  • Be reliable: Be a reliable communicator, and answer emails and questions promptly. Also, avoid letting your clients wonder what you’ve been up to by sending regular status reports and/or when you achieve a goal.

  • Be polite: Be polite and professional, but just as importantly, be friendly. We are human, after all!

  • Be honest: Don’t lie, and always keep your word. Don’t make promises if you know you aren’t going to fulfil them. For example, don’t promise to implement a certain feature at the end of the project, if you already know that you will have troubles completing the project within the estimated deadlines, without that feature.

  • Don’t hide problems: Notify your clients of any problems as soon as possible, if the problem is serious and/or is going to emerge anyway, sooner or later.

  • Keep track of your time: Keep track of your time, and share it regularly with your clients, if you’re paid by the hour. If you work on a flat rate per project instead, it can help you figuring out the difference between estimation and actual effort.

  • Offer technical advice: If you notice clients making a wrong technical decision, be sure to point that out to them rather than letting them flounder. Debate the decision, but remember that, in the end, the client always has the final word.

  • Ask questions: Don’t be afraid to ask questions; this can save you and your clients much headache down the road. In case of doubt, always ask, and avoid solving ambigities basing on what you think the client wants. When a requirement is not properly defined, or is missing important details, ask her to provide more details, or give her your version, so she can immediately spot any mistake.

  • Deliver what your clients expect, rather than what you think they expect: In software development, there’s often an expectation gap—the difference between what clients expect and what they really get. Eliminating ambiguities and avoiding assumptions when something has gone unspecified are good ways to minimize that gap.

    For example, if a requirement states that a user shall be able to register by providing an email address and a password, and another instead says that a user shall be able to sign in by entering a username and password, you may notice that there’s an incongruence: registration requires an email (but not a username), whereas login expects a username. Should you use email during login, or should you also ask for a username during registration? Nobody but the client can answer to that question.

  • Solve problems: When there’s a problem, focus on solving it rather than on complaining about it.

Protecting Your Reputation

Freelance_10_protect_rep

The second set of tips we’d like to share is how to protect your reputation.

As a freelancer, this is your most important asset! As the saying goes, good things are written in sand, bad things in stone.

I know—it should be the opposite, but that’s the way of the world. If you have a bad reputation, it can be quite difficult to find projects, especially in online freelancing networks, where your reputation is public.

A few years ago, I hired a developer on Upwork to help me on a JEE project, even though he didn’t have specific experience with JEE. I offered to pay him to learn what he needed, and I assigned him a simple non-development task, technical writing.

About one week later, he changed his mind, saying that JEE was too complicated. Even worse, he disparaged the architectural choices my client and I had made, using very offensive words to do so. Nevertheless, he wanted me to pay him for all the time he spent on the project, blaming me for making him work on technologies he realized he didn’t want to deal with.

In the end, I paid him for just a fraction of the time he spent, and I left him long, negative feedback on Upwork, which I’m pretty sure disrupted his reputation on that platform. This was intentional. Don’t misunderstand me; I wasn’t retaliating. I simply felt I had to warn potential future clients what level of service and professionalism they should expect from that person.

The best way to protect and enhance your reputation is to make sure your clients are happy!

How to do that? A possible way is by temporarily turning yourself into a client. I hired developers a few times from platforms like Freelancer and Upwork, and thanks to that I experienced myself a few things, such as:

  • how to choose candidates among several applicants
  • what to expect while work is in progress
  • how frustrating it is when developers don’t send updates, and don’t respond to emails
  • how good it is when developers keep you in the loop, anticipating your questions and providing updates

Of course you don’t have to hire developers with the only purpose of behaving like a client. It can be very expensive. :]

But it can help if you, from time to time, think about how you would feel if you were in the client’s shoes. Especially when you are deliberately doing something to hide a problem, lying, etc. My favorite motto in life is: what you do not want done to yourself, do not do to others (Confucius quote).

Solving Common Freelancing Problems

The final set of tips we’d like to share is how to solve common freelancing problems.

Like any career, freelancing has its hazard zones. Here’s how to anticipate and prevent the most common problems.

Solve All Ambiguities Upfront

Above, I mentioned that a key way to keep your clients happy is to seek out and eliminate ambiguities in the client’s expectations. The beginning of a project can also be rife with ambiguities about rates, payments, payment terms and deadlines. Address these right away!

Avoid Signing an Unknown NDA

I’ve been asked several times to sign an NDA before being shown any details about the project. And I always refuse, at the risk of losing the project.

Why? The problem is, how can I sign a non-disclosure agreement, binding myself to confidentiality, non-competition and so forth, when I don’t know what it is I’d be protecting? What if I’ve already worked on projects that conflict with the NDA?

If this happens to you, ask if the client can give you an idea of what the project is about, without disclosing too much—just enough to let you assess whether you can responsibly sign an NDA.

What is the project about? A social dating app? Hmmm, ok I think I should tell you a couple of potentially similar projects I’ve worked on recently.

What is the project about? An app to calculate the trajectory and fuel consumption of a space rocket? Ok, I can sign the NDA, I’m pretty sure I haven’t worked on anything even remotely similar.

Read and Understand Contracts

It sounds obvious, but this is a topic to handle with extreme care. A contract is a legally binding agreement between you and your client, and since it’s usually the client requiring you to sign, the contract is mostly focused on protecting her and her project, rather than you.

It’s difficult to give advice, because no two contracts are the same, and most importantly, I’m not a lawyer. But here are a few general pointers:

  • Read the contract carefully.
  • Read it carefully again, and then again!
  • Don’t hesitate to contact an experienced attorney to review the contract for you, especially if anything is confusing, unclear or worrisome. True, it’s expensive to get legal advice, but the cost is a small fraction of what the advice could save you in the end.
  • Don’t hesitate to propose changes to the contract if you notice any errors, ambiguities or unfavorable terms.
  • If the client refuses to make the changes you require, step back and go look for other projects.

Prepare for a Sudden Lack of Work

It’s part of the nature of freelancing that a project may come to a stop with no prior notice. My countermeasure to protect myself is to work on at least two part-time projects at once, rather than on a single full-time project.

Each project acts as a backup for the other: If one is aborted, I still have work. After all, half an income is better than none at all.

When that happens, you might feel frustrated – at least, this sometimes happens to me. But I know it’s just a normal reaction, and when I feel ready I start looking for other challenges.

Sometimes I let one or two days pass, if I am still not motivated enough. I enjoy some more time with family, and maybe do something I usually couldn’t, because of too much work, such as some leisure time (which, recently, is playing drums :]), learning new things or reading books.

Lastly, I cannot tell if it’s just luck, coincidence, or something else. When a project ends, either suddenly or because of its “natural” expiration, I often receive unsolicited and unexpected offers. Last time, for example, the day after a project was suddenly frozen, I received a proposal via Stack Overflow, and a couple days later another one via LinkedIn. In both cases from new contacts, and not friends of friends.

I’d love to hear if the same happens to you.

However, unsolicited offers or not, I keep searching, applying to projects, asking my contacts, etc., until I have a new project to work on. Sometimes it takes a few days, sometimes even a couple months.

Where To Go From Here?

And that concludes our three part series on freelance software development! I hope it was useful whether you are considering becoming a freelancer, or an existing freelancer looking for tips and tricks.

If you want to learn more, here are some interesting readings:

I’ve been recommended Serial Winner, a book not specific to freelancers but a great read for anyone wanting to succeed at just about anything. However I haven’t read it, although I’ve added to my TO-READ list.

Another book I personally recommend, not related to freelancing at all, but inspiring in several ways when it’s about managing your finances, is The Richest Man in Babylon.

If you have any questions or tips you’d like to share, please join the forum discussion below!

The post Freelance Software Development Tips appeared first on Ray Wenderlich.

Viewing all 4370 articles
Browse latest View live


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