Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to save my users tokens id into my database using POST request in Swift (here PHP code here). I am a bit confused about synchronous and asynchronous request.

  1. Is this code the right way to do it?
  2. would the app crash if there is a connection problem while it is sending the synchronous request
  3. shall I use an api key (not sure is the correct word) to "identify" the user

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {

    var userId = "001" //I just use it as USER number 1

    // prepare the tolen to be saved from <xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx> to xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    var token = NSString(format: "%@", deviceToken)
    token = token.stringByReplacingOccurrencesOfString(
        "<",
        withString: "")
    token = token.stringByReplacingOccurrencesOfString(
        ">",
        withString: "")
    token = token.stringByReplacingOccurrencesOfString(" ", withString: "")


    dispatch_async(dispatch_get_main_queue(), { () -> Void in


        var postBody = NSString(format: "user=%@&token=%@", userId, token)
        var endBody = NSURL(string: "http://www.myServer.com/api/v1.0/saveToken.php")
        var request = NSMutableURLRequest(URL: endBody!, cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData, timeoutInterval: 30.0)

        request.HTTPMethod = "POST";
        request.HTTPBody = postBody.dataUsingEncoding(NSUTF8StringEncoding)
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")


        var response: NSURLResponse?
        var error: NSError?

        NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)

        println(response)
        println(error)

    })

    }
share|improve this question
    
I have rolled back the last edit. Please see what you may and may not do after receiving answers. – Martin R Apr 13 '15 at 11:08
up vote 5 down vote accepted

This:

var token = NSString(format: "%@", deviceToken)
token = token.stringByReplacingOccurrencesOfString("<", withString: "")
token = token.stringByReplacingOccurrencesOfString(">", withString: "")
token = token.stringByReplacingOccurrencesOfString(" ", withString: "")

is actually a bad method to convert an NSData object to an NSString (containing the bytes in hexadecimal). It relies on description having the format

<01020304 05060708 090a0b0c 0d0e0f10>

which is not officially documented. In most cases, the description of an object is only suitable for debugging purposes, but not for further processing.

I would convert all data bytes explicitly to create the string. Here is a possible implementation as an NSData extension method:

extension NSData {
    func hexString() -> String {
        // "Array" of all bytes:
        let bytes = UnsafeBufferPointer<UInt8>(start: UnsafePointer(self.bytes), count:self.length)
        // Array of hex strings, one for each byte:
        let hexBytes = map(bytes) { String(format: "%02hhx", $0) }
        // Concatenate all hex strings:
        return "".join(hexBytes)
    }
}

which can be used as

let token = deviceToken.hexString()

With

dispatch_async(dispatch_get_main_queue(), { ... }

you dispatch the URL request to the main queue where it blocks the UI. You can use dispatch_get_global_queue() instead to dispatch it to a background thread, or simply use sendAsynchronousRequest():

NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
    (response, data, error) -> Void in

    if data != nil {
        println("data: \(data)")
    } else {
        println("failed: \(error.localizedDescription)")
    }
}

Now the request is done in the background and then the completion handler called on the main thread.

In the case of an connection problem, the completion handler is called with data == nil and error != nil containing information about the problem.


shall I use an api key (not sure is the correct word) to "identify" the user

This question is a bit broad and depends on what you are trying to achieve. Here are some comparisons of the available methods:

which might serve as a starting point for your further research.

share|improve this answer
    
thanks a lot for that +1. – mat Apr 11 '15 at 16:52
1  
@mattia: Added more ... – Martin R Apr 11 '15 at 17:31
    
thanks! that's what I was looking for – mat Apr 11 '15 at 17:46
1  
Although, is data guaranteed to be nil? I thought it was generally better to check if error != nil. – nhgrif Apr 11 '15 at 22:36
1  
@nhgrif: No, it is the other way around (see for example stackoverflow.com/a/29384651/1187415). – But here is does not matter, the sendAsynchronousRequest() documentation is quite clear that either data != nil and error == nil or vice versa. – Martin R Apr 11 '15 at 22:42

The extension on NSData by @martin-r can be rewritten in Swift 2 as a computed property using map reduce as follows:

extension NSData {
    var hexString: String {
        let bytes = UnsafeBufferPointer<UInt8>(start: UnsafePointer(self.bytes), count:self.length)
        return bytes.map { String(format: "%02hhx", $0) }.reduce("", combine: { $0 + $1 })
    }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.