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

RWDevCon Student Scholarships: Deadline Extended

$
0
0

RWDevCon Scholarship

By popular request, we are extending the deadline for student scholarships to RWDevCon 2016 one more week – until Wednesday Jan 20.

In addition, we are making two other changes:

  • Age requirement dropped: Rather than requiring you to be 21 or younger, you can apply as long as you are a student in high school or college/university, regardless of your age.
  • Reduced requirements: Since there’s only one week left, rather than writing a full tutorial, all you need to do is send us an email about why you’re interested in programming and why you’d like to attend RWDevCon.

If you win a scholarship, you get a 100% free ticket to the conference – you just have to cover the cost of your travel/hotel arrangements.

So in short – if you’re a student and would like to learn a ton about iOS, tvOS, and Apple Watch development at RWDevCon 2016, send us an email today!

Hopefully this should make it easier for everyone to apply and open it up to a wider range of students. Remember, the conference is sold out so this is your last chance to get a ticket! :]

The post RWDevCon Student Scholarships: Deadline Extended appeared first on Ray Wenderlich.


Rock Solid Networking, and Custom Core Image Filters – Podcast S05 E05

$
0
0
networking

Interested in bullet-proofing your networking code, or building a Core Image filter? This episode has your back!

Join Mic, Jake, and Andrew as they discuss field-tested, rock solid networking, before swiftly changing direction with custom Core Image filters!

[Subscribe in iTunes] [RSS Feed]

Our Sponsor

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

WillowTree is a new breed mobile engagement partner focused on creating great software to improve users’ lives, and they’re hiring!

Much more than a mobile app development company, they work with clients such as GE, Johnson & Johnson, Pepsi and the NBA to create the best mobile experiences possible. WillowTree excel at bleeding-edge projects that allow them to push boundaries and challenge themselves to keep evolving.

How do they do it? They hire the smartest and most passionate people in the industry, and give them what they need to keep growing and learning. WillowTree have all the perks of other leading development shops, but what makes them unique is their “maker” culture, which gives great designers and developers the freedom to produce incredible results.

Visit willowtreeapps.com/careers to find out more!

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 Rock Solid Networking, and Custom Core Image Filters – Podcast S05 E05 appeared first on Ray Wenderlich.

NSURLSession Tutorial: Getting Started

$
0
0
Learn how to implement HTTP data requests and downloads with the NSURLSession API!

Learn how to make HTTP data requests and implement file downloads with NSURLSession!

Whether an app retrieves application data from a server, updates your social media status or downloads remote files to disk, it’s the HTTP network requests living at the heart of mobile applications that make the magic happen. To help you with the numerous requirements for network requests, Apple provides NSURLSession, which is a complete suite of networking API methods for uploading and downloading content via HTTP.

In this NSURLSession tutorial, you’ll learn how to use NSURLSession to build the Half Tunes app, which lets you query the iTunes Search API and download 30-second previews of selected songs. The finished app will also support background transfers and let the user pause, resume or cancel in-progress downloads.

Getting Started

Download the starter project; it already contains a user interface for searching for songs and displaying search results, as well as some helper methods to parse JSON and play tracks. This lets you focus on implementing the networking aspects of the app.

Build and run your project; you should see a view with a search bar at the top and an empty table view below:

Half Tunes Starter Project

Type a query in the search bar and tap Search. The view remains empty, but don’t worry; you’ll change this with your new NSURLSession calls.

Overview of NSURLSession

Before you begin, it’s important to appreciate NSURLSession and its constituent classes, so take a minute to walk through the quick overview below.

NSURLSession is technically both a class and a suite of classes for handling HTTP/HTTPS-based requests:

NSURLSession Tutorial

NSURLSession is the key object responsible for sending and receiving HTTP requests. You create it via NSURLSessionConfiguration, which comes in three flavors:

  • defaultSessionConfiguration: Creates a default configuration object that uses the disk-persisted global cache, credential and cookie storage objects.
  • ephemeralSessionConfiguration: Similar to the default configuration, except that all session-related data is stored in memory. Think of this as a “private” session.
  • backgroundSessionConfiguration: Lets the session perform upload or download tasks in the background. Transfers continue even when the app itself is suspended or terminated.

NSURLSessionConfiguration also lets you configure session properties such as timeout values, caching policies and additional HTTP headers. Refer to the documentation for a full list of configuration options.

NSURLSessionTask is an abstract class that denotes a task object. A session creates a task, which does the actual work of fetching data and downloading or uploading files.

There are three types of concrete session tasks in this context:

  • NSURLSessionDataTask: Use this task for HTTP GET requests to retrieve data from servers to memory.
  • NSURLSessionUploadTask: Use this task to upload a file from disk to a web service, typically via a HTTP POST or PUT method.
  • NSURLSessionDownloadTask: Use this task to download a file from a remote service to a temporary file location.

NSURLSession Tutorial

You can also suspend, resume and cancel tasks. NSURLSessionDownloadTask has the additional ability to pause for future resumption.

Generally, NSURLSession returns data in two ways: via a completion handler when a task finishes either successfully or with an error, or by calling methods on a delegate that you set upon session creation.

Now that you have an overview of what NSURLSession can do, you’re ready to put the theory into practice!

Querying for Tracks

You’ll start by adding the code to query the iTunes Search API when the user searches for a track.

In SearchViewController.swift, add the following code to the top of the class:

// 1
let defaultSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
// 2
var dataTask: NSURLSessionDataTask?

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

  1. You create a NSURLSession and initialize it with a default session configuration.
  2. You declare a NSURLSessionDataTask variable which you’ll used to make an HTTP GET request to the iTunes Search web service when the user performs a search. The data task will be re-initialized and reused each time the user creates a new query.

Now, replace searchBarSearchButtonClicked(_:) with the following:

func searchBarSearchButtonClicked(searchBar: UISearchBar) {
  dismissKeyboard()
 
  if !searchBar.text!.isEmpty {
    // 1
    if dataTask != nil {
      dataTask?.cancel()
    }
    // 2
    UIApplication.sharedApplication().networkActivityIndicatorVisible = true
    // 3
    let expectedCharSet = NSCharacterSet.URLQueryAllowedCharacterSet()
    let searchTerm = searchBar.text!.stringByAddingPercentEncodingWithAllowedCharacters(expectedCharSet)!
    // 4
    let url = NSURL(string: "https://itunes.apple.com/search?media=music&entity=song&term=\(searchTerm)")
    // 5
    dataTask = defaultSession.dataTaskWithURL(url!) {
      data, response, error in
      // 6
      dispatch_async(dispatch_get_main_queue()) {
        UIApplication.sharedApplication().networkActivityIndicatorVisible = false
      }
      // 7
      if let error = error {
        print(error.localizedDescription)
      } else if let httpResponse = response as? NSHTTPURLResponse {
        if httpResponse.statusCode == 200 {
          self.updateSearchResults(data)
        }
      }
    }
    // 8
    dataTask?.resume()
  }
}

Taking each numbered comment in turn:

  1. Upon each user query, you check if the data task is already initialized. If so, you cancel the task as you want to reuse the data task object for the latest query.
  2. You enable the network activity indicator on the status bar to indicate to the user that a network process is running.
  3. Before passing the user’s search string as a parameter to the query URL, you call stringByAddingPercentEncodingWithAllowedCharacters(_:) on the string to ensure that it’s properly escaped.
  4. Next you construct a NSURL by appending the escaped search string as a GET parameter to the iTunes Search API base url.
  5. From the session you created, you initialize a NSURLSessionDataTask to handle the HTTP GET request. The constructor of NSURLSessionDataTask takes in the NSURL that you constructed along with a completion handler to be called when the data task is completed.
  6. Upon receiving a callback that the task completed, you hide the activity indicator and invoke the UI update in the main thread.
  7. If the HTTP request is successful, you call updateSearchResults(_:), which parses the response NSData into Tracks and updates the table view.
  8. All tasks start in a suspended state by default; calling resume() starts the data task.

Build and run your app; search for any song and you should see the table view populate with the relevant track results like so:

HalfTunes Search

With a little bit of NSURLSession magic added, Half Tunes is now somewhat functional!

Downloading a Track

Being able to view song results is nice, but wouldn’t it be better if you could tap on a song to download it? That’s precisely your next order of business.

To make it easy to handle multiple downloads, you’ll first create a custom object to hold the state of an active download.

Create a new file named Download.swift in the Data Objects group.

Open Download.swift and add the following implementation:

class Download: NSObject {
 
  var url: String
  var isDownloading = false
  var progress: Float = 0.0
 
  var downloadTask: NSURLSessionDownloadTask?
  var resumeData: NSData?
 
  init(url: String) {
    self.url = url
  }
}

Here’s a rundown of the properties of Download:

  • url: The URL of the file to download. This also acts as a unique identifier for a Download.
  • isDownloading: Whether the download is ongoing or paused.
  • progress: The fractional progress of the download; a float between 0.0 and 1.0.
  • downloadTask: The NSURLSessionDownloadTask that downloads the file.
  • resumeData: Stores the NSData produced when you pause a download task. If the host server supports it, you can use this to resume a paused download in the future.

Switch to SearchViewController.swift and add the following code to the top of your class:

var activeDownloads = [String: Download]()

This simply maintains a mapping between URLs and their active Download, if any.

Creating a Download Task

With all the preparatory work out of the way, you’re now ready to implement file downloads. You’ll first create a dedicated session to handle your download tasks.

In SearchViewController.swift, add the following code right before viewDidLoad():

lazy var downloadsSession: NSURLSession = {
  let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
  let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
  return session
}()

Here you initialize a separate session with a default configuration to handle all your download tasks. You also specify a delegate, which lets you receive NSURLSession events via delegate calls. This is useful for tracking not just when a task is complete, but also the progress of the task.

Setting the delegate queue to nil causes the session to create a serial operation queue, by default, to perform all calls to the delegate methods and completion handlers.

Note the lazy creation of downloadsSession: this lets you delay the creation of the session until it’s needed. Most importantly, it lets you pass self as the delegate parameter to the initializer — even if self isn’t initialized.

In SearchViewController.swift, find the empty NSURLSessionDownloadDelegate extension and make it look like this:

extension SearchViewController: NSURLSessionDownloadDelegate {
  func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
    print("Finished downloading.")
  }
}

NSURLSessionDownloadDelegate defines delegate methods that you need to implement when using NSURLSession download tasks. The only non-optional method is URLSession(_:downloadTask:didFinishDownloadingToURL:), which you call whenever a download finishes. For now, you’ll print a simple message whenever a download completes.

With your session and delegate configured, you’re finally ready to create a download task when the user requests a track download.

In SearchViewController.swift, replace startDownload(_:) with the following implementation:

func startDownload(track: Track) {
  if let urlString = track.previewUrl, url =  NSURL(string: urlString) {
    // 1
    let download = Download(url: urlString)
    // 2
    download.downloadTask = downloadsSession.downloadTaskWithURL(url)
    // 3
    download.downloadTask!.resume()
    // 4
    download.isDownloading = true
    // 5
    activeDownloads[download.url] = download
  }
}

When you tap the Download button for a track, you call startDownload(_:) with the corresponding Track. Here’s what’s going on :

  1. You first initialize a Download with the preview URL of the track.
  2. Using your new session object, you create a NSURLSessionDownloadTask with the preview URL, and set it to the downloadTask property of the Download.
  3. You start the download task by calling resume() on it.
  4. You indicate that the download is in progress.
  5. Finally, you map the download URL to its Download in the activeDownloads dictionary.

Build and run your app; search for any track and tap the Download button on a cell. You should see a message printed on your console after a while, signifying that the download is complete.

Saving and Playing the Track

When a download task completes, URLSession(_:downloadTask:didFinishDownloadingToURL:) provides a URL to the temporary file location. Your job is to move it to a permanent location in your app’s sandbox container directory before you return from the method. As well, you’ll have to remove the active download from the dictionary and update the table view.

You’ll add a helper method to make things easy. In SearchViewController.swift, add the following method to the class:

