Try! throwing fatal error in Swift 3, issues updating from Swift 2 - swift3

I am trying to parse the JSON data from my server and I am getting an error when it hits the try! statement and it is crashing. It is telling me
Code=3840 "Invalid value around character 0.
It my be because I have not updated my code correctly to Swift 3. I was having an issue with if let parse for the longest time until I switched the as to as?
#IBAction func registerButtonTapped(_ sender: Any) {
let userEmail = userEmailTextField.text;
let userPassword = userPasswordTextField.text;
let userRepeatPassword = repeatPasswordTextField.text;
// Check for empty fields
if((userEmail?.isEmpty)! || (userPassword?.isEmpty)! || (userRepeatPassword?.isEmpty)!){
//Display alert message
displayMyAlertMessage(userMessage: "All fields are required");
return;
}
//Check if passwords matech
if(userPassword != userRepeatPassword){
// Display alert message
displayMyAlertMessage(userMessage: "Passwords do not match");
return;
}
// Send user data to server side
let myUrl = URL(string: "http://");
let request = NSMutableURLRequest(url:myUrl!);
request.httpMethod = "Post";
let postString = "email=\(userEmail)&password=\(userPassword)";
//adding the parameters to request body
request.httpBody = postString.data(using: String.Encoding.utf8);
//creating a task to send the post request
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
if error != nil{
print("error=\(error)")
return
}
//parsing the reponse
//converting response to Any
let json = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as? [String:Any]
//parsing JSON
if let parseJSON = json{
let resultValue = parseJSON["status"] as? String
print("result: \resultValue)")
var isUserRegistered:Bool = false;
if(resultValue=="Success") { isUserRegistered = true;}
var messageToDisplay:String = parseJSON["messsage"] as! String;
if(!isUserRegistered)
{
messageToDisplay = parseJSON["message"] as! String;
}
DispatchQueue.main.async {
//Display alert message with confirmation.
let myAlert = UIAlertController(title:"Alert", message:messageToDisplay, preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title:"ok", style:UIAlertActionStyle.default){ action in
self.dismiss(animated: true, completion:nil);
}
myAlert.addAction(okAction);
self.present(myAlert, animated:true, completion:nil);
};
}
}
task.resume()
}
Please help, thanks

The reason of the error is that you are sending literal "Optional(Foo)" strings to the server via String Interpolation. userEmail and userPassword will never match and the server sends no data back. In Swift 3 you have to explicitly unwrap even implicit unwrapped optional strings.
The solution is a waterproof error handling with optional bindings
#IBAction func registerButtonTapped(_ sender: AnyObject) {
// Check for empty fields
guard let userEmail = userEmailTextField.text, !userEmail.isEmpty,
let userPassword = userPasswordTextField.text, !userPassword.isEmpty,
let userRepeatPassword = repeatPasswordTextField.text, !userRepeatPassword.isEmpty else {
//Display alert message
displayMyAlertMessage(userMessage: "All fields are required")
return
}
...
Now all relevant optionals are safely unwrapped and the server will get the right data.
Further trailing semicolons and parentheses around if conditions are not needed in Swift and use URLRequest rather than NSMutableURLRequest in Swift 3
var request = URLRequest(url:myUrl!) // var is mandatory if properties are going to be changed.
PS: In any case – as already mentioned in the comments – never use carelessly try! when receiving data from a server.

Related

Json parsing in Swift 3.0

