CloudKit completion handler and dispatch_sync issue - asynchronous

I have the following query to Cloud Kit
func cloudKitManageUserPublicTable (typeOfOperation: Int, encriptedBabyName: String?, encriptedOllyKey:String?, result: (error: NSError?, userHasBeenFound: Bool?, ollYKeyHasBeenFound: Bool?, encriptedBabyNameFound: String?) -> Void){
// OPERATION TYPES
// 1 - search for user and add, link or update a key
// 2 - search for user and check he has a key
// 3 - search for a key
// 4 - search for user and add a default one if has not been found
print("cloudKitManageUserPublicTable - operation \(typeOfOperation)")
var recordCounter = 0
var publicUserRecord = CKRecord(recordType: "PublicUsers")
let useriCloudID = NSUserDefaults.standardUserDefaults().objectForKey("useriCloudID") as! String
var predicate = NSPredicate()
switch typeOfOperation {
case 1:
predicate = NSPredicate(format: "useriCloudID == %#", useriCloudID)
case 2:
predicate = NSPredicate(format: "useriCloudID == %#", useriCloudID)
case 3:
predicate = NSPredicate(format: "encriptedOllyKey == %#", encriptedOllyKey!)
default:
print("no scenarios")
}
let cloudKitQuery = CKQuery(recordType: "PublicUsers", predicate: predicate)
let queryOperation = CKQueryOperation(query: cloudKitQuery)
let operationQueue = NSOperationQueue()
let publicDatabase = CKContainer.defaultContainer().publicCloudDatabase;
queryOperation.database = publicDatabase
queryOperation.recordFetchedBlock = { (record : CKRecord) -> Void in
publicUserRecord = record
recordCounter += 1
}
queryOperation.queryCompletionBlock = { (cursor: CKQueryCursor?, error: NSError?) -> Void in
print("cloudKitManageUserPublicTable - # of record found - \(recordCounter)")
if error != nil
{
// ERROR STOP
print("cloudKitManageUserPublicTable - error - \(error)")
result(error: error, userHasBeenFound: nil, ollYKeyHasBeenFound: nil, encriptedBabyNameFound: nil)
}
else
{
switch typeOfOperation {
case 1:
// KEY FOUND, UPDATE
print("cloudKitManageUserPublicTable - search for user and add or update a key")
publicUserRecord["encriptedBabyName"] = encriptedBabyName!
publicUserRecord["encriptedOllyKey"] = encriptedOllyKey!
publicUserRecord["hasKey"] = true
publicDatabase.saveRecord(publicUserRecord) { (CKRecord: CKRecord?, error: NSError?) -> Void in
if error != nil
{
print("cloudKitManageUserPublicTable - creating key - UPDATE error \(error)")
result(error: error, userHasBeenFound: nil, ollYKeyHasBeenFound: nil, encriptedBabyNameFound: nil)
}
else
{
print("cloudKitManageUserPublicTable - creating key - UPDATE OK")
result(error: error, userHasBeenFound: nil, ollYKeyHasBeenFound: true, encriptedBabyNameFound: nil)
}
}
case 2:
print("cloudKitManageUserPublicTable - search for user and check it has a key")
if publicUserRecord.objectForKey("hasKey") as? Bool == false
{
print("cloudKitManageUserPublicTable - user do not have a key")
result(error: nil, userHasBeenFound: nil, ollYKeyHasBeenFound: false, encriptedBabyNameFound: nil)
}
else
{
print("cloudKitManageUserPublicTable - user has a key")
result(error: nil, userHasBeenFound: nil, ollYKeyHasBeenFound: true, encriptedBabyNameFound: nil)
}
case 3:
if recordCounter == 0
{
print("cloudKitManageUserPublicTable - no record has this key")
result(error: nil, userHasBeenFound: nil, ollYKeyHasBeenFound: false, encriptedBabyNameFound: nil)
}
else
{
print("cloudKitManageUserPublicTable - \(recordCounter) records have this key")
result(error: nil, userHasBeenFound: nil, ollYKeyHasBeenFound: true, encriptedBabyNameFound: nil)
}
case 4:
if recordCounter == 0
{
// NO USER FOUND, CREATE
print("cloudKitManageUserPublicTable - search for user and add a default one if has not been found")
// publicUserRecord["encriptedBabyName"] = ""
// publicUserRecord["encriptedOllyKey"] = ""
publicUserRecord["hasKey"] = false
publicUserRecord["useriCloudID"] = useriCloudID
publicDatabase.saveRecord(publicUserRecord) { (CKRecord: CKRecord?, error: NSError?) -> Void in
dispatch_async(dispatch_get_main_queue()) {
if error != nil
{
print("cloudKitManageUserPublicTable - no user - CREATE error \(error)")
result(error: nil, userHasBeenFound: false, ollYKeyHasBeenFound: nil, encriptedBabyNameFound: nil)
}
else
{
print("cloudKitManageUserPublicTable - no user found - CREATE ok")
result(error: nil, userHasBeenFound: false, ollYKeyHasBeenFound: nil, encriptedBabyNameFound: nil)
}
}
}
}
else
{
// USER FOUND - DO NOTHING
print("cloudKitManageUserPublicTable - user exists, do nothing for now")
result(error: nil, userHasBeenFound: true, ollYKeyHasBeenFound: nil, encriptedBabyNameFound: nil)
}
default:
print("no scenarios")
}
}
}
operationQueue.addOperation(queryOperation)
}
The method above is called for the FIRST TIME by the method bellow where I wait for the completion handler to return and then call the method above for the SECOND TIME to then verify if the publicUserRecord["hasKey"] = false was set to false.
But my problem is. When I call the method the SECOND TIME to verify the publicUserRecord["hasKey"] it returns that nothing has been saved yet. If I then wait a bit and call the method to verify the publicUserRecord["hasKey"] for the THIRD TIME then it finds and verifies it.
As I am doing the very same call and the results have been saved in the FIRST call seems that theres a bit of a lag with apple servers or am I not using the completion handlers, dispatch_async, dispatch_sync properly? Any ideas?
func manageUserPublicTable(){
tryAgainButtonOutlet.enabled = false
let spinningActivity = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
spinningActivity.labelText = "Talking to Apple Servers"
spinningActivity.detailsLabelText = "Creating user credentials..."
cloudKitManageUserPublicTable(1) { (error, userExists) -> Void in
dispatch_sync(dispatch_get_main_queue()) {
if error != nil
{
spinningActivity.hide(true)
// let user try again
let optionMenu = UIAlertController(title: nil, message: "Are you all set to upload this record?!", preferredStyle: .ActionSheet)
let tryAgain = UIAlertAction(title: "Try again", style: .Default, handler: {
(alert: UIAlertAction!) -> Void in
self.tryAgainButtonOutlet.enabled = true
})
let cancelAction = UIAlertAction(title: "Not yet...", style: .Cancel, handler: {
(alert: UIAlertAction!) -> Void in
self.tryAgainButtonOutlet.enabled = true
})
optionMenu.addAction(tryAgain)
optionMenu.addAction(cancelAction)
if(isIPad()) {
optionMenu.popoverPresentationController!.permittedArrowDirections = UIPopoverArrowDirection()
optionMenu.popoverPresentationController!.sourceView = self.view
optionMenu.popoverPresentationController!.sourceRect = CGRectMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0, 1.0, 1.0)
}
self.presentViewController(optionMenu, animated: true, completion: nil)
}
else
{
spinningActivity.hide(true)
self.manageEncriptedKey()
}
}
}
}