func trackIndexForDownloadTask(downloadTask: NSURLSessionDownloadTask) -> Int? {
  if let url = downloadTask.originalRequest?.URL?.absoluteString {
    for (index, track) in searchResults.enumerate() {
      if url == track.previewUrl! {
        return index
      }
    }
  }
  return nil
}

This method simply returns the the index of the Track in the searchResults list that has the given URL.

Next, replace URLSession(_:downloadTask:didFinishDownloadingToURL:) with the following code:

func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
  // 1
  if let originalURL = downloadTask.originalRequest?.URL?.absoluteString,
    destinationURL = localFilePathForUrl(originalURL) {
 
    print(destinationURL)
 
    // 2
    let fileManager = NSFileManager.defaultManager()
    do {
      try fileManager.removeItemAtURL(destinationURL)
    } catch {
      // Non-fatal: file probably doesn't exist
    }
    do {
      try fileManager.copyItemAtURL(location, toURL: destinationURL)
    } catch let error as NSError {
      print("Could not copy file to disk: \(error.localizedDescription)")
    }
  }
 
  // 3
  if let url = downloadTask.originalRequest?.URL?.absoluteString {
    activeDownloads[url] = nil
    // 4
    if let trackIndex = trackIndexForDownloadTask(downloadTask) {
      dispatch_async(dispatch_get_main_queue(), {
        self.tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: trackIndex, inSection: 0)], withRowAnimation: .None)
      })
    }
  }
}

Here’s the key steps from above:

  1. You extract the original request URL from the task and pass it to the provided localFilePathForUrl(_:) helper method. localFilePathForUrl(_:) then generates a permanent local file path to save to by appending the lastPathComponent of the URL (i.e. the file name and extension of the file) to the path of the app’s Documents directory.
  2. Using NSFileManager, you move the downloaded file from its temporary file location to the desired destination file path by clearing out any item at that location before you start the copy task.
  3. You look up the corresponding Download in your active downloads and remove it.
  4. Finally, you look up the Track in your table view and reload the corresponding cell.

Build and run your project; pick any track and download it. When the download has finished, you should see the file path location printed to your console:

Screen Shot 2015-08-16 at 8.03.30 pm

The Download button will also disappear, since the track is now on your device. Tap the track and you’ll hear it play in the presented MPMoviePlayerViewController as shown below:

Simulator Screen Shot 17 Aug 2015 1.45.28 am

Monitoring Download Progress

Currently, you have no way to monitor the progress of the download. To improve the user experience, you’ll change your app to listen for download progress events and display the progress in the cells.

In SearchViewController.swift, find the extension that implements NSURLSessionDownloadDelegate and add the following delegate method:

func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
 
    // 1
    if let downloadUrl = downloadTask.originalRequest?.URL?.absoluteString,
      download = activeDownloads[downloadUrl] {
      // 2
      download.progress = Float(totalBytesWritten)/Float(totalBytesExpectedToWrite)
      // 3
      let totalSize = NSByteCountFormatter.stringFromByteCount(totalBytesExpectedToWrite, countStyle: NSByteCountFormatterCountStyle.Binary)
      // 4
      if let trackIndex = trackIndexForDownloadTask(downloadTask), let trackCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: trackIndex, inSection: 0)) as? TrackCell {
        dispatch_async(dispatch_get_main_queue(), {
          trackCell.progressView.progress = download.progress
          trackCell.progressLabel.text =  String(format: "%.1f%% of %@",  download.progress * 100, totalSize)
        })
    }
  }
}

Looking through the delegate method step-by-step:

  1. Using the provided downloadTask, you extract the URL and use it to find the Download in your dictionary of active downloads.
  2. The method also returns the total bytes written and the total bytes expected to be written. You calculate the progress as the ratio of the two values and save the result in the Download. You’ll use this value to update the progress view.
  3. NSByteCountFormatter takes a byte value and generates a human-readable string showing the total download file size. You’ll use this string to show the size of the download alongside the percentage complete.
  4. Finally, you find the cell responsible for displaying the Track, and update both its progress view and progress label with the values derived from the previous steps.

Next, you’ll configure the cells to properly display the progress view and status whenever a download is in progress.

Find the following line of code in tableView(_:cellForRowAtIndexPath:):

let downloaded = localFileExistsForTrack(track)

Add the following code just before the line above:

var showDownloadControls = false
if let download = activeDownloads[track.previewUrl!] {
  showDownloadControls = true
 
  cell.progressView.progress = download.progress
  cell.progressLabel.text = (download.isDownloading) ? "Downloading..." : "Paused"
}
cell.progressView.hidden = !showDownloadControls
cell.progressLabel.hidden = !showDownloadControls

For tracks with active downloads, you set showDownloadControls to true; otherwise, you set it to false. You then display the progress views and labels, provided with the sample project, in accordance with the value of showDownloadControls.

For paused downloads, display “Paused” for the status; otherwise, display “Downloading…”.

Finally, replace the following line:

cell.downloadButton.hidden = downloaded

with the following code:

cell.downloadButton.hidden = downloaded || showDownloadControls

Here, you tell the cell to also hide the Download button if its track is downloading.

Build and run your project; download any track and you should see the progress bar status update as the download progresses:

Screen Shot 2015-08-17 at 11.02.03 pm

Hurray, you’ve made, erm, progress! :]

Pausing, Resuming and Cancelling Downloads

What if you need to pause a download, or cancel it altogether? In this section, you’ll implement the pause, resume and cancel features to give the user complete control over the download process.

You’ll start by allowing the user to cancel an active download.

Replace cancelDownload(_:) with the following code:

func cancelDownload(track: Track) {
  if let urlString = track.previewUrl,
    download = activeDownloads[urlString] {
      download.downloadTask?.cancel()
      activeDownloads[urlString] = nil
  }
}

To cancel a download, you retrieve the download task from the corresponding Download in the dictionary of active downloads and call cancel() on it to cancel the task. You then remove it from the dictionary of active downloads.

Pausing a download is conceptually similar to cancelling; the difference is pausing cancels the download task, but also produces resume data, which contains enough information to resume the download at a later time, should the host server support that functionality.

Note: You can only resume a download under certain conditions. For instance, the resource must not have changed since you first requested it. For a full list of conditions, check out the Apple documentation here.

Now, replace pauseDownload(_:) with the following code:

func pauseDownload(track: Track) {
  if let urlString = track.previewUrl,
    download = activeDownloads[urlString] {
      if(download.isDownloading) {
        download.downloadTask?.cancelByProducingResumeData { data in
          if data != nil {
            download.resumeData = data
          }
        }
        download.isDownloading = false
      }
  }
}

The key difference here is the call to cancelByProducingResumeData(_:) instead of cancel(). You retrieve the resume data from the closure provided by cancelByProducingResumeData(:_) and save it to the appropriate Download for future resumption.

You also set the isDownloading property of the Download to false to signify that the download is paused.

With the pause function completed, the next order of business is to allow the resumption of a paused download.

Replace resumeDownload(_:) with the following code:

func resumeDownload(track: Track) {
  if let urlString = track.previewUrl,
    download = activeDownloads[urlString] {
      if let resumeData = download.resumeData {
        download.downloadTask = downloadsSession.downloadTaskWithResumeData(resumeData)
        download.downloadTask!.resume()
        download.isDownloading = true
      } else if let url = NSURL(string: download.url) {
        download.downloadTask = downloadsSession.downloadTaskWithURL(url)
        download.downloadTask!.resume()
        download.isDownloading = true
      }
  }
}

When the user resumes a download, you check the appropriate Download for the presence of resume data. If found, you create a new download task by invoking downloadTaskWithResumeData(_:) with the resume data and start the task by calling resume(). If the resume data is absent for some reason, you create a new download task from scratch with the download URL anyway and start it.

In both cases, you set the isDownloading flag of the Download to true to indicate the download has resumed.

There’s only one thing left to do for the three functions to work properly: you need to show or hide the Pause, Cancel and Resume buttons as appropriate.

Go to tableView(_:cellForRowAtIndexPath:) and find the following line of code:

if let download = activeDownloads[track.previewUrl!] {

Add the following lines to the end of the let block above:

let title = (download.isDownloading) ? "Pause" : "Resume"
cell.pauseButton.setTitle(title, forState: UIControlState.Normal)

Since the pause and resume functions share the same button, the code above toggles the button between the two states as appropriate.

Next, add the following code to the end of tableView(_:cellForRowAtIndexPath:), just before the return statement:

cell.pauseButton.hidden = !showDownloadControls
cell.cancelButton.hidden = !showDownloadControls

Here you simply show the buttons for a cell only if a download is active.

Build and run your project; download a few tracks concurrently and you’ll be able to pause, resume and cancel them at will:

Simulator Screen Shot 18 Aug 2015 10.14.38 pm

Enabling Background Transfers

Your app is quite functional at this point, but there’s one major enhancement left to add: background transfers. In this mode, downloads continue even when your app is backgrounded or crashes for any reason.

But if your app isn’t running, how can this work? There’s a separate daemon that runs outside the app and manages background transfer tasks; it sends the appropriate delegate messages to the app as the download tasks run. In the event the app terminates during an active transfer, the tasks will continue to run unaffected in the background.

When a task completes, the daemon will relaunch the app in the background. The re-launched app will reconnect to the same session, receive the relevant completion delegate messages and perform any required actions such as persisting downloaded files to disk.

Note: If you terminate the app by force-quiting from the app switcher, the system will cancel all of the session’s background transfers and won’t attempt to relaunch the app.

Still in SearchViewController.swift, in the initialization of downloadsSession, find the following line of code:

let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()

…and replace it with the following line:

let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("bgSessionConfiguration")

Instead of using a default session configuration, you use a special background session configuration. Note that you also set a unique identifier for the session here to allow you to reference and “reconnect” to the same background session if needed.

Next, in viewDidLoad(), add the following code:

_ = self.downloadsSession

Calling the lazily-loaded downloadsSession ensures the app creates exactly one background session upon initialization of SearchViewController.

If a background task completes when app isn’t running, the app will be relaunched into the background. You’ll need to handle this event from your app delegate.

Switch to AppDelegate.swift and add the following code near the top of the class:

var backgroundSessionCompletionHandler: (() -> Void)?

Next, add the following method to AppDelegate.swift:

func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) {
  backgroundSessionCompletionHandler = completionHandler
}

Here, you save the provided completionHandler as a variable in your app delegate for later use.

application(_:handleEventsForBackgroundURLSession:) wakes up the app to deal with the completed background task. You need to handle two things in this event:

  • First, the app needs to reconnect to the appropriate background session with the identifier provided by the delegate method. But since you create and use one background session every time you instantiate SearchViewController, you’re already reconnected at this point!
  • Second, you’ll need to capture the completion handler provided by the delegate method. Invoking the completion handler causes the OS to snapshot your updated UI for display in the app switcher, as well as tells the OS that your app’s done working with all background activities for the current session.

But when should you invoke the completion handler? URLSessionDidFinishEventsForBackgroundURLSession(_:) would be a good choice; it’s a NSURLSessionDelegate method that fires when all tasks pertaining to the background session have finished.

Implement the following extension in SearchViewController.swift:

extension SearchViewController: NSURLSessionDelegate {
 
  func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
    if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
      if let completionHandler = appDelegate.backgroundSessionCompletionHandler {
        appDelegate.backgroundSessionCompletionHandler = nil
        dispatch_async(dispatch_get_main_queue(), {
          completionHandler()
        })
      }
    }
  }
}

The above code simply grabs the stored completion handler from the app delegate and invokes it on the main thread.

Build and run your app; start a few concurrent downloads and tap the Home button to background the app. Wait until you think the downloads have completed, then double-tap the Home button to reveal the app switcher.

The downloads should have finished and their new status reflected in the app screenshot. Open the app to confirm this:

Simulator Screen Shot 19 Aug 2015 1.06.24 am

You now have a fully functional music streaming app! Your move now, Apple Music! :]

Where to Go From Here?

You can download the complete project for this tutorial here.

