Swift - Crash when try to get JSON values for second time - json

I am trying to get an array of values from a JSON file using Swift. I found the way to get the values printed when a button is pressed using a IBAction method.
The Function is printing the array fine the first time the button is pressed however, if I press the button again the app crashes giving the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
The array that I get the first time from printing jsonResult looks Like:
1: {
Age = 30;
Email = "info#example.com";
Location = Rome;
MyText = "Design Agency";
Name = Admin;
Password = 123456;
REF = 002;
"Reg_Date" = "2015-07-28";
Sex = Male;
Surname = "Mobile App"; }
2: {
Age = 30;
Email = "example#gmail.com";
Location = London;
MyText = "aaaaaaaaa";
Name = Andrew;
Password = 123456;
REF = 001;
"Reg_Date" = "2015-07-28";
Sex = Male;
Surname = Nos; }
It seems that the second time I call the function, it cannot read the file anymore.
Whats wrong with my code? Do I need to close the connection?
#IBAction func login_button(sender: AnyObject) {
searchFunction()
}
func searchFunction() {
var tempUrlValue = loginJsonResults.stringForKey("loginJsonResults")
let urlPath: String = "https://example.com/iOS/users_result.json"
var url: NSURL = NSURL(string: urlPath)!
var request: NSURLRequest = NSURLRequest(URL: url)
var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)!
connection.start()
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
self.data.appendData(data)
}
func connectionDidFinishLoading(connection: NSURLConnection!) {
var err: NSError
var jsonResult: NSMutableArray = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSMutableArray
//Call jsonResult Values
var temporaryString: AnyObject = jsonResult[1]
for (index, jsonResult) in enumerate(jsonResult){
println("\(index + 1): \(jsonResult)")
countUsers++
}
println(countUsers)
}

Related

How to Parse JSON data from a URL and append to a UiLabel with Swift 5