This is my code for Jason parsing in Swift:
static func POST(url: String, parameters: NSDictionary, completionBlock: #escaping CompletionBlock){
let todoEndpoint: String = Webservices.Base_Url.appending(url)
guard let url = NSURL(string: todoEndpoint) else {
print("Error: cannot create URL")
return
}
var request = URLRequest(url: url as URL)
//var request = URLRequest(url: NSURL(string: todosEndpoint)! as URL)
let session = URLSession.shared
request.httpMethod = "POST"
var err: NSError?
let jsonData = try? JSONSerialization.data(withJSONObject: parameters)
request.httpBody = jsonData
request.addValue("application/x-www-form-urlencoded;charset=UTF-8 ", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request, completionHandler: {data, response, error -> Void in
guard error == nil else {
print("error calling POST on /todos/1")
print(error)
return
}
// make sure we got data
guard let dataTemp = data else {
print("Error: did not receive data")
return
}
// parse the result as JSON, since that's what the API provides
do {
guard let todo = try JSONSerialization.jsonObject(with: dataTemp, options: []) as? [String: AnyObject] else {
print("error trying to convert data to JSON")
return
}
// now we have the todo, let's just print it to prove we can access it
print("The todo is: " , todo)
// the todo object is a dictionary
// so we just access the title using the "title" key
// so check for a title and print it if we have one
} catch {
print("error trying to convert data to JSON")
return
}
})
task.resume()
}
I got while jason parsing:
error expression produced error: error: Execution was interrupted,
reason: EXC_BAD_ACCESS (code=1, address=0x0). The process has been
returned to the state before expression evaluation.
What's wrong?

Getting 100x100 profile pic using Facebook API, Firebase and Swift

My project had been getting the URL string for the medium sized profile pic using this code:
let downloadMediumPicTask = session.dataTask(with: mediumProfPictureURL) { (data, response, error)
in
// The download has finished.
if let e2 = error {
print("Error downloading profile picture: \(e2)")
} else {
if let res2 = response as? HTTPURLResponse {
print("Downloaded medium profile picture with response code \(res2.statusCode)")
if let imageData2 = data {
mediumProfilePictureUIImageFile = UIImage(data: imageData2)!
print("mediumProfilePictureUIImageFile has now been defined as: \(mediumProfilePictureUIImageFile).")
} else {
print("Couldn't get image: Image is nil")
}
} else {
print("Couldn't get response code for some reason")
}
}
}
downloadMediumPicTask.resume()
It crashes here giving a 403 response code. The URL that is being referenced is an expired signature URL from Facebook. Firebase doesn't adjust to get the new appropriate URL, and it was from Firebase that I had been getting the URL. I can't figure out how to get it directly as tried below:
func getUrlOfMediumProfilePic(){
if (FBSDKAccessToken.current() != nil) {
let graphPathPart2 = "me/picture"
let paramsPart2 = ["type":"medium", "redirect":"false"]
let completionHandlerPart2 = { (connection: FBSDKGraphRequestConnection?, result: Any?, error: Error?) in
if let error = error {
print("Medium picture graph call contained an error: \(error.localizedDescription)")
return
} else {
guard connection != nil else {
print("getURLOfLargeProfilePic() function aborted bc connection failed.")
return
}
let results = result! as! NSDictionary
let dataDict = results["data"] as! NSDictionary
stringOfMediumProfilePicURLaka100x100 = dataDict["url"] as! String
print("medium picture graph call results define stringOfMediumProfilePicURLaka100x100 as: \(stringOfMediumProfilePicURLaka100x100)")
}
}
let graphRequest = FBSDKGraphRequest(graphPath: graphPathPart2, parameters: paramsPart2)!
graphRequest.start(completionHandler: completionHandlerPart2)
}else{
print("User not logged in when getURLOfMediumProfilePic() function was run.")
return
}
}
This code yields an error with code 8.
Have you tried this:
https://graph.facebook.com/{id}/picture?width=100&height=100
I don't know swift, so I can't help about syntax. I think you can make http request to url and get image.
Hope this help :)

How do I know when Data finished downloading