Indeed there can be some time between saving data and being able to retrieve it. There is no specification how long this could be. Usually it's less than seconds.
So you have to make your app logic so that it does not care about that. You already saved the record so your app already knows the content of that record. You could pass on the record from the callback so that you don't have to query for it again.
One other think. Your functions are a bit large to my taste. There is too much functionality in 1 function. That makes it difficult to read. Ideally a function should do only one thing.

Related

Golang Chan is hanging when looping through the results

I am pretty new to GoLang channels, but it isn't working as I would expect.
I have a function that I want to call 3 separate goroutines on and then wait for them all to complete. If I get an error then I am trying to put it on the CHAN and then handle the error after wg.Wait() completes.
Unfortunately, when looping through the CHAN results it will hang. I hypothesize as it is still waiting for the CHAN to get filled but not all goroutines will throw errors.
What is the best way to handle looping through channels that won't always be populated? I also know that I don't have to use CHANs here, but I wanted to make sure that I understood them.
Below is my code.
func createWorkoutPlanForUserPreconditionCheck(planID, userID, transactionID *string) (*sharedstructs.Plan, *sharedstructs.User, *sharedstructs.Profile, error) {
if planID == nil || userID == nil || transactionID == nil {
return nil, nil, nil, sharedstructs.InvalidData{Msg: "Cannot pass in Nil Parameters"}
}
plan := sharedstructs.Plan{}
user := sharedstructs.User{}
profile := sharedstructs.Profile{}
//myError := sharedstructs.InvalidData{}
ch := make(chan sharedstructs.InvalidData, 3)
var wg sync.WaitGroup
wg.Add(3)
//Get the Plan from the Plan ID
go func() {
defer wg.Done()
returnedPlan, readError := readPlan(*planID)
if readError != nil || returnedPlan == nil {
ch <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
} else {
plan = *returnedPlan
}
}()
//Get the User
go func() {
defer wg.Done()
returnedUser, getUserError := userdomain.GetUserByID(*userID, *transactionID)
if getUserError != nil || &returnedUser == nil {
ch <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
} else {
user = returnedUser
}
}()
//Get the Profile
go func() {
defer wg.Done()
readProfile, getProfileError := profiledomain.GetProfile(*userID, *transactionID)
if getProfileError != nil || readProfile == nil {
ch <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
} else {
profile = *readProfile
}
}()
wg.Wait()
////"Hangs Here" - PUT MY ERROR HANDLING LOGIC HERE
for err := range ch {
fmt.Println(err.Error())
}
return &plan, &user, &profile, nil
}
So, not long after posting I figured a solution. My problem was really two fold:
Closing my channel so that it knew when to stop listening
Using inconsistent methods to get my data from my goroutine to my calling function. For errors I was using chan's but for custom structs I was just setting it. I generisized my chan to an interface{} and then did a type switch on it when processing to determine the type of struct that it was.
^^^ fixing these issues made my code work but here is what my code ended up as..
func createWorkoutPlanForUserPreconditionCheck(planID, userID, transactionID *string) (*sharedstructs.Plan, *sharedstructs.User, *sharedstructs.Profile, error) {
if planID == nil || userID == nil || transactionID == nil {
return nil, nil, nil, sharedstructs.InvalidData{Msg: "Cannot pass in Nil Parameters"}
}
outputChannel := make(chan interface{}, 3)
var wg sync.WaitGroup
wg.Add(3)
//Get the Plan from the Plan ID
go func() {
defer wg.Done()
returnedPlan, readError := readPlan(*planID)
if readError != nil || returnedPlan == nil {
outputChannel <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
} else {
outputChannel <- *returnedPlan
}
}()
//Get the User
go func() {
defer wg.Done()
returnedUser, getUserError := userdomain.GetUserByID(*userID, *transactionID)
if getUserError != nil || &returnedUser == nil {
outputChannel <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
} else {
outputChannel <- returnedUser
}
}()
//Get the Profile
go func() {
defer wg.Done()
readProfile, getProfileError := profiledomain.GetProfile(*userID, *transactionID)
if getProfileError != nil || readProfile == nil {
outputChannel <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
} else {
outputChannel <- *readProfile
}
}()
wg.Wait()
close(outputChannel)
plan := sharedstructs.Plan{}
user := sharedstructs.User{}
profile := sharedstructs.Profile{}
for result := range outputChannel {
switch result.(type) {
case sharedstructs.InvalidData:
return nil, nil, nil, result.(sharedstructs.InvalidData)
case sharedstructs.Plan:
plan = result.(sharedstructs.Plan)
case sharedstructs.User:
user = result.(sharedstructs.User)
case sharedstructs.Profile:
profile = result.(sharedstructs.Profile)
}
}
return &plan, &user, &profile, nil
}

