I get datas from the url with JSON. When I printing the variable of berabereOran, it shows in 1 or 2 seconds on the Xcode console. But it shows in uilabel in 8 or 10 seconds. I don't know because of what.
Note: In my other project, I used tableView, because of this, I added this code: dispatch_async(dispatch_get_main_queue()) { self.tableView.reloadData() }
But this time, I don't use tableView. What should I write here?
MY CODES:
let urls = NSURL(string: "http://gigayt.com/mackolik/?code=101")
let sessions = NSURLSession.sharedSession().dataTaskWithURL(urls!){
data, response, error -> Void in
if (error != nil){ print(error) }
do {
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
let evsahibiLogo:String = jsonResult["ev-sahibi-logo"] as! String
let deplasmanLogo:String = jsonResult["deplasman-logo"] as! String
let berabereOran:String = jsonResult["berabere-oran"] as! String
print(berabereOran) //shows in 1-2 seconds
self.macsonusifirLabel.text = "(\(berabereOran))" //shows in 8-10 seconds
}
dispatch_async(dispatch_get_main_queue()) {
//self.tableView.reloadData()
}
}
catch { print(error) }
}
sessions.resume()
Try this one :-
let urls = NSURL(string: "http://gigayt.com/mackolik/?code=101")
let sessions = NSURLSession.sharedSession().dataTaskWithURL(urls!){
data, response, error -> Void in
if (error != nil){ print(error) }
do {
dispatch_async(dispatch_get_main_queue()) {
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
let evsahibiLogo:String = jsonResult["ev-sahibi-logo"] as! String
let deplasmanLogo:String = jsonResult["deplasman-logo"] as! String
let berabereOran:String = jsonResult["berabere-oran"] as! String
print(berabereOran) //shows in 1-2 seconds
self.macsonusifirLabel.text = "(\(berabereOran))" //shows in 8-10 seconds
}
}
}
catch { print(error) }
}
sessions.resume()
}
Related
For some reason the JSON object from parsing doesnt update after network calls to and api we built. I check the endpoint and now for a fact it updates right away. I have a timer being called every 10 sec to make the call but the parsed json doesnt update until after a minute or so. I have tried putting it on the main thread and that still doesnt work. Here is my code:
#objc func getLaunches() {
let simulator = UserDefaults.standard.string(forKey: self.launchSimulator)
if(simulator == self.password){
print("they are the same")
}
guard let launchUrl = URL(string: launchesURL) else {
return
}
let request = URLRequest(url: launchUrl)
DispatchQueue.main.async { [weak self] in
let task = URLSession.shared.dataTask(with: request, completionHandler: {
(data, response, error) -> Void in
if let error = error {
print(error)
return
}
// Parse JSON data
if let data = data {
self?.launches.removeAll()
self?.launches = (self!.parseJsonData(data: data))
let nextlaunch = self?.launches[0]
// Reload table view
self?.hours = nextlaunch?.time
self?.yearMonth = nextlaunch?.date
var fulltime = self?.yearMonth
fulltime!.insert("-", at: fulltime!.index(fulltime!.startIndex, offsetBy: 4))
fulltime!.insert("-", at: fulltime!.index(fulltime!.startIndex, offsetBy: 7))
fulltime = fulltime! + " "
fulltime = fulltime! + self!.hours
let fullFormatter = DateFormatter()
fullFormatter.dateFormat = "YYYY-MM-dd HH:mm"
fullFormatter.timeZone = TimeZone(abbreviation: "EST")
self?.launchDate = fullFormatter.date(from: fulltime!)
self?.getCountdown()
}
})
task.resume()
}
}
//parse launch info from json to dictionary into launches object
func parseJsonData(data: Data) -> [NextLaunch] {
var launches = [NextLaunch]()
do {
let jsonResult = try JSONSerialization.jsonObject(with: data, options:
JSONSerialization.ReadingOptions.allowFragments) as? NSDictionary
let jsonLaunches = jsonResult?["launches"] as! [NSDictionary]
for jsonLaunch in jsonLaunches {
let launch = NextLaunch()
launch.date = jsonLaunch["date"] as! String
launch.time = jsonLaunch["time"] as! String
if(launch.time == ""){
launch.time = "00:00"
}
launch.mission = jsonLaunch["mission"] as! String
launch.launchpad = jsonLaunch["launch_pad"] as! String
launch.image = jsonLaunch["image"] as! String
launch.delay = jsonLaunch["delayed"] as! String
//show delay image if it is delayed
if(launch.delay == "1"){
self.delayed()
}else{
self.notDelayed()
}
launches.append(launch)
}
} catch {
print(error)
}
return launches
}
You need
DispatchQueue.main.async {
self?.getCountdown()
}
As the response of URLSession.shared.dataTask(with: occurs in a background thread
Hello I am having an error when parsing some JSON in Swift, my error is:
'Invalid conversion from throwing function of type '(_, _, _) throws -> Void' to non-throwing function type '(NSData?, NSURLResponse?, NSError?) -> Void'
I think this is something to do with catching an error somewhere but I cannot figure out where this would go could anyone help me please? Here is my source code:
import UIKit
import CoreData
class MasterViewController: UITableViewController {
var detailViewController: DetailViewController? = nil
override func viewDidLoad() {
super.viewDidLoad()
var appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var context: NSManagedObjectContext = appDel.managedObjectContext
let url = NSURL(string: "https://www.googleapis.com/blogger/v3/blogs/10861780/posts?key=AIzaSyBwmI4AzMnBmr7oSVeL0EHdzMjXV1aATnQ")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
if error != nil {
print(error)
} else {
//print(NSString(data: data!, encoding: NSUTF8StringEncoding))
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions(rawValue: 0)) as! NSDictionary
if jsonResult.count > 0 {
if let items = jsonResult["items"] as? NSArray {
for items in items {
print(items)
if let title = items["title"] as? String {
if let content = items["content"] as? String {
var newPost: NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName("Posts", inManagedObjectContext: context)
newPost.setValue(title, forKey: "title")
newPost.setValue(content, forKey: "content")
do {
try context.save()
}
}
}
}
}
}
} catch let error as NSError {
print(error)
}
var request = NSFetchRequest(entityName: "Posts")
request.returnsObjectsAsFaults = false
var results = try context.executeFetchRequest(request)
self.tableView.reloadData()
}
})
task.resume()
}
Thanks!
It looks like you haven't taken care of all the throwing functions using do-try-catch method.
According to the Swift 3 Documentation at https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html
In your case, you seem to have forgotten to take care of the error thrown at var- results. Also, you haven't handled the throwing function session.dataTaskWithURL with a do-try-catch method.
You should not be getting this error if you modify your code as following:
override func viewDidLoad() {
super.viewDidLoad()
var appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var context: NSManagedObjectContext = appDel.managedObjectContext
let url = NSURL(string: "https://www.googleapis.com/blogger/v3/blogs/10861780/posts?key=AIzaSyBwmI4AzMnBmr7oSVeL0EHdzMjXV1aATnQ")
let session = NSURLSession.sharedSession()
do {
let task = try session.dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
if error != nil {
print(error)
} else {
//print(NSString(data: data!, encoding: NSUTF8StringEncoding))
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions(rawValue: 0)) as! NSDictionary
if jsonResult.count > 0 {
if let items = jsonResult["items"] as? NSArray {
for items in items {
print(items)
if let title = items["title"] as? String {
if let content = items["content"] as? String {
var newPost: NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName("Posts", inManagedObjectContext: context)
newPost.setValue(title, forKey: "title")
newPost.setValue(content, forKey: "content")
do {
try context.save()
} catch let error1 as NSError { // this is for context.save
print(error1)
}
}
}
}
}
}
}
var request = NSFetchRequest(entityName: "Posts")
request.returnsObjectsAsFaults = false
do{
var results = try context.executeFetchRequest(request)
} catch let error2 as NSError { // this is for context.executeFetchRequest
print(error2)
}
self.tableView.reloadData()
}
})
task.resume()
} catch let error3 as NSError { // this is for session.dataTaskWithURL
print(error3)
}
}
Hope this helps ! Cheers !
I'm trying to make an application using Opendata.
This is my JSON data: http://datatank.stad.gent/4/infrastructuur/publieksanitair
The problem I have is that I don't know how to parse this JSON file.
I'm always getting "Data does not contain a root object."
So it goes wrong in the Service.swift file. I'm sure my request works because when debugging I see data is returned, but I don't know how to handle it.
You can pull my project from: https://github.com/StijnPil/iOSProjectShared/tree/develop
but I've also put the important code below:
Service.swift
import Foundation
class Service
{
enum Error: ErrorType
{
case InvalidJsonData(message: String?)
case MissingJsonProperty(name: String)
case MissingResponseData
case NetworkError(message: String?)
case UnexpectedStatusCode(code: Int)
}
static let sharedService = Service()
private let url: NSURL
private let session: NSURLSession
private init() {
let path = NSBundle.mainBundle().pathForResource("Properties", ofType: "plist")!
let properties = NSDictionary(contentsOfFile: path)!
url = NSURL(string: properties["baseUrl"] as! String)!
session = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration())
}
func createFetchTask(completionHandler: Result<[PubliekSanitair]> -> Void) -> NSURLSessionTask {
return session.dataTaskWithURL(url) {
data, response, error in
let completionHandler: Result<[PubliekSanitair]> -> Void = {
result in
dispatch_async(dispatch_get_main_queue()) {
completionHandler(result)
}
}
guard let response = response as? NSHTTPURLResponse else {
completionHandler(.Failure(.NetworkError(message: error?.description)))
return
}
guard response.statusCode == 200 else {
completionHandler(.Failure(.UnexpectedStatusCode(code: response.statusCode)))
return
}
guard let data = data else {
completionHandler(.Failure(.MissingResponseData))
return
}
do {
guard let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? [NSDictionary] else {
completionHandler(.Failure(.InvalidJsonData(message: "Data does not contain a root object.")))
return
}
//old code
//let lots = try json.filter { $0["city"]?["name"] as? String == "Gent" }.map { try ParkingLot(json: $0) }
//new code
let lots = try json.map{ try PubliekSanitair(json: $0)}
completionHandler(.Success(lots))
} catch let error as Error {
completionHandler(.Failure(error))
} catch let error as NSError {
completionHandler(.Failure(.InvalidJsonData(message: error.description)))
}
}
}
}
Result.swift
enum Result<T>
{
case Success(T)
case Failure(Service.Error)
}
PubliekSanitair.swift
import Foundation
class PubliekSanitair
{
let type_sanit: String
init(type_sanit: String){
self.type_sanit = type_sanit
}
}
extension PubliekSanitair
{
convenience init(json: NSDictionary) throws {
guard let document = json["Document"] as? NSDictionary else{
throw Service.Error.MissingJsonProperty(name: "Document")
}
guard let folder = document["Folder"] as? NSDictionary else{
throw Service.Error.MissingJsonProperty(name: "Folder")
}
guard let placemark = folder["Placemark"] as? NSDictionary else{
throw Service.Error.MissingJsonProperty(name: "Placemark")
}
guard let extendedData = placemark["ExtendedData"] as? NSDictionary else{
throw Service.Error.MissingJsonProperty(name: "Placemark")
}
guard let schemaData = extendedData["SchemaData"] as? NSDictionary else{
throw Service.Error.MissingJsonProperty(name: "Placemark")
}
guard let simpleData = schemaData["SimpleData"] as? NSDictionary else{
throw Service.Error.MissingJsonProperty(name: "Placemark")
}
guard let type_sanit = simpleData[0]!["#text"] as? String else{
throw Service.Error.MissingJsonProperty(name: "#text in type_sanit")
}
self.init(type_sanit: type_sanit)
}
}
I have a tableview. cekilecek_data contains tableview datas. I get some datas from JSON and I want to append this datas to tableview. But I have to do this inside of jsonGetir(). However, it does not work. kodJSON and kodlarJSON are nil in viewDidLoad(). Also, cekilecek_data.append(kodJSON[1]) it doesn't add the datas to the table.
How do I fix it?
var cekilecek_data = ["Fenerbahçe", "Chelsea", "Arsenal"]
var kodlarJSON:String = ""
var kodJSON:[String] = []
func jsonGetir(){
let urls = NSURL(string: "http://gigayt.com/mackolik/deneme.php")
let sessions = NSURLSession.sharedSession().dataTaskWithURL(urls!){
data, response, error -> Void in
if (error != nil){ print(error) }
do {
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
kodlarJSON = jsonResult["kodlar"] as! String //101,102,103
kodJSON = kodlarJSON.componentsSeparatedByString(",")
cekilecek_data.append(kodJSON[1]) //Here doesn't work!
}
}
catch { print(error) }
}
sessions.resume()
}
Reload your tableview after you got data from server this way:
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
And your final code will be:
func jsonGetir(){
let urls = NSURL(string: "http://gigayt.com/mackolik/deneme.php")
let sessions = NSURLSession.sharedSession().dataTaskWithURL(urls!){
data, response, error -> Void in
if (error != nil){ print(error) }
do {
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
self.kodlarJSON = jsonResult["kodlar"] as! String //101,102,103
self.kodJSON = self.kodlarJSON.componentsSeparatedByString(",")
self.cekilecek_data.append(self.kodJSON[1]) //Here doesn't work!
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData() //Reload tableview here.
}
}
catch { print(error) }
}
sessions.resume()
}
With kodJSON = kodlarJson.componentsseparatedByString(",") you are creating an Array of only one object. Then with cekilecke_data.append(kodJSON[1]) you are trying to append your data with the second object from this array that you have only set one object to.
do {
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
kodlarJSON = jsonResult["kodlar"] as! String
kodJSON = kodlarJSON.componentsSeparatedByString(",")
// this line sets kodJSON:[String] to ["kodlar"]
cekilecek_data.append(kodJSON[1]) //Here doesn't work!
// this tries to append cekilecek_data from index [1] or second slot of kodJSON which only has one entry
}
}
if you change line to kodlarJSON = jsonResult["kod,lar"] as! String, it would work because kodJSON[1] would equal "lar"
let task = session.dataTaskWithURL(url!, completionHandler: {
data, response, error -> Void in
if (error != nil) {
println(error)
} else {
let jsonresult = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
var dummyfeed:AnyObject
//println(jsonresult)
for var i = 0; i < jsonresult["feed"]!.count; i++ {
self.feeds.append([String:String]())
dummyfeed = jsonresult["feed"]![i] as NSDictionary
self.feeds[i]["id"] = dummyfeed["id"] as? String
self.feeds[i]["name"] = dummyfeed["name"] as? String
self.feeds[i]["status"] = dummyfeed["status"] as? String
self.feeds[i]["profilePic"] = dummyfeed["profilePic"] as? String
self.feeds[i]["timeStamp"] = dummyfeed["timeStamp"] as? String
self.feeds[i]["url"] = dummyfeed["url"] as? String
}
}
})
task.resume()
So Feeds is a global variable, so that I display the picture of each entry in Feeds on a table view. But it's calling asynchronously println(self.feeds) inside the task variable and println(feeds) outside of the task variable are differnent. How do I make it synchronously?
Do not make it run synchronously. Run it asynchronously, but then synchronize the interaction with feeds. The simplest way to achieve that it to dispatch the updating of the feeds back to the main queue and reloadData for the table view. This eliminates the possibility that you'll be using it from the main queue while it's mutating in the background, but avoids the horrible UX of doing this network request synchronously:
let task = session.dataTaskWithURL(url!) { data, response, error in
if (error != nil) {
println(error)
} else {
var parseError: NSError?
if let jsonresult = NSJSONSerialization.JSONObjectWithData(data, options:nil, error: nil) as? NSDictionary {
if let receivedFeeds = jsonresult["feed"] as? [[String: AnyObject]] {
dispatch_async(dispatch_get_main_queue()) {
self.feeds = [[String: String]]()
for receivedFeed in receivedFeeds {
var outputFeed = [String : String]()
outputFeed["id"] = receivedFeed["id"] as? String
outputFeed["name"] = receivedFeed["name"] as? String
outputFeed["status"] = receivedFeed["status"] as? String
outputFeed["profilePic"] = receivedFeed["profilePic"] as? String
outputFeed["timeStamp"] = receivedFeed["timeStamp"] as? String
outputFeed["url"] = receivedFeed["url"] as? String
self.feeds.append(outputFeed)
}
self.tableView.reloadData()
}
} else {
println("did not find `feed`")
}
} else {
println("problem parsing JSON: \(parseError)")
}
}
}
task.resume()
That should be a little more robust handling errors and employs asynchronous pattern of letting request run asynchronously, but dispatch updating of model object and UI back to the main thread.
let task = session.dataTaskWithURL(url!, completionHandler: {
data, response, error -> Void in
if (error != nil) {
println(error)
} else {
let jsonresult = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
var dummyfeed:AnyObject
//println(jsonresult)
for var i = 0; i < jsonresult["feed"]!.count; i++ {
self.feeds.append([String:String]())
dummyfeed = jsonresult["feed"]![i] as NSDictionary
dispatch_async(dispatch_get_main_queue()) {
self.feeds[i]["id"] = dummyfeed["id"] as? String
self.feeds[i]["name"] = dummyfeed["name"] as? String
self.feeds[i]["status"] = dummyfeed["status"] as? String
self.feeds[i]["profilePic"] = dummyfeed["profilePic"] as? String
self.feeds[i]["timeStamp"] = dummyfeed["timeStamp"] as? String
self.feeds[i]["url"] = dummyfeed["url"] as? String
}
}
self.tableView.reloadData()
}
})
task.resume()
Hey Rob, I did what I think you tell me to do, and feeds is still empty :(
I have same problem my code is was working fine, but now, using dataTaskWithURL it didn't return any data, or even error. I think issue is iOS 8.2 I upgraded.