I would like to know when the function below has finished downloading the data.
I know I can use a completion handler, but this is in an NSObject and I'd like to know when to return the completion handler for this function, making sure the video is downloaded completely and ready to go, before the function returns the completion handler, and my View Controller resumes it's logic.
Thanks :)
func downloadVideo(identity:JSON_Video){
// use guard to make sure you have a valid url
let videoId = identity.video_id!
let videoString:String = "\(Constants.endPoint_video)\(videoId).mp4"
guard let videoURL = URL(string: videoString) else { return }
let library_url = self.findVideo(video: identity)
if self.findVideo(video: identity) != nil{
print("Video exists. No need to download")
print("Existing video \(library_url!)")
}else{
print("Video not found. Downloading now")
// Variables to input on request
let loginString = Constants.loginString
let loginData = loginString.data(using: String.Encoding.utf8)!
let base64LoginString = loginData.base64EncodedString()
// URL request
var urlRequest = URLRequest(url: videoURL)
urlRequest.httpMethod = "GET"
urlRequest.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
// set up the session
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
// make the request
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
// do stuff with response, data & error here
if let error = error{
print("Data Session Error: \(error.localizedDescription)")
print(response ?? "No response")
return
}
if let data = data {
print("Incoming video....")
print("Data: \(data.description)")
if let finalDatabaseURL = self.videosBaseUrl()?.appendingPathComponent("\(identity.video_id!).mp4"){
print("Copying from: \(videoURL)")
print("Copying to: \(finalDatabaseURL)")
do {
try
data.write(to: finalDatabaseURL)
print("Writing data to file")
// *****
// How do I know when data finished writing?
// Completion handler goes here ?
// *****
}catch{
print("Error writing data to file")
print(error.localizedDescription)
}
}
}
}
})
task.resume()
}
}

I'm trying to read json data and it is returning "false"

Here is my code that is returning a false instead of the json array count.
I must comment that at one point it was working and then it stopped. Please help.
let task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
let urlError = false
if error == nil {
let urlContent = NSString(data: data!, encoding: NSUTF8StringEncoding) as NSString!
let data: NSData = urlContent.dataUsingEncoding(NSUTF8StringEncoding)!
print("data here\(data)”) // I see a lot of data in the logs with this print
do {
let jsonObject = try (NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSArray)!
print(“here is the array count\(jsonObject.count)”) // it never prints this to the logs. What I get is “false"
…The rest of the code...

Handling Facebook Graph API result in iOS SDK with Swift

I just want to request data from Facebook's Graph API, e.g. get the current user's basic info.
The Objective-C doc is: https://developers.facebook.com/docs/ios/graph#userinfo
[FBRequestConnection startForMeWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
/* My question: How do I read the contents of "result" in Swift? */
// Success! Include your code to handle the results here
NSLog(#"user info: %#", result);
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
}
}];
There's no Swift doc yet, and I'm confused about the "result" parameter whose type is "id".
It looks like result contains a dictionary, but it may be nil. In Swift, its type will map to AnyObject?.
So, in Swift, you could do something like:
// Cast result to optional dictionary type
let resultdict = result as? NSDictionary
if resultdict != nil {
// Extract a value from the dictionary
let idval = resultdict!["id"] as? String
if idval != nil {
println("the id is \(idval!)")
}
}
This can be simplified a bit:
let resultdict = result as? NSDictionary
if let idvalue = resultdict?["id"] as? String {
println("the id value is \(idvalue)")
}
Just remember it is not a dictionary all the way down, it is combinations of dictionaries and arrays.
FBRequestConnection.startWithGraphPath("me?fields=feed", completionHandler: { (connection, result, error) -> Void in
if( error == nil){
let fbGraphObject = result as FBGraphObject
let feed = fbGraphObject.objectForKey("feed") as NSMutableDictionary
let data = feed.objectForKey("data") as NSMutableArray
let postDescription = data[0].objectForKey("description") as String
//println( post )
self.fbu.initialUserFeed = feed
self.performSegueWithIdentifier("SelectStreams", sender: self)
}else
{
//TODO Allert to user that something went wrong
println(error)
}
})
I got confused about this in the beginning
This is a simpler way:
let params: [NSObject : AnyObject] = ["redirect": false, "height": 800, "width": 800, "type": "large"]
let pictureRequest = FBSDKGraphRequest(graphPath: "me/picture", parameters: params, HTTPMethod: "GET")
pictureRequest.startWithCompletionHandler({
(connection, result, error: NSError!) -> Void in
if error == nil {
print("\(result)")
let dictionary = result as? NSDictionary
let data = dictionary?.objectForKey("data")
let urlPic = (data?.objectForKey("url"))! as! String
print(urlPic)
} else {
print("\(error)")
}
})
}