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

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...

Related

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()
}
}

Parsing data returned from server using Alamofire and SwiftyJSON, what is the data type returned?

I hope I manage to ask this properly:
I am using Alamofire and SwiftyJSON for managing the JSON files I get from the server.
I have issues with understanding the type of response.result.value , how to cast it to an object I can construct it with SwiftyJSON's JSON(data: data) constructor.
This is my code for the request using Alamofire:
func performRequest() {
// parameters["retry_count"] = retryNum
if let _ = host, let path = path {
let request = Alamofire.request(HOST + path, method: method, parameters: parameters, headers: headers)
request.responseJSON { response in
print("-----")
print(response.response?.statusCode)
print("-----")
// check if responseJSON already has an error
// e.g., no network connection
if let json = response.result.value {
print("--------")
print(json)
print("--------")
}
guard response.result.error == nil else {
print(response.result.error?.localizedDescription ?? "Response Error")
self.completionHandler?(response.result.isSuccess, nil)
self.retryRequest()
return
}
// make sure we got JSON and it's a dictionary
guard let json = response.result.value as? [String: AnyObject] else {
print("didn't get dictionary object as JSON from API")
self.completionHandler?(response.result.isSuccess, nil)
self.retryRequest()
return
}
// make sure status code is 200
guard response.response?.statusCode == 200 else {
// handle status code
self.completionHandler?(response.result.isSuccess, nil)
return
}
self.completionHandler?(response.result.isSuccess, json)
RequestsQueue.sharedInstance.sema.signal()
}
}
This results with this print:
{
numOfShiftsInDay = 3;
shifts = (
{
endTime = "14:00";
startTime = "07:30";
},
{
endTime = "20:00";
startTime = "13:30";
},
{
endTime = "02:00";
startTime = "19:30";
}
);
}
this data type is a [String: AnyObject].
I want to use it to construct a SwiftyJSON JSON object since it is easier for me to parse the data using SwiftyJSON methods..
This is the code I try for parsing it and then using it but obviously it doesn't work:
let json = JSON(data: data)
I get this compilation error:
Cannot convert value of type '[String : AnyObject]?' to expected argument type 'Data'
So how should I go about this?
You need to use JSON(data) instead of JSON(data: data) because this init(data:) wants Data as argument.
Changed line
let json = JSON(data: data)
To
let json = JSON(data)

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

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.

Issue Getting NSData Request To Work In Swift 2.0

I'm hoping someone may be able to help me figure out a snafu I'm having with an app I am trying to write (or learn to write) in Swift 2.0. This previously worked in Swift 1.2, but after the necessary conversions, I am continunally facing the error;
Cannot invoke initializer of type 'NSData' with an argument list of type '(contenOfURL: NSURL, options: NSDataReadingOptions, error:nil)'
Here is my code, slightly truncated, that I am using;
...
class func fetchMinionData() -> [Minion] {
let myURL = "https://myurl/test.json"
let dataURL = NSURL(string: myURL)
let data = NSData(contentsOfURL: dataURL!, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: nil)
//THIS IS THE LINE THAT THROWS THE ERROR
let minionJSON = JSON(data)
var minions = [Minion]()
for (_ , minionDictionary) in minionJSON {
minions.append(Minion(minionDetails: minionDictionary))
}
return minions
}
...
Note that I plan to use the SwiftyJSON library to further parse the data once it is downloaded. I am searching endlessly online, but I just can't seem to figure this out! Thank you!
If you are working with Swift 2, you should not pass the last argument "error". Instead put a try around the NSData initialization. If data needs to be accessed outside take the init result in a var and convert to let Modified code
var optData:NSData? = nil
do {
optData = try NSData(contentsOfURL: dataURL!, options: NSDataReadingOptions.DataReadingMappedIfSafe)
}
catch {
print("Handle \(error) here")
}
if let data = optData {
// Convert data to JSON here
}
Example code for Dictionary :) Swift 2.0
https://github.com/DaRkD0G/LoadExtension/edit/master/LoadExtensionDictionary.swift
enum EHError: ErrorType {
case Nil(String)
case NSData(String)
case JSON(String)
}
extension Dictionary {
/**
Loads a JSON file from the app bundle into a new dictionary
- parameter filename: File name
- throws: PathForResource / NSData / JSON
- returns: Dictionary<String, AnyObject>
*/
static func loadJSONFromBundle(filename: String) throws -> Dictionary<String, AnyObject> {
guard let path = NSBundle.mainBundle().pathForResource(filename, ofType: "json") else {
throw EHError.Nil("[EasyHelper][loadJSONFromBundle][->pathForResource] The file could not be located\nFile : '\(filename).json'")
}
guard let data = try? NSData(contentsOfFile: path, options:NSDataReadingOptions()) else {
throw EHError.NSData("[EasyHelper][loadJSONFromBundle][->NSData] The absolute path of the file not find\nFile : '\(filename)'")
}
guard let jsonDict = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? Dictionary<String, AnyObject> else {
throw EHError.JSON("[EasyHelper][loadJSONFromBundle][->NSJSONSerialization]Error.InvalidJSON Level file '\(filename)' is not valid JSON")
}
return jsonDict
}
}
If I do not do a mistake, for you is that
/**
Loads a JSON file from the app bundle into a new dictionary
- parameter filename: File name
- throws: EHError : PathForResource / NSData / JSON
- returns: [String : AnyObject]
*/
static func loadJSONFromBundle(filename: String, nameJson:String) throws -> [String : AnyObject] {
guard let path = NSBundle.mainBundle().pathForResource(filename, ofType: "json") else {
throw EHError.Nil("[EasyHelper][loadJSONFromBundle][->pathForResource] The file could not be located\nFile : '\(filename).json'")
}
guard let data = try? NSData(contentsOfFile: path, options:NSDataReadingOptions()) else {
throw EHError.NSData("[EasyHelper][loadJSONFromBundle][->NSData] The absolute path of the file not find\nFile : '\(filename)'")
}
guard let jsonDict = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [String : AnyObject] else {
throw EHError.JSON("[EasyHelper][loadJSONFromBundle][->NSJSONSerialization] Invalid JSON\n nameJson '\(nameJson)'\nFile '\(filename)'")
}
return jsonDict
}

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)")
}
})
}