I am trying to get data from Json url for this specific line "ConfirmedCount" from https://raw.githubusercontent.com/BlankerL/DXY-COVID-19-Data/master/json/DXYOverall.json to a UiLabel that I created but keeps getting error. I have been trying to do this for week now.
Here is my code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var labeltest: UILabel!
//the json file url
let URL_HEROES = "https://raw.githubusercontent.com/BlankerL/DXY-COVID-19-Data/master/json/DXYOverall.json";
//the label we create
#IBOutlet weak var labelTest: UILabel!
//A string array to save all the names
var nameArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
//calling the function that will fetch the json
getJsonFromUrl()
}
//this function is fetching the json from URL
func getJsonFromUrl(){
//creating a NSURL
let url = NSURL(string: URL_HEROES)
//fetching the data from the url
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
//printing the json in console
print(jsonObj.value(forKey: "results")!)
//getting the avengers tag array from json and converting it to NSArray
if let heroeArray = jsonObj.value(forKey: "results") as? NSArray {
//looping through all the elements
for results in heroeArray{
//converting the element to a dictionary
if let heroeDict = results as? NSDictionary {
var confirmedCount: Int
//getting the name from the dictionary
if let confirmedCount = heroeDict.value(forKey: "confirmedCount") {
//adding the name to the array
self.nameArray.append((String (format: "1234", confirmedCount as! Int)))
}
}
}
}
OperationQueue.main.addOperation({
//calling another function after fetching the json
//it will show the names to label
self.showNames()
})
}
}).resume()
}
func showNames(){
//looping through all the elements of the array
for confirmedCount in nameArray{
labelTest.text = (confirmedCount)
}
}
}
This is the error that I am getting:
(
{
abroadRemark = "";
confirmedCount = 80422;
confirmedIncr = 120;
curedCount = 49923;
curedIncr = 2663;
currentConfirmedCount = 27515;
currentConfirmedIncr = "-2581";
deadCount = 2984;
deadIncr = 38;
generalRemark = "\U7591\U4f3c\U75c5\U4f8b\U6570\U6765\U81ea\U56fd\U5bb6\U536b\U5065\U59d4\U6570\U636e\Uff0c\U76ee\U524d\U4e3a\U5168\U56fd\U6570\U636e\Uff0c\U672a\U5206\U7701\U5e02\U81ea\U6cbb\U533a\U7b49";
note1 = "\U75c5\U6bd2\Uff1aSARS-CoV-2\Uff0c\U5176\U5bfc\U81f4\U75be\U75c5\U547d\U540d COVID-19";
note2 = "\U4f20\U67d3\U6e90\Uff1a\U65b0\U51a0\U80ba\U708e\U7684\U60a3\U8005\U3002\U65e0\U75c7\U72b6\U611f\U67d3\U8005\U4e5f\U53ef\U80fd\U6210\U4e3a\U4f20\U67d3\U6e90\U3002";
note3 = "\U4f20\U64ad\U9014\U5f84\Uff1a\U7ecf\U547c\U5438\U9053\U98de\U6cab\U3001\U63a5\U89e6\U4f20\U64ad\U662f\U4e3b\U8981\U7684\U4f20\U64ad\U9014\U5f84\U3002\U6c14\U6eb6\U80f6\U4f20\U64ad\U548c\U6d88\U5316\U9053\U7b49\U4f20\U64ad\U9014\U5f84\U5c1a\U5f85\U660e\U786e\U3002";
remark1 = "\U6613\U611f\U4eba\U7fa4\Uff1a\U4eba\U7fa4\U666e\U904d\U6613\U611f\U3002\U8001\U5e74\U4eba\U53ca\U6709\U57fa\U7840\U75be\U75c5\U8005\U611f\U67d3\U540e\U75c5\U60c5\U8f83\U91cd\Uff0c\U513f\U7ae5\U53ca\U5a74\U5e7c\U513f\U4e5f\U6709\U53d1\U75c5";
remark2 = "\U6f5c\U4f0f\U671f\Uff1a\U4e00\U822c\U4e3a 3\Uff5e7 \U5929\Uff0c\U6700\U957f\U4e0d\U8d85\U8fc7 14 \U5929\Uff0c\U6f5c\U4f0f\U671f\U5185\U53ef\U80fd\U5b58\U5728\U4f20\U67d3\U6027\Uff0c\U5176\U4e2d\U65e0\U75c7\U72b6\U75c5\U4f8b\U4f20\U67d3\U6027\U975e\U5e38\U7f55\U89c1";
remark3 = "\U5bbf\U4e3b\Uff1a\U91ce\U751f\U52a8\U7269\Uff0c\U53ef\U80fd\U4e3a\U4e2d\U534e\U83ca\U5934\U8760";
remark4 = "";
remark5 = "";
seriousCount = 6416;
seriousIncr = "-390";
suspectedCount = 520;
suspectedIncr = 143;
updateTime = 1583295001876;
}
)
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file /Users/AbdalQaydi/Desktop/jnews/jnews/ViewController.swift, line 84
2020-03-04 00:26:49.829895-0500 jnews[12702:1192396] Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file /Users/AbdalQaydi/Desktop/jnews/jnews/ViewController.swift, line 84
(lldb)
It looks like it can parse the data but I don't know how to add the json data for line "confirmedCount" to label.
Please any help is really appreciated. I have been trying to figure out how to do this and just can't find a way.
Use Codable to parse the JSON data.
Models:
struct Root: Decodable {
let results: [Result]
let success: Bool
}
struct Result: Decodable {
let currentConfirmedCount, confirmedCount, suspectedCount, curedCount: Int
let deadCount, seriousCount, currentConfirmedIncr, confirmedIncr: Int
let suspectedIncr, curedIncr, deadIncr, seriousIncr: Int
let generalRemark, abroadRemark, remark1, remark2: String
let remark3, remark4, remark5, note1: String
let note2, note3: String
let updateTime: Int
}
Parse the data like,
if let url = URL(string: URL_HEROES) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let data = data {
do {
let response = try JSONDecoder().decode(Root.self, from: data)
let confirmedCountArr = response.results.map { String($0.confirmedCount) }
nameArray.append(contentsOf: confirmedCountArr)
//rest of the code...
} catch {
print(error)
}
}
}.resume()
}