Congratulations! You’re now well-equipped to handle most common networking requirements in your app. There are more details to NSURLSession than would fit in this NSURLSession tutorial, such as upload tasks and session configuration settings such as timeout values and caching policies.

To learn more about these features (and others!), check out the following resources:

I hope you found this tutorial useful. Feel free to join the discussion below!

The post NSURLSession Tutorial: Getting Started appeared first on Ray Wenderlich.

Video Tutorial: Introducing Concurrency Part 8: Dispatch Groups

Video Tutorial: Introducing Concurrency Part 9: Thread-safe Resources

Video Tutorial: Introducing Concurrency Part 10: GCD Delights

Video Tutorial: Introducing Concurrency Part 11: Conclusion

tvOS Apprentice Early Access Update Available: Now With 17 Chapters!

$
0
0

TVT-Thumb

As we develop our new book the tvOS Apprentice, we are releasing early access versions along the way. Today, we are happy to release our second early access release of the book!

This version now has 17/28 chapters ready, 10 of which are new to this release:

  • 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.
  • Chapter 2, Hello, TVML (New!): Shows you how to set up a basic Hello World app using TVML and Javascript.
  • Chapter 3, Beginning TVML (New!): You’ll use basic TVML templates to manipulate the UI in a simple application.
  • Chapter 4, Intermediate TVML (New!): Building off of chapter 3, you’ll learn more complicated interfaces and templates.
  • Chapter 5, TVJS (New!): Start working in Javascript and learn to manipulate the TVML DOM.
  • Chapter 8, Hello, Traditional App: Learn how to set up a basic “Hello World” app using native libraries in Swift.
  • Chapter 9, Basic Controls: Learn the basic controls your users can use to interact with your apps.
  • Chapter 10, Stack Views (New!): Stack Views are the backbone to the layout of your app – learn how to use them here.
  • Chapter 11, Collection Views (New!): See how easy it is to display a list of items in an engaging layout.
  • Chapter 15, Networking (New!): Learn how to download content, video, and other assets over the network.
  • 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!
  • Chapter 18, Advanced Video Playback (New!): Learn about some of the more advanced topics in playing videos.
  • Chapter 20, Beginning CloudKit: Learn how to use CloudKit on tvOS to store your app’s data.
  • Chapter 21, Advanced CloudKit (New!): Go further in depth with CloudKit with user specific storage and error handling.
  • Chapter 24, tvOS Design: Learn how to design your apps to fit in well with the tvOS ecosystem.
  • Chapter 25, Creating Layered Images: Shows how to create a new kind of image specifically for the TV.
  • Chapter 26, The Top Shelf (New!): 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.

We’re nearing the final release of the book – just 11 chapters left! :]

Where To Go From Here?

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

  • If you preordered the tvOS Apprentice: You can download the early access release immediately on your My Loot page.
  • If you don’t have the book yet: What are you waiting for – preorder the book now, get early access, and save $10 off the final price! :]

The recent release of tvOS brings tons of new opportunities for developers, and you’ll want to be prepared to make the most of it.

Prepare yourself for your own private tour on making tvOS apps – from beginning to advanced. Jerry, Eric, Sam, Evan, Joshua, Michael, Kelvin, Julien, Mike and I hope you enjoy the book!

The post tvOS Apprentice Early Access Update Available: Now With 17 Chapters! appeared first on Ray Wenderlich.


iOS Metal Tutorial with Swift Part 4: Lighting

$
0
0
Learn how to add lighting into your Metal apps!

Learn how to add lighting into your Metal apps!

Welcome back to our iOS Metal tutorial series!

In the first part of the series, you learned how to get started with Metal and render a simple 2D triangle.

In the second part of the series, you learned how to set up a series of transformations to move from a triangle to a full 3D cube.

In the third part of the series, you learned how to add a texture to the cube.

In this forth part of the series, you’ll learn how to add some lighting to the cube. As you work through this tutorial, you’ll learn:

  • Some basic light concepts
  • Phong light model components
  • How to calculate light effect for each point in the scene, in shaders

Without further ado, it’s time to get Metal!

Getting Started

Before you begin, you need to understand how lighting works.

Lightning means applying light generated from light sources to rendered objects. That’s how our real world works; light sources (like the sun or lamps) produce light, and rays of these lights collide with environment and illuminate it. Our eyes can then see this environment and we have a picture rendered on our eyes retina.

In our real world there are multiple light sources. Those light sources work like this:

source_of_light

Rays are emitted in all directions from the light source.

The same rule applies to our biggest light source – sun. However, when we take into account the huge distance between the Sun and the Earth, it’s safe to treat the small percentage of rays emitted from the Sun that actually collide with Earth as parallel rays.

parallel

For this tutorial, you’ll use only one light source with parallel rays, just like those of the sun. This is called a directional light and is commonly used in 3D games.

Phong Lighting Model

There are various algorithms used to shade objects based on light sources, but one of the most popular is called the phong lighting model.

This model is popular for a good reason. Not only is it quite simple to implement and understand, but it’s also quite performant and looks great!

The phong lighting model consist of three components:

32_a

  1. Ambient Lighting: Represents light that hits an object from all directions. You can think of this as light bouncing around a room.
  2. Diffuse Lighting: Represents light that is brighter the more a surface is facing the light source. Of rall three components, I’d argue this is the most important part for the visual effect.
  3. Specular Lighting: Represents light that causes a bright spot for the small area that is directly toward the light source. You can think of this as a bright spot on a shiny piece of metal.

You will learn more about each of these components as you implement them in this tutorial.

Project Setup

It’s time to code! Start by downloading the starter project for this tutorial. It’s exactly where we finished in the previous tutorial, except for that now it is updated for Xcode 7 and Swift 2.0.

Run it on a Metal-compatible iOS device, just to be sure it works correctly. You should see the following:

IMG_4274

This represents a 3D cube. It looks great except all areas of the cube are currently lit evenly so it looks a bit flat. Let’s improve the looks through the power of lighting!

Ambient Lighting Overview

Remember that ambient lighting highlights all surfaces in the scene the same amount, no matter where the surface is located, which direction the surface is facing, or what the light direction is.

To calculate ambient lighting, you need two parameters:

  1. Light color: Light can be different colors. For example, if a light is red, it will tint each object the light hits red. For this tutorial you will use a plain white color for the light. White light is a common choice, since white doesn’t tint the material of the object any differently.
  2. Ambient intensity: This is a value that represents the strength of the light. The higher the value, the stronger the illumination of the scene will be.

Once you have those parameters, you can calculate the ambient lighting as follows:

Ambient color = Light color * Ambient intensity

Let’s give this a shot in code!

Adding Ambient Lighting

Creating a Light Structure

First, you need a structure to store light data.

Add a new Swift file to your project named Light.swift and replace its contents with the following:

import Foundation
 
struct Light {
 
  var color: (Float, Float, Float)  // 1
  var ambientIntensity: Float       // 2
 
  static func size() -> Int {       // 3
    return sizeof(Float) * 4
  }
 
  func raw() -> [Float] {
    let raw = [color.0, color.1, color.2, ambientIntensity]   // 4
    return raw
  }
}

Let’s review this section by section:

  1. A property that stores the light color in red, green, and blue.
  2. Stores the intensity of the ambient effect.
  3. This is a convenience function to get size of Light structure.
  4. This is a convenience function to convert the structure to an array of floats. You’ll use this and the size() function to send the light data to the GPU.

This is similar to Vertex structure that you created in part 2 of this series.

Now open Node.swift and add the following constant to the class:

let light = Light(color: (1.0,1.0,1.0), ambientIntensity: 0.2)

This creates a white light with a low intensity (0.2).

Passing the Light Data to the GPU

Next you need to pass this light data to the GPU. You already include the projection and model matrices in uniform buffer; you’ll modify this to include the light data too.

To do this, open BufferProvider.swift, and in init(device:inflightBuffersCount) replace this line of code:

let sizeOfUniformsBuffer = sizeof(Float) * (2 * Matrix4.numberOfElements())

…with this one:

let sizeOfUniformsBuffer = sizeof(Float) * (2 * Matrix4.numberOfElements()) + Light.size()

Here you have increased the size of uniform buffers, so that now you have room for the light data.

Now change this method declaration:

func nextUniformsBuffer(projectionMatrix: Matrix4, modelViewMatrix: Matrix4) -> MTLBuffer

…to be like this:

func nextUniformsBuffer(projectionMatrix: Matrix4, modelViewMatrix: Matrix4, light: Light) -> MTLBuffer

Here you added an extra parameter for the light data. Now inside this same method, find these lines:

memcpy(bufferPointer, modelViewMatrix.raw(), sizeof(Float)*Matrix4.numberOfElements())
memcpy(bufferPointer + sizeof(Float)*Matrix4.numberOfElements(), projectionMatrix.raw(), sizeof(Float)*Matrix4.numberOfElements())

…and add this line just below:

memcpy(bufferPointer + 2*sizeof(Float)*Matrix4.numberOfElements(), light.raw(), Light.size())

With this additional memcpy() call, you copy light data to the uniform buffer, just as you did with with projection and modelView matrices.

Modifying the Shaders to Accept the Light Data

Now that the data is passed to GPU, you need to modify your shader to use it. To do this, open Shaders.metal and below the VertexOut structure, add the a new structure for the light data you pass across:

struct Light{
  packed_float3 color;
  float ambientIntensity;
};

Now modify the Uniforms structure to contain Light, as follows:

struct Uniforms{
  float4x4 modelMatrix;
  float4x4 projectionMatrix;
  Light light;
};

At this point, you can access light data inside of the vertex shader. However, you also need this data in fragment shader.

To do this, change the fragment shader declaration to match this:

fragment float4 basic_fragment(VertexOut interpolated [[stage_in]],
                               const device Uniforms&  uniforms    [[ buffer(1) ]],
                               texture2d<float>  tex2D     [[ texture(0) ]],
                               sampler           sampler2D [[ sampler(0) ]])

This adds the uniform data as the second parameter.

Now, before you forget, open Node.swift, and inside render(_:pipelineState:drawable:parentModelViewMatrix:projectionMatrix:clearColor:) find this line:

renderEncoder.setVertexBuffer(uniformBuffer, offset: 0, atIndex: 1)

…and add this line right underneath:

go to the Node file into the render method, and add this:

renderEncoder.setFragmentBuffer(uniformBuffer, offset: 0, atIndex: 1)

By adding this code, you pass uniform buffer as a parameter not only to the vertex shader, but to the fragment shader as well.

While you’re in this method, you’ll notice an error on this line:

let uniformBuffer = bufferProvider.nextUniformsBuffer(projectionMatrix, modelViewMatrix: nodeModelMatrix)

To fix this error, you need to pass the light data to the buffer provider. To do this, replace that line with the following:

let uniformBuffer = bufferProvider.nextUniformsBuffer(projectionMatrix, modelViewMatrix: nodeModelMatrix, light: light)

Take a step back to make sure you understand what you’ve done so far. At this point, that you’ve passed Light data from CPU to GPU, and more specifically, to the fragment shader. This is very similar to how you passed matrices to GPU in previous parts.

Make sure you understand the flow, because you will pass some more data later, in a similar fashion.

Adding the Ambient Light Calculation

Now return to the fragment shader in Shaders.metal. Add these lines to the top of the fragment shader:

// Ambient
Light light = uniforms.light;
float4 ambientColor = float4(light.color * light.ambientIntensity, 1);

This retrieves the light data from the uniforms, and uses the values to calculate the ambientColor using the algorithm discussed earlier.

Now that you have calculated ambientColor, replace the last line of the method as follows:

return color * ambientColor;

This multiplies the color of the material by the calculated ambient color.

That’s it! Build and run the app and you’ll see the following:

IMG_4275

What’s Going On?

As you can see, it’s really dark right now. You might ask yourself: “Adding ambient light just made my scene darker! Is that really the way it works?!”

Darkness

Although it may seem strange, the answer is “Yes”!

Another way of looking at it is that without any light, everything is pitch black. But by adding a small amount of ambient light, you have highlighted your objects slightly, as-if it was the early dawn of a morning.