Newly created users are not saved to the Firebase Database

So I am having trouble with my code that creates new users and uploads/stores their user information such as First name, Last name and Email to the firebase database. Whenever I create a user and go onto my firebase databse there is not a new user present.
Auth.auth().createUser(withEmail: usernameTextField.text!, password: passwordTextField.text!) { (user, error) in
if error != nil {
print(error!.localizedDescription)
return
}
let ref = Database.database().reference()
let usersReference = ref.child("users")
let uid = user?.user.uid
let newUserReference = usersReference.child(uid!)
newUserReference.setValue(["username": self.usernameTextField.text!,"firstname": self.firstnameTextField.text!, "lastname": self.lastnameTextField.text!,"email": self.emailTextField.text!])
This should work:
#objc func handleSignUp() {
let ref = Database.database().reference
Auth.auth().createUser(withEmail:usernameTextField.text!, password: passwordTextField.text!) { (user, error) in
if error != nil {
print(error as Any)
return
}
guard let uid = user?.user.uid else {
return
}
// successfully authenticated user
let values = ["name": "some name", "email": "some email", "username": "your username", "userId": user?.user.uid]
let userReference = ref.child("user").child(uid)
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = self.usernameField.text
changeRequest?.commitChanges(completion: nil)
userReference.updateChildValues(values, withCompletionBlock: { (err, ref) in
if err != nil {
print(err as Any)
return
}
// add your code here to upload user information to FirebaseDatabase
})
Hope that your problem is solved and the solution works for your purposes
I accidentally wrote
Auth.auth().createUser(withEmail: usernameTextField.text!, password: passwordTextField.text!
instead of:
Auth.auth().createUser(withEmail: emailTextField.text!, password: passwordTextField.text!) { (user, error) in
if error != nil {
print(error!.localizedDescription)
return
} ...

Wait for 2 callbacks before instantiating an object

I would like to download from firebase:
data issued from a group profile (Firebase realtime DB)
including...
data issued from the group admin profile (Firebase realtime DB)
a group profile image (Firebase Storage)
Then I can instantiate a group object with its data and its image
First approach, I used 3 nested closures that allowed me to get data, and then to get the image.
It did work, but it was quite long to get sequentially all that stuffs from firebase.
So I tried to use GCD in order to push my 2 latest Firebase queries (user data + group image) at the same time (rather than one after the other), and to wait for the last callback to start instantiating my group.
Is it a correct approach ?
If yes, I find some difficulties to implement it...
My issue : returnedUser and returnedGroupImage are always nil
Here is my bunch of code :
static func getGroup(_ groupID:String, completionBlock: #escaping (_ group: Group?) -> ()) {
dataRef.child("data").child("groups").child(groupID).observe(.value, with: { (snapshot) in
if let snapshotValue = snapshot.value {
guard let name = (snapshotValue as AnyObject).object(forKey: "name") as? String else
{
completionBlock(nil)
return
}
guard let adminID = (snapshotValue as AnyObject).object(forKey: "adminID") as? String else
{
completionBlock(nil)
return
}
let queue = DispatchQueue(label: "asyncQueue", attributes: .concurrent, target: .main)
let dispatch_group = DispatchGroup()
var returnedUser: User?
var returnedGroupImage: UIImage?
queue.async (group: dispatch_group) {
FireBaseHelper.getUser(adminID, completionBlock: { (user) in
if user != nil {
returnedUser = user
}
})
}
queue.async (group: dispatch_group) {
FireBaseHelper.getGroupImage(groupID, completionBlock: { (image) in
if image != nil {
returnedGroupImage = image
}
})
}
dispatch_group.notify(queue: DispatchQueue.main) {
// Single callback that is supposed to be executed after all tasks are complete.
if (returnedUser == nil) || (returnedGroupImage == nil) {
// always true !
return
}
let returnedGroup = Group(knownID: (snapshotValue as AnyObject).key, named: name, createdByUser: currentUser!)
returnedGroup.groupImage = returnedGroupImage
completionBlock(returnedGroup)
}
}
})
}
Thanks for your help !
I believe that the way you are using DispatchGroups are not correct.
let dispatch_group = DispatchGroup()
var returnedUser: User?
var returnedGroupImage: UIImage?
dispatch_group.enter()
FireBaseHelper.getUser(adminID, completionBlock: { (user) in
if user != nil {
returnedUser = user
}
dispatch_group.leave()
})
dispatch_group.enter()
FireBaseHelper.getGroupImage(groupID, completionBlock: { (image) in
if image != nil {
returnedGroupImage = image
}
dispatch_group.leave()
})
dispatch_group.notify(queue: DispatchQueue.main) {
// Single callback that is supposed to be executed after all tasks are complete.
if (returnedUser == nil) || (returnedGroupImage == nil) {
// always true !
return
}
let returnedGroup = Group(knownID: (snapshotValue as AnyObject).key, named: name, createdByUser: currentUser!)
returnedGroup.groupImage = returnedGroupImage
completionBlock(returnedGroup)
}

How to return HTTP result synchronously in Swift3?

I have this code which- as far as I understand- is async:
func testConnection() -> Bool {
let url = URL(string: uri)!
let task = URLSession.shared.dataTask(with: url) {
(data, response, error) in
guard let data = data, let _:URLResponse = response , error == nil else {
print("error")
return
}
let dataString = String(data: data, encoding: String.Encoding.utf8)
}
task.resume()
}
How would a synchronous version look that allows to return the testConnection result to the sender?
You could use a semaphore to wait for the async call to finish:
func testConnection() -> Bool {
let url = URL(string: uri)!
var dataStringOrNil: String?
let semaphore = DispatchSemaphore(value: 0)
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
defer {
semaphore.signal()
}
guard let data = data, error == nil else {
print("error")
return
}
dataStringOrNil = String(data: data, encoding: .utf8)
}
task.resume()
semaphore.wait()
guard let dataString = dataStringOrNil else {
return false
}
// some substring checking
return dataString.contains("href")
}
I wouldn't recommend it, but there can be reasons for sync calls. We use them sometimes in command-line tools.

HTTP POST error Handling in Swift 2

I'm new here, and this is my first question...
I try to write an App in Swift 2 that makes an HTTP POST request but I can't figure out how to use the new error handling of Swift 2. Can anyone tell me please how to implement the "do-try-catch" error handling of Swift 2 to the code snippet below?
(This code snippet uses the old error handling of swift 1.2)
func post(params : Dictionary<String, String>, url : String) {
var request = NSMutableURLRequest(URL: NSURL(string: url)!)
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil/*, error: &err*/)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
print("Response: \(response)")
var strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Body: \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves/*, error: &err*/) as? NSDictionary
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
print(err!.localizedDescription)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
}
else {
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
var success = parseJSON["success"] as? Int
print("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
}
}
})
task!.resume()
}
You presumably want to wrap your NSJSONSerialization calls in do/try/catch logic as shown below.
In Swift 3:
var request = URLRequest(url: URL(string: urlString)!)
let session = URLSession.shared
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = try! JSONSerialization.data(withJSONObject: parameters)
// or if you think the conversion might actually fail (which is unlikely if you built `parameters` yourself)
//
// do {
// request.httpBody = try JSONSerialization.data(withJSONObject: parameters)
// } catch {
// print(error)
// }
let task = session.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error: \(error)")
return
}
// this, on the other hand, can quite easily fail if there's a server error, so you definitely
// want to wrap this in `do`-`try`-`catch`:
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
let success = json["success"] as? Int // Okay, the `json` is here, let's get the value for 'success' out of it
print("Success: \(success)")
} else {
let jsonStr = String(data: data, encoding: .utf8) // No error thrown, but not dictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError) // Log the error thrown by `JSONObjectWithData`
let jsonStr = String(data: data, encoding: .utf8)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
Or, in Swift 2
let request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(parameters, options: [])
// or if you think the conversion might actually fail (which is unlikely if you built `parameters` yourself)
//
// do {
// request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: [])
// } catch {
// print(error)
// }
let task = session.dataTaskWithRequest(request) { data, response, error in
guard let data = data where error == nil else {
print("error: \(error)")
return
}
// this, on the other hand, can quite easily fail if there's a server error, so you definitely
// want to wrap this in `do`-`try`-`catch`:
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary {
let success = json["success"] as? Int // Okay, the `json` is here, let's get the value for 'success' out of it
print("Success: \(success)")
} else {
let jsonStr = String(data: data, encoding: NSUTF8StringEncoding) // No error thrown, but not NSDictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError) // Log the error thrown by `JSONObjectWithData`
let jsonStr = String(data: data, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
I'd also suggest being a little more careful about forced unwrapping of data, because you want to detect/handle the errors, not crash. For example, above I use a guard statement to unwrap it.
In general if a function throws you have to write it inside a do catch block or just mark the outer scope function (in this case post) as throws:
func post(params : Dictionary<String, String>, url : String) {
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
do {
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: .PrettyPrinted)
} catch {
//handle error. Probably return or mark function as throws
print(error)
return
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
// handle error
guard error == nil else { return }
print("Response: \(response)")
let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Body: \(strData)")
let json: NSDictionary?
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
} catch let dataError {
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
print(dataError)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
// return or throw?
return
}
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
let success = parseJSON["success"] as? Int
print("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
}
})
task!.resume()
}
If you don't want to handle these errors right in your post function you can just declare it as throws than you don't have to use do catch at all

Resources