Swift 3 GET request unable to display returned values

Trying to make a GET request with Swift 3 and Xcode8 but not having much luck outputting data I received back from my GET request to the Main.Storyboard either in a label or a text field all I get is all the returned JSON in the console in Xcode8.
There is a snippet of JSON that is returned with my request in Xcode8 which I have attached below for reference. I can access "#encoding" and "#version" but everything else is not able to be accessed and I am not able to figure out why. If this was a web based setup I could just declare a variable and then set it equal to someObject.petfinder[1].shelters etc...
This is my code that is making the request, taking a zipcode from an input field and then building the url and returning it which then is using NSDictionary.
The error I get back in the console is:
"fatal error: unexpectedly found nil while unwrapping an Optional value
2017-06-20 12:15:49.392688 PetFinder[47445:9486946] fatal error: unexpectedly found nil while unwrapping an Optional value"
// SEND HTTP GET REQUEST
// DEFINE SERVER SIDE SCRIPT URL
let scriptUrl = "https://api.petfinder.com/"
let methodType = "shelter.find"
let apiKey = "?key=0000000000000000000000000"
let urlWithParams = scriptUrl + methodType + apiKey + "&location=\(shelterZip)&format=json"
// CREATE NSURL Object
let myUrl = NSURL(string: urlWithParams)
// CREATE URL REQUEST
let request = NSMutableURLRequest(url:myUrl! as URL);
// REQUEST METHOD - GET / POST
request.httpMethod = "GET"
// RUN HTTP REQUEST
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error \(error!)")
return
}
// PRINT OUT RESPONSE STRING
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(String(describing: responseString))")
// CONVERT RECEIVED JSON TO NSDictionary
do {
if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
// Print out dictionary
print(convertedJsonIntoDict)
// Get value by key
let shelterName = convertedJsonIntoDict["shelters"] as? [String: Any]
for(key, pair) in convertedJsonIntoDict {
print("-->\(key) \(pair)")
}
print(shelterName!)
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
task.resume()
}
// SNIPPET OF RETURNED JSON FROM THE TOP
{
"#encoding" = "iso-8859-1";
"#version" = "1.0";
petfinder = {
"#xmlns:xsi" = "http://www.w3.org/2001/XMLSchema-instance";
"#xsi:noNamespaceSchemaLocation" = "http://api.petfinder.com/schemas/0.9/petfinder.xsd";
header = {
status = {
code = {
"$t" = 100;
};
message = {
};
};
timestamp = {
"$t" = "2017-06-20T16:15:49Z";
};
version = {
"$t" = "0.1";
};
};
lastOffset = {
"$t" = 25;
};
shelters = {
shelter = (
{
address1 = {
};
address2 = {
};
city = {
"$t" = Nebraska;
};
country = {
"$t" = US;
};
email = {
"$t" = "wooffun#woof.net";
};
fax = {
};
id = {
"$t" = NE117;
};
latitude = {
"$t" = "13.004";
};
longitude = {
"$t" = "-31.449";
};
name = {
"$t" = WOOF COMPANY;
};
phone = {
};
state = {
"$t" = NE;
};
zip = {
"$t" = 68001;
};
},
First of all – and as always
Do not use NSDictionary in Swift. You throw away the type information.
Do not use Foundation classes like NSURL, NS(Mutable)URLRequest if there is a native Swift counterpart.
A GET request does not require an URLRequest at all, it's the default.
Second of all lets use a type alias for convenience reasons.
typealias JSONDictionary = [String:Any]
This code is supposed to extract the keys and values you are looking for
let scriptUrl = "https://api.petfinder.com/"
let methodType = "shelter.find"
let apiKey = "?key=0000000000000000000000000"
let urlWithParams = scriptUrl + methodType + apiKey + "&location=\(shelterZip)&format=json"
// CREATE NSURL Object
let myUrl = URL(string: urlWithParams)!
// RUN HTTP REQUEST
let task = URLSession.shared.dataTask(with: myUrl) { data, response, error in
if error != nil {
print("error \(error!)")
return
}
// CONVERT RECEIVED JSON TO NSDictionary
do {
if let rootDictionary = try JSONSerialization.jsonObject(with: data!) as? JSONDictionary,
let petfinder = rootDictionary["petfinder"] as? JSONDictionary {
// Get value by key
if let shelters = petfinder["shelters"] as? JSONDictionary,
let shelter = shelters["shelter"] as? [JSONDictionary] {
for item in shelter {
for (key, value) in item {
print("-->\(key) \(value)")
}
}
}
}
} catch {
print(error.localizedDescription)
}
}
task.resume()

Swift: Implementing Find-or-Create Efficiently

So I set up some data from an API to create a managed object, How do I determine whether the managed object already exists (in my example, every object has a unique id), and create it if it does not.
// set up core data
var appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var context:NSManagedObjectContext = appDel.managedObjectContext!
// Get data from API
let urlPath = "http://www.example.com"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let getMovies = session.dataTaskWithURL(url!, completionHandler: {
data, response, error -> Void in
if error != nil {
println(error)
} else {
// Parse the JSON data from API
var moviesResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
if let subjects = moviesResult["subjects"] as? [[NSObject:AnyObject]] {
var movies = [[String:NSString]()]
var movie:AnyObject
var newMovieItem:NSManagedObject
// Loop through the arrays returned by API to get each movie
for (var i = 0 ; i < subjects.count ; i++) {
// Initialize the movies array
movies.append([String:NSString]())
movie = subjects[i] as NSDictionary
movies[i]["title"] = movie["title"] as? NSString
movies[i]["id"] = movie["id"] as? NSString
newMovieItem = NSEntityDescription.insertNewObjectForEntityForName("Movies", inManagedObjectContext: context) as! NSManagedObject
newMovieItem.setValue(movies[i]["title"], forKey: "title")
newMovieItem.setValue(movies[i]["id"], forKey: "id")
context.save(nil)
}
var request = NSFetchRequest(entityName: "Movies")
request.returnsObjectsAsFaults = false
var results = context.executeFetchRequest(request, error: nil)
}
}
})
getMovies.resume()

EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) with dataTaskWithUrl

I'm using the google places api to search for nearby places. However, I only want places of specific types. The code (seen below) works when I specify just one type, but when I add a second my code runs and promptly give me a EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) error on this line:
session.dataTaskWithURL(url!, completionHandler: { (data : NSData!, response : NSURLResponse!, error : NSError!) -> Void in
I know the url is valid. I can plug it into the browser and see the json, so I don't understand what the problem is.
func search(location : CLLocationCoordinate2D, radius : Int, callback : (items : [Attraction]?, errorDescription : String?) -> Void) {
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=37.7873589,-122.408227&radius=4000&types=aquarium|art_gallery&key=YOURKEY"
var url = NSURL(string: urlString)
var session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
session.dataTaskWithURL(url!, completionHandler: { (data : NSData!, response : NSURLResponse!, error : NSError!) -> Void in
if error != nil {
callback(items: nil, errorDescription: error.localizedDescription)
}
if let statusCode = response as? NSHTTPURLResponse {
if statusCode.statusCode != 200 {
callback(items: nil, errorDescription: "Could not continue. HTTP Status Code was \(statusCode)")
}
}
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
callback(items: GooglePlaces.parseFromData(data), errorDescription: nil)
})
}).resume()
}
class func parseFromData(data : NSData) -> [Attraction] {
var attractions = [Attraction]()
var json = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
var results = json["results"] as? [NSDictionary]
for result in results! {
var placeId = result["place_id"] as String
var image = result["icon"] as String
var name = result["name"] as String
var ratingString = ""
var types = result["types"] as [String]
println(types)
if result["rating"] != nil {
var rating = result["rating"] as Double
ratingString = "\(rating)"
}
var coordinate : CLLocationCoordinate2D!
if let geometry = result["geometry"] as? NSDictionary {
if let location = geometry["location"] as? NSDictionary {
var lat = location["lat"] as CLLocationDegrees
var long = location["lng"] as CLLocationDegrees
coordinate = CLLocationCoordinate2D(latitude: lat, longitude: long)
var placemark = MKPlacemark(coordinate: coordinate, addressDictionary: nil)
var attraction = Attraction(id: placeId, imageUrl: "image url", locationName: name, ratingAvg: "\(ratingString)", types: types, placemarker: placemark)
attractions.append(attraction)
}
}
}
return attractions
}
I know the url is valid
The URL is not valid. You do not know what you think you know. Listen to the runtime. It knows more than you do.
Just try this code alone (in a playground, for instance):
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=37.7873589,-122.408227&radius=4000&types=aquarium|art_gallery&key=YOURKEY"
let url = NSURL(string:urlString)
url is nil. And that's your problem. You cannot force-unwrap nil; you will crash if you do.
Once you acknowledge this, you can start to think about why the URL is not valid. (It's pretty obvious why that might be.) Learning to believe the compiler and the runtime is key to successful programming.
HINT: Form your URL like this and all is well:
let url2 = NSURL(scheme: "https", host: "maps.googleapis.com", path: "/maps/api/place/nearbysearch/json?location=37.7873589,-122.408227&radius=4000&types=aquarium|art_gallery&key=YOURKEY")
Why do you suppose that is? Look at the docs and see what this initializer does for you...
I would use .stringByAddingPercentEscapesUsingEncoding()
var urlString = "http://example.com/?foo=bar|baz"
if var escapedURLString = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
NSURL(string: escapedURLString)
}
Returns: http://example.com/?foo=bar%7Cbaz

Swift: Return JSON string from NSURLSession task

I'd like to get token as String type, however the following code returns error as " "String" is not convertible to "Void" ".
Could you tell me what is the problem?
In order to parse JSON, I used SwiftyJSON
func authentication() -> String {
let request = NSMutableURLRequest(URL: NSURL(string: "https://~~~/v2/authenticate/api")!)
request.HTTPMethod = "POST"
var loginID = "my_ID"
var apiKey = "my_APIKEY"
var postString:NSString = "login_id=\(loginID)&api_key=\(apiKey)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
println("response = \(response)")
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("responseString = \(responseString)")
let json = JSON(data:data)
if let token = json["auth_token"].stringValue{
println("\(token)")
return token ///Error Here
}
}
task.resume()
}
※Edited Jan6th 7:50(GMP+9hr)
I edited as following, however I got error as ""Use of unresolved identifier "tokenString".
Please tell me how to solve the problem.
func authentication() -> String {
let request = NSMutableURLRequest(URL: NSURL(string: "https://~~~/v2/authenticate/api")!)
request.HTTPMethod = "POST"
var loginID = "my_ID"
var apiKey = "my_APIKEY"
var postString:NSString = "login_id=\(loginID)&api_key=\(apiKey)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
println("response = \(response)")
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("responseString = \(responseString)")
let json = JSON(data:data)
if let token = json["auth_token"].stringValue{
println("\(token)")
tokenString = self.didReceiveAuthToken(token)///Edited
}
}
task.resume()
return tokenString
}
func didReceiveAuthToken(token : String) ->String{
return token
}
The dataTaskWithRequest closure takes a return type of void. Your method that returns a string ends immediately after task.resume() is executed and does not return anything.
Your basic problem is that you're applying synchronous thinking to an asynchronous task. One easy suggestion is to have authentication() return void (ie, nothing), and then make a separate method like didReceiveAuthToken(token : String) that is called by your completion handler when the token is received.