You might also wonder, “Why hasn’t the background changed?”. And the answer for that is simple: The vertex shader runs on all scene geometry, but the background is not geometry. In fact, it’s not even a background, it’s just a constant color which the GPU uses for places where nothing is drawn.

The green color, despite being quintessence of awesomeness, doesn’t really suit anymore for a clear color role. So in Node.swift inside render(_:pipelineState:drawable:parentModelViewMatrix:projectionMatrix:clearColor:) find this line:

renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 104.0/255.0, blue: 5.0/255.0, alpha: 1.0)

…and replace it with the following:

renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)

Build and run, and you’ll see the following:

IMG_4276

Now it looks a lot less confusing!

Diffuse Lighting Overview

Introducing Normals

To calculate diffuse lighting, you need to know which direction each vertex is facing. You do this by associating a normal with each vertex.

So what is normal of a vertex? It’s a vector which is perpendicular to the surface that the vertex is a part of.

Take a look at this picture so that it becomes more visual:

38_a

You will store the normal of each vertex in the Vertex structure, similarly to how you store texture coordinates or position values.

Introducing Dot Products

There is also one important topic left to cover before the actual implementation of diffuse lighting – the dot product of vectors.

The dot product is a mathematical function between two vectors, such that:

  • When the vectors are parallel: the dot product of them is equal 1.
  • When the vectors are opposite directions: the dot product of them is equal -1.
  • When the angle between the vectors is 90°: the dot product is equal to 0.

Screen Shot 2015-08-14 at 12.59.39 AM

This will come in handy shortly.

Introducing Diffuse Lighting

Now when you have normals and you understand dot product, let’s see how to implement diffuse lighting.

Remember that diffuse lighting is brighter if the normal of a vector is facing toward the light, and (you guessed it) weaker otherwise.

To calculate diffuse lighting, you need two parameters:

  1. Light color: You need the color of the light, similar to ambient lighting. In this tutorial, you’ll use the same color for all types of light (ambient, diffuse, and specular), but you can make them different if you want.
  2. Diffuse intensity: This is a value similar to Ambient intensity; the bigger it is, the stronger the diffuse effect is.
  3. Diffuse factor: This is a value that you can get by taking the dot product between the light direction vector and vertex normal. The smaller the angle between those two vectors, the higher this value, and the stronger diffuse lighting effect should be.

You can calculate the diffuse lighting as follows:

<em>Diffuse Color = Light Color * Diffuse Intensity * Diffuse factor</em>.

33_a

On the picture, you can see dot products of various point of the object, depending on how they are pointing related to the light direction; this represents the diffuse factor. The higher the diffuse factor, the brighter the diffuse light.

Now let’s dive into the implementation!

Adding Diffuse Lighting

Adding Normal Data

First things first, you need to add normal data to Vertex.

Open Vertex.swift and find these properties:

var s,t: Float       // texture coordinates

Below those properties, add the following properties:

var nX,nY,nZ: Float  // normal

Now modify func floatBuffer() to look like this:

func floatBuffer() -> [Float] {
    return [x,y,z,r,g,b,a,s,t,nX,nY,nZ]
}

This adds the new normal properties to the buffer of floats.

Now open Cube.swift and change vertices to match those:

//Front
let A = Vertex(x: -1.0, y:   1.0, z:   1.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0, s: 0.25, t: 0.25, nX: 0.0, nY: 0.0, nZ: 1.0)
let B = Vertex(x: -1.0, y:  -1.0, z:   1.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0, s: 0.25, t: 0.50, nX: 0.0, nY: 0.0, nZ: 1.0)
let C = Vertex(x:  1.0, y:  -1.0, z:   1.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0, s: 0.50, t: 0.50, nX: 0.0, nY: 0.0, nZ: 1.0)
let D = Vertex(x:  1.0, y:   1.0, z:   1.0, r:  0.1, g:  0.6, b:  0.4, a:  1.0, s: 0.50, t: 0.25, nX: 0.0, nY: 0.0, nZ: 1.0)
 
//Left
let E = Vertex(x: -1.0, y:   1.0, z:  -1.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0, s: 0.00, t: 0.25, nX: -1.0, nY: 0.0, nZ: 0.0)
let F = Vertex(x: -1.0, y:  -1.0, z:  -1.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0, s: 0.00, t: 0.50, nX: -1.0, nY: 0.0, nZ: 0.0)
let G = Vertex(x: -1.0, y:  -1.0, z:   1.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0, s: 0.25, t: 0.50, nX: -1.0, nY: 0.0, nZ: 0.0)
let H = Vertex(x: -1.0, y:   1.0, z:   1.0, r:  0.1, g:  0.6, b:  0.4, a:  1.0, s: 0.25, t: 0.25, nX: -1.0, nY: 0.0, nZ: 0.0)
 
//Right
let I = Vertex(x:  1.0, y:   1.0, z:   1.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0, s: 0.50, t: 0.25, nX: 1.0, nY: 0.0, nZ: 0.0)
let J = Vertex(x:  1.0, y:  -1.0, z:   1.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0, s: 0.50, t: 0.50, nX: 1.0, nY: 0.0, nZ: 0.0)
let K = Vertex(x:  1.0, y:  -1.0, z:  -1.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0, s: 0.75, t: 0.50, nX: 1.0, nY: 0.0, nZ: 0.0)
let L = Vertex(x:  1.0, y:   1.0, z:  -1.0, r:  0.1, g:  0.6, b:  0.4, a:  1.0, s: 0.75, t: 0.25, nX: 1.0, nY: 0.0, nZ: 0.0)
 
//Top
let M = Vertex(x: -1.0, y:   1.0, z:  -1.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0, s: 0.25, t: 0.00, nX: 0.0, nY: 1.0, nZ: 0.0)
let N = Vertex(x: -1.0, y:   1.0, z:   1.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0, s: 0.25, t: 0.25, nX: 0.0, nY: 1.0, nZ: 0.0)
let O = Vertex(x:  1.0, y:   1.0, z:   1.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0, s: 0.50, t: 0.25, nX: 0.0, nY: 1.0, nZ: 0.0)
let P = Vertex(x:  1.0, y:   1.0, z:  -1.0, r:  0.1, g:  0.6, b:  0.4, a:  1.0, s: 0.50, t: 0.00, nX: 0.0, nY: 1.0, nZ: 0.0)
 
//Bot
let Q = Vertex(x: -1.0, y:  -1.0, z:   1.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0, s: 0.25, t: 0.50, nX: 0.0, nY: -1.0, nZ: 0.0)
let R = Vertex(x: -1.0, y:  -1.0, z:  -1.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0, s: 0.25, t: 0.75, nX: 0.0, nY: -1.0, nZ: 0.0)
let S = Vertex(x:  1.0, y:  -1.0, z:  -1.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0, s: 0.50, t: 0.75, nX: 0.0, nY: -1.0, nZ: 0.0)
let T = Vertex(x:  1.0, y:  -1.0, z:   1.0, r:  0.1, g:  0.6, b:  0.4, a:  1.0, s: 0.50, t: 0.50, nX: 0.0, nY: -1.0, nZ: 0.0)
 
//Back
let U = Vertex(x:  1.0, y:   1.0, z:  -1.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0, s: 0.75, t: 0.25, nX: 0.0, nY: 0.0, nZ: -1.0)
let V = Vertex(x:  1.0, y:  -1.0, z:  -1.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0, s: 0.75, t: 0.50, nX: 0.0, nY: 0.0, nZ: -1.0)
let W = Vertex(x: -1.0, y:  -1.0, z:  -1.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0, s: 1.00, t: 0.50, nX: 0.0, nY: 0.0, nZ: -1.0)
let X = Vertex(x: -1.0, y:   1.0, z:  -1.0, r:  0.1, g:  0.6, b:  0.4, a:  1.0, s: 1.00, t: 0.25, nX: 0.0, nY: 0.0, nZ: -1.0)

This adds a normal to each vertex.

If you don’t understand those normal values, try to sketch a cube on a piece of paper, and for each vertex write its normal vertex value. You will get the same numbers as me!

To think about it, it really makes sense, all vertices that are on the same face, have the same normal values.

Build and run, and you’ll see the following:

IMG_4277

Woooooooooooow!

giphyad

If glitches like this are not a good reason to learn 3D graphics, then what is? :]

Do you have any idea what went wrong?

Passing the Normal Data to the GPU

At this point your vertex structure includes normal data, but your shader does not expect this data.

Therefore, the shader reads position data for next vertex where normal data from the previous vertex is stored. That’s why you end up with this weird look.

To fix this, open Shaders.metal. In VertexIn structure, add this below all the other components:

packed_float3 normal;

Build and run. Voila! Cube looks just like expected.

IMG_4278

Adding Diffuse Lighting Data

Right now Light structures don’t have all needed data for diffuse lighting, so let’s go add some.

In Shaders.metal, add two new values to the bottom of the Light structure:

packed_float3 direction;
float diffuseIntensity;

Now open Light.swift and add these properties below ambientIntensity:

var direction: (Float, Float, Float)
var diffuseIntensity: Float

Also modify the methods to look like this:

static func size() -> Int {
    return sizeof(Float) * 8
}
 
func raw() -> [Float] {
    let raw = [color.0, color.1, color.2, ambientIntensity, direction.0, direction.1, direction.2, diffuseIntensity]
    return raw
}

Nothing fancy, you’ve just added two properties, used them when getting the raw float array and increased the size value.

Next open Node.swift and add modify the light constant to match this:

let light = Light(color: (1.0,1.0,1.0), ambientIntensity: 0.2, direction: (0.0, 0.0, 1.0), diffuseIntensity: 0.8)

The direction that you pass (0.0, 0.0, 1.0) is a vector pointing perpendicularly to the screen. This mean that light is pointing the same way as the camera. You also set the diffuse intensity to a largish amount (0.8).

Adding the Diffuse Lighting Calculation

Now let’s actually use the normal data. Right now you have normal data in the vertex shader, but you need the interpolated normal for each fragment. So you need to pass normal data to VertexOut.

To do this, open Shaders.metal and inside VertexOut add this below the other components:

float3 normal;

Then in the vertex shader find this line:

VertexOut.texCoord = VertexIn.texCoord;

…and add this right below:

VertexOut.normal = (mv_Matrix * float4(VertexIn.normal, 0.0)).xyz;

This way you will get normal value for each fragment in a fragment shader.

Now in the fragment shader, add this right after the ambient color part:

//Diffuse
float diffuseFactor = max(0.0,dot(interpolated.normal, light.direction)); // 1
float4 diffuseColor = float4(light.color * light.diffuseIntensity * diffuseFactor ,1.0); // 2

Let’s discuss this line by line:

  1. Here you calculate diffuse factor. There is some math involved, so let’s go through it from right to left:
    1. You take dot product of fragment normal and light direction.
    2. As discussed previously this will return value from -1 to 1, depending on angle between the two normals.
    3. You need this value to be capped from 0 to 1, so you use max function to force any negative value into 0.
  2. Here’s how you get diffuse color, you multiply light color with diffuse intensity and diffuse factor. You also set alpha to 0 and make it float4 value.

Almost done, change the last line in fragment shader from:

return color * ambientColor;

…to:

return color * (ambientColor + diffuseColor);

Build and run, and you’ll see the following:

IMG_4279

Looking good, eh? For even better look, find this line in Node.swift:

let light = Light(color: (1.0,1.0,1.0), ambientIntensity: 0.2, direction: (0.0, 0.0, 1.0), diffuseIntensity: 0.8)

And change the ambient intensity to 0.1:

let light = Light(color: (1.0,1.0,1.0), ambientIntensity: 0.1, direction: (0.0, 0.0, 1.0), diffuseIntensity: 0.8)

Build and run again and there will be less ambient light, making the diffuse effect more noticeable:

IMG_4281

As you can see, the more face is pointed toward the light source, the brighter it becomes.

LikeABoss

Specular Lighting Overview

