Apple's June 1 64-bit deadline

In October 2014, Apple announced that all submissions to the App Store must include 64-bit support by June 1, 2015. The SoundCloud API for Cocoa contains 32-bit dependencies and will not be updated, because it has been discontinued. Anyone using the SoundCloud API for Cocoa will need to will need to migrate away from it if they wish to update their app after June 1.

To ease this transition we have built a sample app that demonstrates how to authorize a user via OAuth using only built-in Foundation libraries.

Once an access_token has been obtained via OAuth, you can make GET requests like so:

let urlSession = NSURLSession.sharedSession()
let urlString = "https://api.soundcloud.com/me"
let urlComponents = NSURLComponents(string: urlString)!
urlComponents.queryItems = [ NSURLQueryItem(name: "oauth_token", value: "insert an OAuth token here")]
let url = urlComponents.URL!

let dataTask = urlSession.dataTaskWithRequest(NSURLRequest(URL: url)) { (data, response, error) -> Void in
   if let jsonOutput = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? [String:AnyObject] {
       // do stuff with JSON
   }
}

dataTask.resume()

POST requests that contain multipart data (e.g. uploading a track) look like this:

import UIKit

class ViewController: UIViewController {
    func uploadTrack(title: String, trackPath: String) {
        let urlSession = NSURLSession.sharedSession()
        let urlRequest = getURLRequest(title, audioPath: trackPath)
        let task = urlSession.dataTaskWithRequest(urlRequest) { (data, response, error) -> Void in
            if let httpResponse = response as? NSHTTPURLResponse {
                println("returned \(httpResponse.statusCode)")
            }
            if data != nil, let response = NSString(data: data, encoding: NSUTF8StringEncoding) {
                println(response)
            }
            if let err = error {
                println(err)
            }
        }
        task.resume()
    }

    func getURLRequest(title: String, audioPath: String) -> NSURLRequest {
        let boundary = NSUUID().UUIDString
        let request = NSMutableURLRequest(URL: NSURL(string: "https://api.soundcloud.com/tracks")!)
        request.HTTPMethod = "POST"
        request.HTTPBody = getPostData("insert an OAuth token here", boundary: boundary, title: title, audioPath: audioPath)
        let contentType = "multipart/form-data; boundary=" + boundary
        request.setValue(contentType, forHTTPHeaderField: "Content-Type")
        return request
    }

    func getPostData(token: String, boundary: String, title: String, audioPath: String) -> NSData {
        let boundaryStart = "--\(boundary)\r\n"
        let boundaryEnd = "\r\n--\(boundary)--\r\n"
        let bodyData : NSMutableData = NSMutableData()

        // add the token
        var tokenSection = boundaryStart
        tokenSection += "Content-Disposition: form-data; name=\"oauth_token\"\r\n\r\n"
        tokenSection += "\(token)\r\n"
        bodyData.appendData(tokenSection.dataUsingEncoding(NSUTF8StringEncoding)!)

        // add the track title
        var titleSection = boundaryStart
        titleSection += "Content-Disposition: form-data; name=\"track[title]\"\r\n\r\n"
        titleSection += "\(title)\r\n"
        bodyData.appendData(titleSection.dataUsingEncoding(NSUTF8StringEncoding)!)

        // add the audio file
        let trackData = NSData(contentsOfFile: audioPath)!
        var trackSection = boundaryStart
        trackSection += "Content-Disposition: form-data; name=\"track[asset_data]\"; "
        trackSection += "filename=\"\(audioPath.lastPathComponent)\"\r\n"
        trackSection += "Content-Type: application/octet-stream\r\n"
        trackSection += "\r\n"
        bodyData.appendData(trackSection.dataUsingEncoding(NSUTF8StringEncoding)!)
        bodyData.appendData(trackData)
        bodyData.appendData(boundaryEnd.dataUsingEncoding(NSUTF8StringEncoding)!)
        return bodyData
    }
}

Note: This example assumes access tokens will never expire, however, we encourage you not to make this assumption in your production code. Instead, build your app assuming that tokens will periodically expire and can be refreshed using a refresh token. For details on how to use a refresh token, see Section 1.5 of the OAuth 2.0 specification.