Specular lighting is the third and final component of the Phong lighting model.

Remember you can think of this component as the one that exposes shininess of objects.
This is kind of like when light falls on metallic objects, you can see a small extremely shiny spot.

You calculate the specular color in a similar fashion to how you calculate the diffuse color:

SpecularColor = LightColor * SpecularIntensity * SpecularFactor

Specular intensity, just like diffuse and ambient intensity, is the value which you can modify to get that perfect look that you want.

The real question is, what is Specular factor? For that, have a look at the following picture:

37_a

This illustration you have a light ray that hits a vertex. The vertex has a normal (n), and the light reflects off the vertex in a particular direction (r). The question is: how close is that reflection vector to the vector that points toward the camera?

  1. The more this reflected vector is pointed towards the camera, the more shiny you want this point to be.
  2. The farther this vector is from the camera the darker the fragment should become, and unlike diffuse lighting you want this to happen fairly quickly, to get this cool metallic effect.

To calculate SpecularFactor you use our good buddy dot product:

SpecularFactor = - (r * eye)shininess

After you get the dot product of reflected vector and eye vector, you raise it to a new value – shininess. Shininess is a material parameter – for example wooden objects will have less shininess than metallic objects.

Adding Specular Lighting

Adding Specular Lighting Data

First things first, open Light.swift and add two properties below the others:

var shininess: Float
var specularIntensity: Float
Note: Shininess is not a parameter of light, it’s more like a parameter of object material. But for the sake of this tutorial you will keep it simple and pass it with Light.

As always, don’t forget to modify the methods to include the new values:

static func size() -> Int {
    return sizeof(Float) * 10
}
 
func raw() -> [Float] {
    let raw = [color.0, color.1, color.2, ambientIntensity, direction.0, direction.1, direction.2, diffuseIntensity, shininess, specularIntensity]
    return raw
}

Now in Node.swift change the light constant value to this:

let light = Light(color: (1.0,1.0,1.0), ambientIntensity: 0.1, direction: (0.0, 0.0, 1.0), diffuseIntensity: 0.8, shininess: 10, specularIntensity: 2)

Now open Shaders.metal and add this to its Light structure:

float shininess;         
float specularIntensity;

Build and run.

ragecomic

Crash?!

Byte Alignment

The problem you faced is a bit complicated, so listen carefully. In Light structure size method returns 10 * sizeOf(Float) = 40 bytes.

In Shaders.metal, Light structure shuld also be 40 bytes, because that’s exactly the same structure. Right?

Right, but that’s not how GPU works. GPU operates with memory chunks with size 16 bytes.

Replace Light structure in Shaders.metal with this, for some illustration:

struct Light{
  packed_float3 color;      // 0 - 2
  float ambientIntensity;          // 3
  packed_float3 direction;  // 4 - 6
  float diffuseIntensity;   // 7
  float shininess;          // 8
  float specularIntensity;  // 9
 
  /*
  _______________________
 |0 1 2 3|4 5 6 7|8 9    |
  -----------------------
 |       |       |       |
 | chunk0| chunk1| chunk2|
  */
};

Even though you have 10 floats, GPU is still allocating memory for 12 floats. And you have a mismatch sizes error.

All you need to do to fix this crash is to increase the Light structure size to match those 3 chunks (12 floats).

Open Light.swift and change the size() method to return 12 instead of 10:

static func size() -> Int {
  return sizeof(Float) * 12
}

Build and run. Everything should be working OK.

IMG_4281

Adding the Specular Lighting Calculation

Now that you have the data passed through, it’s time for the calculation itself.

Open Shaders.metal, and add the following value to the VertexOut struct, right below position:

float3 fragmentPosition;

And in the vertex shader find this line:

VertexOut.position = proj_Matrix * mv_Matrix * float4(VertexIn.position,1);

…and add this line just below it:

VertexOut.fragmentPosition = (mv_Matrix * float4(VertexIn.position,1)).xyz;

This new value “fragment position” does just what it says, it’s a fragment position related to a camera. You will use this value to get the eye vector.

Now add the following under the diffuse calculations in the fragment shader:

//Specular
float3 eye = normalize(interpolated.fragmentPosition); //1
float3 reflection = reflect(light.direction, interpolated.normal); // 2
float specularFactor = pow(max(0.0, dot(reflection, eye)), light.shininess); //3
float4 specularColor = float4(light.color * light.specularIntensity * specularFactor ,1.0);//4

This is the same algorithm you learned about earlier:

  1. Get the eye vector.
  2. Calculate reflection vector of the light across the current fragment.
  3. Calculate the specular factor.
  4. Combine all the values above to get the specularColor.

Now with specular color, modify return line in fragment shader to match:

return color * (ambientColor + diffuseColor + specularColor);

Build and run.

IMG_4282

Enjoy your new shiny object!

Where To Go From Here?

Here is the final example project from this iOS Metal Tutorial.

Nicely done. Take a moment to review what you’ve done in this tutorial.

  1. You created a Light structure to send with matrices in uniform buffer to the GPU.
  2. Modified BufferProvider class to handle Light data.
  3. You implemented ambient lighting, diffuse lighting, and specular lighting.
  4. You learned how GPU handles memory, and fixed the crash.

Now go for a walk or take a nap – you totally deserve some rest! :]

Don’t feel tired? We hope to make more Metal tutorials in the future, but in the meantime, be sure to check out some of these great resources:

Also tune into the OpenGL ES video tutorials on this site, and learn as Ray explains — in depth — how many of these same concepts work in OpenGL ES.

Thank you for joining me for this tour through Metal. As you can see, it’s a powerful technology that’s relatively easy to implement once you understand how it works.

If you have questions, comments or Metal discoveries to share, please leave them in the comments below!

The post iOS Metal Tutorial with Swift Part 4: Lighting appeared first on Ray Wenderlich.

Video Tutorial: How to Make a Game Like Flappy Bird in Swift: Series Introduction

Video Tutorial: How to Make a Game Like Flappy Bird in Swift Part 1: Getting Started

Video Tutorial: How to Make a Game Like Flappy Bird in Swift Part 2: Moving the Background

Sketch Tutorial for iOS Developers

$
0
0

Sketch for OS X

As an iOS developer, I’ve worked on a few projects without a designer, and let me tell you – it can be tough.

But one thing I’ve learned though these types of projects: even if you’re working without a designer, design is important – especially iterating on design.

Let’s face it, clients don’t always know exactly what they want. Jumping straight into Xcode before they figure it out usually ends with massive frustration and lots of beautiful code being thrown away.

The safer approach? Nail down the spec first by iterating on design mockups rather than code.

But how can you design without a designer?! Well, one great option is Sketch.

Sketch is a great tool for creating logos and custom icons. It’s vector-based, which means you can resize without losing quality. Since it includes iPhone device-sized Artboards and a built-in UIKit Template, you can also use Sketch to create mockups for design iteration. Plus, Sketch is simple enough for a busy developer to pick up quickly.

In this tutorial, you’ll learn how to:

  • Create a mockup using the UIKit Template.
  • Create icons using the Vector Tool.
  • Create icons by combining basic shapes.
  • Export image assets for Xcode.

And best of all, you’ll be able to follow along even if you’re a developer like me. Get ready to level up your design skills!

delete

Getting Started

First things first, you’ll need Sketch. Download the 14-day trial at www.sketchapp.com. License activation costs $99.

Once you have Sketch installed, open Sketch, and sit back, relax, and get ready for a grand tour!

In the sections that follow, I’ll give you a tour of the various UI elements in Sketch and will challenge you to make various items. Note that everything you make is just for learning purposes; after you make it, you can safely delete it as you won’t need it later in the tutorial.

Let’s begin the tour!

Templates

The iOS UI Design template is a collection of UIKit components in vector format. It has a Tab Bar, Nav Bar, Table View, and more. You can use this as a springboard for creating mockups.

Let’s try this out. Select to File\New From Template\iOS UI Design, and you’ll see the following:

Creating a new iOS UI Design template in Sketch

Notice there’s a Material Design option for the Android folks.

You’ll see a huge template with various iOS UI Components. You can move around the canvas by holding space and clicking to drag, and you can zoom by holding command and using your mouse wheeel.

Artboards

You can draw anywhere you want on Sketch’s infinite canvas, but if you’re mocking up an app with multiple screens, you’ll want to use Artboards. An Artboard organizes layers inside a fixed frame. When you export the Artboard, all the layers inside get combined into a single file. Think of them as View Controller Scenes in a Storyboard.

Let’s try this out. Perform the following steps to create a new Artboard:

  • Hold space and drag until you have a clear area of canvas on the screen.
  • Click the Insert button and select Artboard from the list.
  • In the right pane, choose iPhone 6.
Note: This image and some of the other images in this article are from an older version of the iOS UI template. Although the locations of the UI elements may be in a different spot, the instructions in this tutorial still apply.

artboard

You should see a blank Artboard called “iPhone 6” in portrait mode. By default, a newly created Artboard will envelop any free-floating elements it overlaps. If this isn’t your intention, first pan to a clear area of the canvas.

You can add as many Artboards as you like. Sketch has sizes for iPhone, Apple Watch, and even the iPad Pro. If you ever need to get rid of an Artboard, just click on the title and hit delete.

Note: If you need an artboard of an arbitrary size, you can simply go to Insert\Artboard and then drag a box of an arbitrary size in your canvas.

Copy and Paste

Now that you have an Artboard, drag in a few items from the UIKit template. Start with a Navigation Bar, Tab Bar, and a Table View Cell.

Although you can copy and paste (⌘C and ⌘V) with Sketch, it’s hard to predict where the pasted item is going to end up. Instead, Option-Drag an item, and your copy always ends up where you let go of your mouse.

steal-from-template

Pro tip: The keyboard shortcut ⌘D duplicates the previous action. Option-Drag with ⌘D is a useful combo for creating multiple copies:

  • Option-Drag a Table View Cell directly beneath itself.
  • Spam ⌘D to create the rest of the cells.

Basic Shapes

First, create a new artboard to work with by clicking Insert\Artboard and drawing a square somewhere in the canvas.

Now, let’s make some shapes! Click Insert\Shape to see a menu of available options.

shape-options

In practice, it’s a lot easier to use the keyboard shortucts. Create an oval by typing the letter O and dragging your mouse across the screen. Do the same with R and you’ll make a rectangle. The most common shapes have their own keyboard shortcut:

  • L: Line
  • O: Oval
  • T: Text
  • R: Rectangle

See if you can use what you’ve learned to make this robot (note you may have to change your font settings to get this same look):

smiley-robot

Note: Hold down Shift as you drag in order to make proportional shapes like squares and circles.

Styling a Shape

Shapes are all well and good, but the client won’t be impressed unless those shapes are pretty! You can use the Inspector on the right to change the properties of a layer, like color and border radius. Think of it like the Attributes Inspector in Xcode.

style-options

Here are some options you’ll be using in this tutorial:

  • Position/Size: When it’s difficult to drag to the correct spot using the mouse, type in the exact number. Click the lock icon to keep icons proportional.
  • Radius: This is a slider for adjusting the corner radius of a rectangle.
  • Opacity: This is useful for tracing images. More on this later!
  • Fills: Use the color picker to change the layer’s fill color, or uncheck the box for a transparent fill.
  • Borders: Set the thickness and color of the border, or disable it entirely.

Pro tip: Sketch has a built-in color dropper you can activate using Control-C. Not only does it work outside of the Sketch window, it will automatically set the color of the currently selected shape.

color-picker

Two of the icons in this tutorial use a pill shape as a building block. Try creating one for yourself by styling a rectangle:

  • Make a rectangle using the R keyboard shortcut.
  • Round the corners by setting the Radius to a large value like 100

pill-shape

You can also try changing some of the other settings, as mentioned above.

Layer List

The Layer List in the left pane contains all the layers in your file. Layers that appear higher in the list overlap the ones below. Think of it as the View Hierarchy in the Storyboard.

Groups organize layers logically. You can move multiple layers as a unit if they are Grouped together. You can also export a Group of layers as a single image. In the Layer List, Groups are represented as folder icons.

Here’s a list of common shortcuts for managing the Layer List:

  • ⌘G: Group multiple shapes together. Use ⌘-Shift-G to ungroup.
  • ⌘R: Rename the selected item.
  • ⌘-Option-Up/Down: Move an item up or down in the Layer List.
  • ⌘-Shift-L: Lock a layer in place so it becomes unclickable. This is useful in the next section.

layer-list

Pro tip: It’s good practice to rename layers to something meaningful, like “Tab Bar.” As it gets buried underneath other layers, you can easily find it in the Layer List. Then you can use ⌘-Option-Up to bring it to the forefront. Try not to use drag-and-drop to rearrange layers because you might wind up combining them unintentionally. Trust me, it happens!

Try grouping some of the layers you added to your iPhone mockup, and give them a descriptive name.

Vector Tool

Drawing circles, squares, and lines is fun, but pretty limiting. But with the Vector Tool, you can make any shape you want!

Shapes With Straight Lines

You can create any polygon just by clicking: the spots where you click become the corners of a shape.

Let’s make a polygon:

  1. Type V to activate the Vector Tool.
  2. Start clicking the corners of a trapezoid.
  3. Close the shape by clicking on the starting point.
  4. Click the Edit button, and drag individual vector points around to reposition them.
  5. Add a Fill color.
  6. Remove the Border.

trapezoid

Thankfully, since Sketch lets you reposition each vector point after the fact, you don’t need to have great drawing skills to use the Vector Tool. The mouse also snaps to the red guidelines as you drag.

Rotate Copies

A simple trapezoid might not look like much, but you can use it to derive other shapes using the Rotate Copies feature. Rotate Copies creates multiple copies of your shape and fans them out in a circle, like the petals of a flower. Let’s try it:

  1. Select Layer\Paths\Rotate Copies.
  2. Type in 3 copies (counting the original shape, you’ll end up with 4 total).
  3. Drag the white dot, which represents the center of the circle, to create icons like a bank logo, a shuriken, or a pinwheel.

rotate-copies

Sketch automatically combines your rotated copies into a single shape. This tutorial will cover shape combination in a later section.

Scissors

Right above Rotate Copies is a menu option called Scissors. There’s a neat trick where you can create a WatchKit activity ring using the Scissors tool:

  1. Create a circle (remember, use the O key and hold Shift and click to drag a circle).
  2. Remove the Fill.
  3. Increase the Border thickness to 25.
  4. Select Layer\Paths\Scissors.
  5. Snip open the circle by clicking the top left portion.
  6. Next to Borders, click the Gear button to reveal a popup menu.
  7. Select the rounded ends option.

watchkit-ring

Notice that a circle is really just a vector path made up of four points, and that vector paths can be open like the arc of a circle.

Pro tip: You can make the ring any length by adding an additional point to the circle before you snip. To do so, click the Edit button and single-click anywhere along the circle’s path.

Modes and Handles

Sketch represents a circle using four vector points. You can see this by drawing a circle, and then clicking Edit in the toolbar.

But wait a minute — a rectangle also has four vector points. What’s going on? The difference between the two is in the use of Bezier Curves.

circle-vector-points

Bezier Curves are lines you can bend into curves using control points. Sketch calls these control points handles. Each vector point comes with two handles that control the curvature on each side. This means that the curve of a line is determined by the handle at each of its ends. This isn’t as complicated as it sounds: in Sketch, you simply drag the handles until the curve looks good.

Sketch defines four different Modes based on the relative handle positions on a vector point.

vector-modes

  • Straight: The handles are retracted into the vector point, as if they didn’t exist. No handles means no curvature.
  • Mirrored: The handles are the same length and form a straight line, like the wings of an airplane. Use this to create symmetric curves.
  • Asymmetric: The handles form a straight line, but they can be different lengths.
  • Disconnected: The handles are positioned independent of one another.

In practice, making curves is pretty simple. Just double-click on a vector point and click on Disconnected. Then you futz with each handle like the rabbit ears of a TV antenna until the curve looks right.

To learn more about modes and handles, this article is a great resource.

Bezier Curve Theory

You don’t really need to know the math behind Bezier curves in order to use the Vector Tool — I sure don’t! :] But I have a non-math analogy that helps me understand how the computer is drawing this stuff on screen.

Imagine a grand slam in baseball, but the umpire isn’t looking and the runners are cutting corners. Keep an eye on the red path.

bezier

First base and home plate represent vector points. Second and third represent handles. The path from first base to home plate is the Bezier curve.

bezier-curve

Again, you don’t need to understand how Bezier curves work in order to use them, but if you’re interested, there’s an interactive visualization tool that simulates how the computer draws these things.

Vector Handles In Action

Enough mathing. Let’s use our new skills to create a map marker icon:

  1. Create a circle.
  2. Increase the Border thickness to 15.
  3. Click the Edit button and select the bottom vector point.
  4. Change the mode from Mirrored to Straight.
  5. Drag the bottom point downward to stretch it out.
  6. Drag the Corners slider to 35 to round out the corner.

map-marker

The map marker shape is really just a circle with a corner as one of its points. Easy! You’ll revisit the map marker icon later on in the tutorial.

Creating Custom Icons

When coming up with a logo idea, it’s easiest to prototype with pencil and paper or use an online image as a starting point. Then you can trace the picture using the Vector Tool.

In this example, you will be recreating the Ray Wenderlich logo.

  1. Rip a low-res version of the Ray Wenderlich logo right off the internet.
  2. Drag and drop the logo into Sketch.
  3. With the image selected, use the inspector to reduce the Opacity to 20% so it’s easier to trace.
  4. Lock the layer using Command-Shift-L so you don’t accidentally drag it around. You should see a lock icon next to the layer name.
  5. Type V to activate the Vector Tool.
  6. Click on all the corners of the logo. You don’t need to click on the curve of the “R,” but do click the first corner again at the end to close the vector path.
  7. Double-click anywhere along the path to Edit.
  8. Reposition any points that are off the mark. You can pinch to zoom-in to get it pixel perfect.

rw-logo-corners

To create the curve of the “R,” you’re going to put all your knowledge of vector point Modes to good use.

  1. Double-click the top-left corner, and it will turn from Straight to Mirrored.
  2. Change it to Disconnected.
  3. Stretch the curved-facing handle out toward the right.
  4. Tuck the other handle into the vector point.
  5. Find the vector point on the other end of the “R” curve and double-click it.
  6. Again, change it to Disconnected and drag the handles around. You might have to switch back and forth between both points of the curve before you get it right.

rw-logo-disconnected

Luckily, the RW logo only has a single curve. You can still use this approach for more complex logos — you just have more curves to deal with. The project you’ll download later includes a rough attempt at the Swift bird logo. I’m using Tab to cycle through each vector point to show the handle positions.

swifty-bird

Combining Shapes

Have you ever played that game Tangoes where you combine plastic triangles to form a rabbit shape? Previously, we covered creating icons using the Vector Tool, but another approach is to combine basic shapes.

In programming, you have Logical Operators AND, OR, and XOR. Sketch has something similar called Boolean Operators, but uses different terminology like Union, Subtract, Intersect, and Difference.

Union

Union adds shapes together. Let’s use this to combine a pill and circle shape to form a cloud.

  1. Create a pill shape by maxing out the Radius on a rectangle.
  2. Create a circle.
  3. Move the circle so that it overlaps the pill.
  4. Select both images, and click the Union button.

cloud

Notice how the outlines of the two shapes meld together. Voila! A cloud :]

Subtract

Subtract uses one shape to cut a hole out of another, like a cookie cutter.

The map marker from our previous example looks OK, but all the cool kids nowadays put a donut hole inside their map markers. You can do the same using the Subtract button:

  1. Create a map marker icon, but this time make sure Border is unchecked.
  2. Create a small circle and drag it onto the map marker.
  3. In the Layer List, drag the circle layer onto the map marker layer to combine the shapes.
  4. Expand the disclosure triangle on the newly combined shape.
  5. Make sure the hole layer is above the map marker layer.
  6. Click the boolean-operator icon to the right of the layer name to reveal a pop-up menu.
  7. Select Subtract from the menu.
  8. Select the donut hole sublayer and use the arrow keys to fine-tune its position.

map-marker-hole

Whew! Subtraction sure is complicated. But there are a few important concepts to take from this example:

  • You can drop layers on top of others within the Layer List to combine them. How cool is that?
  • When you combine the shapes, Sketch makes an educated guess about which operator you intended to use. If you see the None option selected, Sketch is picking one automatically.
  • For subtraction, order matters. Make sure the hole layer is always on top. If your shapes disappear, try rearranging the sublayers in the Layer List.

Fill vs. Outline

For this part of the tutorial, you’ll need a starter Sketch file I’ve prepared for you and double click it to open it. You should see the following:

finished-artboard

This starter file includes a one-page mockup and custom vector icons – feel free to review them to see how they were made. There are also some before-and-after Artboards, including a few for tab bar icons which you’ll use in this section.

Tab Bar icons change color based on the selected state, but some icons have a lot of empty space, so the color change is too subtle. In these situations, the Apple Human Interface Guidelines recommend using a separate filled version of the icon as the selectedImage. The mockup of the RWDevCon app has both a filled and outline version of each Tab Bar icon.

fill-vs-outline

In the Sketch project file you downloaded earlier, there’s an Artboard called Calendar Starter which contains several building blocks that you’ll combine into a calendar icon. These building blocks are just rectangles and pills, which you already know how to make.

To create the filled calendar icon:

  1. Open the Sketch file and expand the Calendar Starter Artboard in the Layer List.
  2. Select the Calendar Body and Separator sublayers.
  3. Press Subtract.
  4. Shift-select the Right Hole layer and Subtract it from the above shape.
  5. Also Subtract the Left Hole layer.
  6. Shift-select the Right Ring layer and click Union.
  7. Add the Left Ring layer using Union.

calendar-fill

You should end up with a single shape that contains all the sublayers of the calendar-fill icon. Everything should be green except for the subtracted areas, which should be clear. If you run into any issues, use the Calendar Fill Artboard directly beneath for comparison.

Now that you have a filled icon, it’s time to create an outline version by resizing one of the sublayers.

  1. Find the Calendar Fill Artboard on the canvas.
  2. Expand the Calendar Fill Artboard in the Layer List.
  3. Expand the Calendar Body layer and select the Separator layer.
  4. Increase the Separator height to 35.

calendar-outline

All it took to create the outline version of the calendar icon was to turn the separator line into a square. If Sketch doesn’t let you drag to the exact height, you can just type the number into the Inspector instead.

Round Profile Avatars

The RWDevCon mockup has round profile pictures of each speaker. To achieve this effect, you’ll use the Mask feature, which is very similar to Subtract. But rather than cutting a hole, Mask trims the outside of a shape like the crust off of a peanut butter and jelly sandwich.

Let’s create an avatar:

  1. Expand the Greg Before Artboard in the Layer List.
  2. Inside this Artboard, create a circle big enough to cover his face.
  3. Select both the greg layer and the oval layer you just created.
  4. Make sure the mask layer (in this case, the oval) is on the bottom.
  5. Click the Mask button.
  6. Expand the newly combined greg layer and select the Mask layer.
  7. Add a Border, and use the arrow keys to adjust the position.

greg-mask

Make sure the masking layer is on the bottom. This is the opposite of Subtract, where the hole goes on top.

Image Export

You can export a single layer by clicking Make Exportable near the bottom right of the screen.

If you want to export multiple layers, there are a couple ways to do this:

  • Group: When layers are grouped together, you can export the Group as a single image.
  • Artboard: All the layers inside the Artboard are exported as a single image. The image size is based on the Artboard frame.

Before you export, check the Width and Height in the Inspector. These dimensions determine the @1x size of your image export.

Pro tip: Rather than resizing shapes using the bottom-right corner, use the Scale button. Scale ensures style properties like border width and corner radius remain proportional after resizing.

scale

PNG

Sketch makes it easy to export images in different densities:

  1. On the bottom right, click on Make Exportable.
  2. Click the Plus button to add a @2x copy.
  3. Click the Plus button again to add a @3x copy.
  4. Click the Export button to save the PNG files to disk.

exporting

PDF

You’re probably used to creating @2x and @3x versions of every image, but Sketch is vector-based, so take advantage of that. Xcode accepts vector images in PDF format, which is like SVG but with size information.

  1. Click on Make Exportable.
  2. Keep the size at 1x.
  3. Select PDF as the Format, and click Export.

export-pdf

You can import this single PDF icon into the Asset Catalog.

  1. Within Xcode, open Images.xcassets.
  2. Create a New Image Set.
  3. In the Attributes Inspector, change Scale Factors from Multiple to Single Vector.
  4. Drop your PDF icon into the All image slot.

scale-factors

Xcode will generate the appropriate @2x and @3x PNG files for you at build time. You still end up with PNGs, so the benefit is managing fewer image files.

Where To Go From Here?

And that’s our intro to Sketch! You can download the Sketch project file here.

Sketch is powerful, with a lot of great features beyond what’s covered in this tutorial. To learn more, check out the official documentation. There are also blogs and videos for learning tips and tricks.

Finally, you can also download Sketch files that contain icon sets and vector images of iOS devices.

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

The post Sketch Tutorial for iOS Developers appeared first on Ray Wenderlich.

Video Tutorial: How to Make a Game Like Flappy Bird in Swift Part 3: Adding the Player

Readers’ App Reviews – January 2016

$
0
0

reviews_thumb

Its a new year, and that means new apps!

The holidays certainly didn’t slow down our community. I came back from Christmas with an inbox full of apps, so I downloaded them all and picked a few I’d like to highlight this month.

Did you know that I receive on average an app a day from raywenderlich.com readers? Unfortunately, I don’t have time to write about every app that comes my way, but hopefully this will be a small showcase of what the community has been working on.

This month we have:

  • A supercharged browser history
  • A camera app to protect your memories
  • Games to ring in the new year
  • And of course, much more!

Keep reading to see the first apps released by raywenderlich.com readers this year!

Fetching

fetching
Fetching supercharges your browser history by not only storing the addresses you’ve visited but also the content.

Fetching saves a cached copy of each webpage you visit to ensure a full history remains. It features powerful search of not just the title but the entire content of the webpage.

You’ll never need to retrace your steps again when looking for a website from last week. Just type a few words you remember and it will pop up instantly.

And best of all, if the public website changes between the first and second time you view it, your cache will show exactly what you saw. Very useful for constantly changing websites. Catch the black Friday deal changes in the act! ;]

Fetching also offers blacklists to prevent certain sites like your banks or other sensitive information from being cached. They also offer both Mac and Cloud versions of the service. The Mac version of course can be backed up and encrypted like any other Mac files. While the Cloud version offers the benefit of working cross platform.

Chain Quest

ChainQuest
Combine the addictive nature of match three games with leveling up and battle. Thats right, you get an extremely addicting game called Chain Quest.

Chain Quest plays like a match 3 game or more specifically a chain matching game. But you’re not just clearing game tokens. You’re battling an enemy! You and your enemy take turns clearing the board. Each type of game token you clear does something unique. Some boost your magic levels. Some attack your enemy. Others build up your shield.

You can also unlock monsters and potions to help you win. As you clear game tokens your potions will brew and monsters will come alive. Your monster has a power it can use on your turn. It could be an attack against your enemy or a constant boost to your shield. Your potions and monster combinations are all part of the strategy. Build your own combo for ultimate power.

Reporter Camera

ReporterCamera
Reporter Camera is a powerful camera app that has all the bells and whistles plus one: encryption. Reported Camera can encrypt photos from your gallery or right as you take them within the app to protect your photos from prying eyes. All it takes is a simple PIN to start encrypting sensitive photos.

Reporter Camera also has the standards like exposure control, temperature balance settings, framing guides, and of course filters.

You can also sign your work with an automatic signature. Just sign your name once and it can be attached to all your photos automatically giving your photography a little extra professionalism.

Archer’s Revenge

archerrevenge
A rampant army of orcs is descending upon your village and you’re their only hope!

Archer’s Revenge is a game perfect for iOS. Great physics work exactly as you expect. Just drag the bowstring and release! You can volley your enemy or go for the straight shot. Go toe to toe with enemy archers or shoot down advancing orcs.

There are more than 30 unique levels protecting your village. You can choose between three characters each with advantages on power, recovery time, or health. Save up your gold and there are new bows available offering better distance or faster rate of fire.

Gallus Gallus

Gallusgallus
Mutated chicken eggs are in Earth’s lower atmosphere and could plummet down at any moment! Elon Musk can’t save us this time; its up to you!

Gallus Gallus is a unique puzzle and physics game thats one part skill and one part logic. There are over 120 hand crafted levels packed with debris, patterns, and challenges. Your mission is to steer the last escape pod, using your limited remaining Newtonian Pulses, to capture the mutated eggs of the Space Station’s test chicken Clux.

Tapping behind the escape pod will trigger a Newtonian Pulse sending the pod flying. Avoid rocks, satellites, and other obstacles as you collect the eggs. You’ve got limited propulsion so you’ll need to find the most efficient route to capture all the eggs in each level. It will take some reflexes to ensure your pod doesn’t jettison into deep space!

Home Workout – 7 Minute Workout

HomeWorkout
That New Year’s resolution not going quite as you hoped? Maybe Home Workout can help.

Home Workout takes the now ubiquitous 7 minute workout and wraps it in an easy to use iOS app. Home Workout packs nice illustrations and instructions to help you learn the exercises before you start. None of the exercises in the workout require equipment so all you need is the app!

Home Workout also uses Voice Over to make your workout app hands free. It will countdown for you and read out the next exercise so you can focus on working out while it focuses on keeping track. It has some achievements to help you set goals. And if you’re too busy for a 7 minute workout you can just get your heart beating with a 3 or 5 minute workout.

Remed – Remember Taking Your Medicine

Remed
Do you take daily or weekly medication or vitamins? Do you even forget to take your pills for short term stints to clear up a cold? Remed can help.

Remed will help you remember to take your medicine on the proper schedule and with the proper doses. Just enter each of your medications and their dosage into Remed. Then use the scheduler to set your schedule be it twice daily or once weekly. Remed will take care of the rest.

You’ll get a push notification when its time to medicate. Best of all using iOS’s activity notifications Remed allows you to mark your meds as taken right from the notification. No need to unlock your device and find the app.

As you use Remed, the app will keep track of how you’ve been doing staying on schedule. You’ll be able to get a list of medicine you’ve taken or missed.

Mobs & Potions

MobsPotions
Mobs & Potions is a simple yet addicting game.

You are presented with cards one at a time. The controls are simple swipe right to attack, swipe left to use it. You might swipe right on a rat, or ice goblin, or giant with a club. You’ll swipe left on health potions and coin bonuses. Your health is constantly dropping. Health potions buy you some time while failures to attack lose you some time.

Use your coins between battles to buy equipment. There are health rings to boost your health or slow down the rate it drains. There are multiplier rings to give you bonus points when you swipe correctly for a stretch. And of course much much more.

plusclock Calc

plusclockcalc
There are two mode of input on the Apple Watch: touch and the digital crown. The digital crown is extremely easy to spin precisely. Touch is useful but only as long as the targets are large enough.

Most calculator apps are plagued by having too much input to fit comfortably on the Apple Watch. Enter plusclock Calc.

This app uses the digital crown to slide between buttons. Then you can simply tap the screen to select the highlighted button. Its also easy to backspace, just tap the right side of the input box. And you can clear the entire display by tapping the left of the input box.

Its certainly a unique design taking advantage of both Apple Watch input methods!

Golden House

goldenhouse
You sister is lost in a haunted house and needs your help!

Gold House is a retro platformer made for your iPhone. Its exactly what you’d expect with the classic left/right and jump button layout. You can double jump as well as wall jump which makes for some pretty cool interactions.

There are of course tons of enemies and obstacles between you and your sister. Everything from classic spikes to spinning blades to zombies.

There are 6 worlds and 48 levels with more to come. And of course it wouldn’t be complete without a retro chiptune soundtrack. What are you waiting for? Your sister needs help getting out of this haunted house!

Honorable Mentions

Every month I get way more submissions than I have time to write about. I download every app to try them out, but only have time to review a select few. I love seeing our readers through the apps submitted to me every month.

It’s not a popularity contest or even a favorite picking contest — I just try to share a snapshot of the community through your submissions. Please take a moment and try these other fantastic apps from readers like you.

Slow Maddie
Pyramid Stack
Grabble Words!
ProtoZoah!
Life – Moments for every mood
Slime Sports
The Shopping List App
Spiral Painter
Parcheesi FullHD
Busy Suby

Where To Go From Here?

Each month, I really enjoy seeing what our community of readers comes up with. The apps you build are the reason we keep writing tutorials. Make sure you tell me about your next one, submit here.

If you saw an app your liked, hop to the App Store and leave a review! A good review always makes a dev’s day. And make sure you tell them you’re from raywenderlich.com; this is a community of makers.

If you’ve never made an app, this is the month! Check out our free tutorials to become an iOS star. What are you waiting for – I want to see your app next month.

The post Readers’ App Reviews – January 2016 appeared first on Ray Wenderlich.


Video Tutorial: How to Make a Game Like Flappy Bird in Swift Part 4: Spawning Obstacles

Video Tutorial: How to Make a Game Like Flappy Bird in Swift Part 5: Physics Bodies & Collision Detection

Swift Tutorial: Working with JSON

$
0
0

JSON tutorial

Update 12/21/2015: Updated for Xcode 7.1 and Swift 2.0.

JavaScript Object Notation, or JSON for short, is a common way to transmit data to and from web services. It is simple to use and human-readable, which is why it’s so incredibly popular.

Consider the following JSON snippet:

[
  {
    "person": {
      "name": "Dani",
      "age": "24"
    }
  },
  {
    "person": {
      "name": "ray",
      "age": "70"
    }
  }
]

In Objective-C, parsing and deserializing JSON is fairly straightforward:

NSArray *json = [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:nil];
NSString *age = json[0][@"person"][@"age"];
NSLog(@"Dani's age is %@", age);

In Swift, parsing and deserializing JSON is a little more tedious due to Swift optionals and type-safety:

var json: Array!
do {
  json = try NSJSONSerialization.JSONObjectWithData(JSONData, options: NSJSONReadingOptions()) as? Array
} catch {
  print(error)
}
 
if let item = json[0] as? [String: AnyObject] {
  if let person = item["person"] as? [String: AnyObject] {
    if let age = person["age"] as? Int {
      print("Dani's age is \(age)")
    }
  }
}

In the code above, each object from the JSON must be checked before you use it via optional binding. This makes your code safe; but the more complicated your JSON is, the more ugly your code becomes.

As part of Swift 2.0 the guard statement was introduced to help get rid of nested if statements:

guard let item = json[0] as? [String: AnyObject],
  let person = item["person"] as? [String: AnyObject],
  let age = person["age"] as? Int else {
    return;
}
print("Dani's age is \(age)")

Still too verbose, isn’t it? But how could you make it simpler?

In this JSON tutorial, you’re going to learn an easier way to parse JSON in Swift – using a popular open source library called Gloss.

In particular, you’ll use Gloss to parse and map a JSON document containing the top 25 apps in the US App Store. You’ll see that it can be just as easy as it is in Objective-C! :]

Note: This tutorial assumes that you have some basic knowledge of Swift. If you are new to Swift, check out our Swift Quick Start tutorial series.

Getting Started

Download the starter playground for this tutorial.

Since a user interface isn’t important for this JSON tutorial, you’ll be working exclusively with playgrounds.

Open Swift.playground in Xcode and have a look around.

Note: You may find that the playground Project Navigator is closed by default. If so, simply type Command-1 to display it.

The starter playground file has a few source and resource files included to keep the focus purely on parsing JSON in Swift. Take a look at it’s structure to get an overview of what’s included:

  • The Resources folder bundles resources that can be accessed from your Swift code.
    • topapps.json: Contains the JSON string to be parsed.
  • The Sources folder contains additional Swift source files that your main playground code can access. Putting extra supporting .swift files into the Sources folder makes it easy to keep your playground clean and readable.
    • App.swift: A plain old Swift struct representing an app. Your goal is to parse the JSON into a collection of these objects.
    • DataManager.swift: Manages the data retrieval whether local or from the network. You’ll use the methods in this file to load some JSON later in this tutorial.

Once you feel like you have a good understanding of what’s currently in the playground, read on!

Parsing JSON the Native Swift Way

First, you’ll start by parsing JSON the native Swift way – i.e. without using any external libraries. This will help you understand the benefit of using a library like Gloss.

Note: If you already know about the pain of parsing JSON the native way and want to jump straight to Gloss, skip to the next section.

Let’s parse the provided JSON file to get the name of the #1 app on the App Store!

First, while you are going to work with dictionaries a lot, define a type alias at the top of the playground:

typealias Payload = [String: AnyObject]

Complete the code inside the callback of getTopAppsDataFromFileWithSuccess as follows:

DataManager.getTopAppsDataFromFileWithSuccess { (data) -> Void in
 
  var json: Payload!
 
  // 1
  do {
    json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? Payload
  } catch {
    print(error)
    XCPlaygroundPage.currentPage.finishExecution()
  }
 
  // 2
  guard let feed = json["feed"] as? Payload,
    let apps = feed["entry"] as? [AnyObject],
    let app = apps.first as? Payload
    else { XCPlaygroundPage.currentPage.finishExecution() }
 
  guard let container = app["im:name"] as? Payload,
    let name = container["label"] as? String
    else { XCPlaygroundPage.currentPage.finishExecution() }
 
  guard let id = app["id"] as? Payload,
    let link = id["label"] as? String
    else { XCPlaygroundPage.currentPage.finishExecution() }
 
  // 3
  let entry = App(name: name, link: link)
  print(entry)
 
  XCPlaygroundPage.currentPage.finishExecution()
 
}

Here’s what’s going on above:

  1. First you deserialize the data using NSJSONSerialization.
  2. You need to check each and every subscript value in the JSON object to make sure that it is not nil. Once you’re sure it has a valid value, search for the next object. Once you’ve made your way through all of the subscripts, you’ll get the name and link values to work with.

    Note that if any element in the JSON is unexpected, you bail on the whole mess and the app name never gets printed. This is desirable in this case.

  3. The last step is initializing an App using the values of name and link and printing it to the console.

Save and run your storyboard; you should see the following result in your debugger console:

App(name: "Game of War - Fire Age", link: "https://itunes.apple.com/us/app/game-of-war-fire-age/id667728512?mt=8&uo=2")

Yes — “Game of War – Fire Age” is the #1 app in the JSON file.

It took a lot of verbose code just to retrieve the name of the first app — it’s time to see how Gloss stacks up.

Introduction to JSON object mapping

Object mapping is a technique to turn JSON objects into native Swift objects. After defining model objects and corresponding mapping rules, Gloss does the hard work by performing the parsing instead of you.

It has significant benefits over the approach you just tried:

  • You code will be cleaner, reusable and easier to maintain.
  • You can work with objects rather than generic arrays and dictionaries.
  • You can extend model classes to add additional functionality.

Sounds good, huh? Let’s see how it works!

Parsing JSON the Gloss way

To keep everything nice and clean, create a new playground called Gloss.playground, then copy over topapps.json into Resources and DataManager.swift into Sources.

Integrating Gloss in Your Project

It’s fairly straightforward to integrate Gloss into your project/playground:

  1. Click the following link Gloss Repo Zip File and save the library to a convenient location.
  2. Unzip it and drag the Gloss-master/Gloss/Gloss folder into your Sources folder of your playground.

Your Project Navigator should look like this:
JSON tutorial

That’s it! Now that you have Gloss added to your playground, you can start parsing JSON without the optional binding headache!

Note: Gloss can be installed via Cocoapods as well. Since playgrounds are not supported yet, you can only use this method when working with regular Xcode projects.

Mapping JSON to objects

First, you have to define how your model objects relate to your JSON document.

Model objects must conform to the Decodeable protocol, which enables them to be decoded from JSON. To do so, you’ll implement the init?(json: JSON) initializer as defined in the protocol.

Have a look at the structure of topapps.json and create the data model!

TopApps

The TopApps model represents the top level object, and it contains a single key-value pair:

{
  "feed": {
    ...
  }
}

Create a new Swift file called TopApps.swift in the Sources folder of your playground and add the following code:

public struct TopApps: Decodable {
 
  // 1
  public let feed: Feed?
 
  // 2
  public init?(json: JSON) {
    feed = "feed" <~~ json
  }
 
}
  1. Define your model’s properties. In this case there is only one. You’ll define the Feed model object later.
  2. Make sure TopApps conforms to the Decodable protocol by implementing the custom initializer.
  3. You might wondering what <~~ is! It's called the Encode Operator and it is defined in Gloss's Operators.swift file. Basically it tells Gloss to grab the value which belongs to the key feed and encode it. Feed is a Decodable object as well; so Gloss will delegate the responsibility of the encoding to this class.

Feed

The Feed object is very similar to the top level object. Feeds have two key-value pairs, but since you are only interested in the top 25 apps, it's not necessary to process the author object.

{
  "author": {
    ...
  },
  "entry": [
    ...
  ]	
}

Create a new Swift file called Feed.swift in the Sources folder of your playground and define Feed as follows:

public struct Feed: Decodable {
 
  public let entries: [App]?
 
  public init?(json: JSON) {
    entries = "entry" <~~ json
  }
 
}

App

App is the last model object you are going to define. It represents an app in the chart:

{
  "im:name": {
    "label": "Game of War - Fire Age"
  },
  "id": {
    "label": "https://itunes.apple.com/us/app/game-of-war-fire-age/id667728512?mt=8&uo=2",	
    ...
  },
  ...
}

Create a new Swift file called App.swift in the Sources folder of your playground and add the following code:

public struct App: Decodable {
 
  // 1
  public let name: String
  public let link: String
 
  public init?(json: JSON) {
    // 2
    guard let container: JSON = "im:name" <~~ json,
      let id: JSON = "id" <~~ json
      else { return nil }
 
    guard let name: String = "label" <~~ container,
      link: String = "label" <~~ id
      else { return nil }
 
    self.name = name
    self.link = link
  }
 
}
  1. Feed and TopApp both used optional properties. It is possible to define a property as non-optional if you are sure that the JSON being used will always contain the values to populate them.
  2. You don't necessarily have to create model objects for every member in the JSON. For example, in this case it makes no sense to create a model for in:name and id. When working with non-optional and nested objects, always make sure to check for nil.

Now that your model classes are ready the only thing left is to let Gloss do it's job! :]

Open the playground file and add the following code:

import UIKit
import XCPlayground
 
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
 
DataManager.getTopAppsDataFromFileWithSuccess { (data) -> Void in
  var json: [String: AnyObject]!
 
  // 1
  do {
    json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? [String: AnyObject]
  } catch {
    print(error)
    XCPlaygroundPage.currentPage.finishExecution()
  }
 
  // 2
  guard let topApps = TopApps(json: json) else {
    print("Error initializing object")
    XCPlaygroundPage.currentPage.finishExecution()
  }
 
  // 3
  guard let firstItem = topApps.feed?.entries?.first else {
    print("No such item")
    XCPlaygroundPage.currentPage.finishExecution()
  }
 
  // 4
  print(firstItem)
 
  XCPlaygroundPage.currentPage.finishExecution()
 
}
  1. First you deserialize the data using NSJSONSerialization. Same way you did before.
  2. Initialize an instance of TopApps by feeding the JSON data into it's constructor.
  3. Get the #1 app by simply getting the first entry of the feed.
  4. Print the app to the console.

Seriously — that's all the code you need.

Save and run your storyboard; you'll see that you successfully get the app name again, but this time in a more elegant way:

App(name: "Game of War - Fire Age", link: "https://itunes.apple.com/us/app/game-of-war-fire-age/id667728512?mt=8&uo=2")

That takes care of parsing local data — but how would you parse data from a remote source?

Retrieving Remote JSON

It's time to make this project a bit more realistic. Normally, you'd be retrieving remote data, not data from a local file. You can easily grab the App Store ratings using an online request.

Open DataManager.swift and define the Top Apps URL:

let TopAppURL = "https://itunes.apple.com/us/rss/topgrossingipadapplications/limit=25/json"

then add the following method to DataManager's implementation:

public class func getTopAppsDataFromItunesWithSuccess(success: ((iTunesData: NSData!) -> Void)) {
  //1
  loadDataFromURL(NSURL(string: TopAppURL)!, completion:{(data, error) -> Void in
      //2
      if let data = data {
        //3
        success(iTunesData: data)
      }
  })
}

The above code looks pretty familiar; but instead of retrieving a local file you're using NSURLSession to pull the data from iTunes. Here's what's happening in detail:

  1. First you call loadDataFromURL; this takes the URL and a completion closure that passes in an NSData object.
  2. Next you make sure the data exists using optional binding.
  3. Finally, you pass the data to the success closure as you did before.

Open your storyboard and replace the line

DataManager.getTopAppsDataFromFileWithSuccess { (data) -> Void in

with

DataManager.getTopAppsDataFromItunesWithSuccess { (data) -> Void in

Now you're retrieving real data from iTunes.

Save and run your storyboard; you'll see that the data parsing still arrives at the same conclusion of the #1 app:

App(name: "Game of War - Fire Age", link: "https://itunes.apple.com/us/app/game-of-war-fire-age/id667728512?mt=8&uo=2")

The above value may be different for you, as the top apps in the App Store change constantly.

Usually people aren't just interested in the top app in the App Store — they want to see a list of all top apps. You don't have to code anything in order to access them - you can easily access them with the following code snippet:

topApps.feed?.entries

Peeking Under the Hood at Gloss

You can definitely see that Gloss works really well at taking care of the parsing process — but how does it work under the hood?

<~~ is a custom operator for a set of Decoder.decode functions. Gloss has built-in support for decoding a lot of types:

  • Simple types (Decoder.decode)
  • Decodable models (Decoder.decodeDecodable)
  • Simple arrays (Decoder.decode)
  • Arrays of Decodable models (Decoder.decodeDecodableArray)
  • Enum types (Decoder.decodeEnum)
  • Enum arrays (Decoder.decodeEnumArray)
  • NSURL types (Decoder.decodeURL)
  • NSURL arrays (Decode.decodeURLArray)
Note:If you want to learn more about Custom Operators take a look at the tutorial on the subject: Operator Overloading in Swift Tutorial

In this tutorial you relied heavily on Decodable models. If you need something more complex, it's possible to extend Decoder and provide your own decoding implementation.

Of course Gloss can convert objects back to JSON as well. If you are interested in doing that, have a look at the Encodable protocol.

Where to Go From Here?

Here is the final playground from the above JSON tutorial.

You can definitely use the playground as starter code for your next app; simply replace the URL for retrieving remote data with your own URL, handle the individual keys and indices of your new JSON response, and you'll have a new project that parses something else like the results of football matches or any other piece of data that can be downloaded over the network as JSON.

Development on Gloss will continue here on Github, so keep an eye out for the latest updates.

Swift is still evolving as well, so you'll want to keep up to date on Apple's documentation for any future updates for the language.

I hope you enjoyed this JSON tutorial; don't forget to check out all the other Swift tutorials on the website. If you have any questions or comments, feel free to join the discussion below!

The post Swift Tutorial: Working with JSON appeared first on Ray Wenderlich.

Video Tutorial: How to Make a Game Like Flappy Bird in Swift Part 6: Game States & State Machines

Video Tutorial: How to Make a Game Like Flappy Bird in Swift Part 7: Keeping Score

Viewing all 4370 articles
Browse latest View live