I am trying to get a list of users that is following me, but it doesn't seems to give me any result. This is the code I am using:
func followers(){
print("1")
let url = URL(string: "https://api.instagram.com/v1/users/self/followed-by?access_token=\(self.currentAccessTolken)")
URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
print("2")
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
print("3")
if let userJson = json["data"] as? [String : AnyObject] {
print("4")
if let username = userJson["username"] as? String {
print("username: \(username)")
}
if let fullname = userJson["full_name"] as? String {
print("full name: \(fullname)")
}
}
} catch let error as NSError {
print(error)
}
}).resume()
}
API: https://www.instagram.com/developer/endpoints/relationships/#get_users_followed_by
The printn("1"), printn("2") and printn("3") shows up in the event log, but not the printn("4"). Also it doesn't give me any result of either username or full name. The scopes I use is: basic+follower_list+public_content+relationships. Anyone knows what may be wrong here?
Related
I need to fetch some quizzes for my application from the server. Unfortunately, it seems that URLSession.DataTask.shared is not working. How do I fix the problem?
This is for Swift 4.
import Foundation
import UIKit
class QuizService {
let baseUrl = "https://iosquiz.herokuapp.com/api/quizzes"
func fetchQuizzes(completion: #escaping (([Quiz]?) -> Void)) -> Void {
if let url = URL(string: baseUrl) {
let request = URLRequest(url: url)
let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
if let resultsList = json as? [String: Any], let results = resultsList["quizzes"] as? [[String: Any]] {
let quizzes = results.map({ json -> Quiz? in
print(json)
if
let title = json["title"] as? String,
let id = json["id"] as? Int,
let level = json["level"] as? Int,
let description = json["description"] as? String,
let category = json["category"] as? String,
let questions = json["questions"] as? [String: Any],
let imageUrl = json["image"] as? String {
let quiz=Quiz(id:id,title:title,descript:description,category:category,level:level,imageUrl:imageUrl,questions:questions)
return quiz
} else {
return nil
}
}).filter { $0 != nil } .map { $0! }
completion(quizzes)
} else {
completion(nil)
}
} catch {
completion(nil)
}
} else {
completion(nil)
}
}
dataTask.resume()
} else {
completion(nil)
}
}
}
My error is that field of quizzes are null, so my code is not working in my view controller.
I took a look at the response here https://iosquiz.herokuapp.com/api/quizzes.
The "questions" should be array of dictionaries instead of dictionary.
so it should works if you replace this line
let questions = json["questions"] as? [String: Any]
with this line
let questions = json["questions"] as? [[String: Any]]
BTW, I prefer to extract the logic of parsing json into another method to keep fetchQuizzes method simple.
Hope this helps!
I have the following code to get the path between two points in Google maps iOS SDK. However, I am not receiving any data back or any errors even.
let url = URL(string: "http://maps.googleapis.com/maps/api/directions/json?origin=\(latitude),\(longitude)&destination=\(finallat),\(finallong)&key=**************")
URLSession.shared.dataTask(with: url!) { (data:Data?, response:URLResponse?, error:Error?) in
if let data = data {
do {
// Convert the data to JSON
let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
if let json = jsonSerialized, let url = json["url"], let explanation = json["explanation"] {
print(url)
print(explanation)
}
} catch let error as NSError {
print(error.localizedDescription)
}
} else if let error = error {
print(error.localizedDescription)
}
}
You don't do anything with the dataTask so it isn't actually being called. You need to call resume().
let url = URL(string: "http://maps.googleapis.com/maps/api/directions/json?origin=\(latitude),\(longitude)&destination=\(finallat),\(finallong)&key=**************")
let task = URLSession.shared.dataTask(with: url!) { (data:Data?, response:URLResponse?, error:Error?) in
if let data = data {
do {
// Convert the data to JSON
let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
if let json = jsonSerialized, let url = json["url"], let explanation = json["explanation"] {
print(url)
print(explanation)
}
} catch let error as NSError {
print(error.localizedDescription)
}
} else if let error = error {
print(error.localizedDescription)
}
}
task.resume()
I try to get information about the weather hourly from the Dark Sky API, but the code stops working at the if let data = hourly["data"] as? [String : AnyObject] line (checked with printing stuff after every line). I want to know what is wrong with my code. I think it could be something with the "data" let, but I don't know for sure.
let Task2 = URLSession.shared.dataTask(with: urlRequestDark) { (data, response, error) in
if error == nil {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
if let hourly = json["hourly"] as? [String : AnyObject] {
if let data = hourly["data"] as? [String : AnyObject]{
if let hourNum = data["14"] as? [String : AnyObject] {
if let chanceRain = hourNum["precipProbability"] as? Float{
self.chanceHour1 = String(chanceRain)
}
DispatchQueue.main.sync {
self.ChanceRainLabel.text = self.chanceHour1
}
}
}
}
} catch let jsonError {
print(jsonError.localizedDescription)
}
}
}
Task2.resume() test
The strange part is, this does work:
let urlRequestDark = URLRequest(url: URL (string: "https://api.darksky.net/forecast/(API Key)/(coordinates)")!)
let Task = URLSession.shared.dataTask(with: urlRequestDark) { (data, response, error) in
if error == nil {
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
if let currently = json["currently"] as? [String : AnyObject] {
if let chance2 = currently["precipProbability"] as? Float{
print(String(chance2))
self.chance = String(Int(chance2 * 100)) + "%"
self.PreType = currently["precipType"] as? String
}
if let _ = json["error"]{
}
DispatchQueue.main.sync{
self.TypeLabel.text = self.PreType
self.ChanceLabel.text = self.chance
}
}
}catch let jsonError{
print(jsonError.localizedDescription)
}
}
}
Task.resume()
You've made couple mistakes.
First, "data" is an array of dictionaries, so it should be cast to [[String : AnyObject]].
Second, you're trying to subscript array by String, not Int.
Third, using self in escaping closures potentially creates retain cycles.
Let me propose you some fixed and adjusted code.
let task2 = URLSession.shared.dataTask(with: urlRequestDark) { [weak self] (data, response, error) in
guard error == nil else { return }
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String : AnyObject],
let hourly = json["hourly"] as? [String : AnyObject],
let data = hourly["data"] as? [[String : AnyObject]],
data.count > 14,
let chanceRain = data[14]["precipProbability"] as? Float {
self?.chanceHour1 = String(chanceRain)
DispatchQueue.main.sync {
self?.ChanceRainLabel.text = self?.chanceHour1
}
}
} catch let jsonError {
print(jsonError.localizedDescription)
}
}
task2.resume()
Try like this
import UIKit
class WebService: NSObject {
var session = URLSession()
public class var sharedInstance: WebService {
struct Singleton {
static let instance = WebService()
}
return Singleton.instance
}
override init() {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 30.0
configuration.timeoutIntervalForResource = 60.0
session = URLSession(configuration: configuration)
}
public func weatherData(coordinate:String,APIkey:String,completion:#escaping (_ responsedata:NSDictionary?,_ error:NSError?) -> Void) {
var Baseurl = "https://api.darksky.net/forecast/\(APIkey)/\(coordinate)"
Baseurl = Baseurl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let weatherRequestUrl = URL(string: Baseurl)
let request = NSMutableURLRequest(url: weatherRequestUrl!)
let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
guard error == nil && data != nil else {
return
}
if let httpStatus = response as? HTTPURLResponse{
if httpStatus.statusCode != 200 {
print("Something is wrong")
}
}
do {
let WindlocationData = try JSONSerialization.jsonObject(with: data! as Data, options:.allowFragments) as! NSDictionary
print(WindlocationData)
completion(WindlocationData,nil)
}
catch let error as NSError {
completion(nil,error)
}
}
task.resume()
}
}
And call API like this!
func callAPI(latlong:String,APIkeyParm:String) {
WebService.sharedInstance.weatherData(coordinate: latlong,APIkey: APIkeyParm) { (responsData, error) in
if error == nil{
print("Response data is-\(responsData)")
}
}
}
Call the method like this
let latlongStr = "\(latitude),\(longitude)"
self.callAPI(latlong: latlongStr,APIkeyParm: "APIKeyString")
One importent thing you need to pass latlong like this format 23.022504999999999,72.571362100000002
I have this long function here which makes a bunch of API calls, parses through data and returns two arrays representing a bunch of sight-seeing locations (one array holds the latitudes, one holds the latitudes). The issue I am having is determining when the two arrays are finished being populated. Ideally, I would like to be able to place
print("ArrayCount = \(self.latArray.count)")
somewhere in my code and receive a single print statement in the console reading ArrayCount = 123. However everywhere I place the print statement I get either an array count of 0 or a loop of values being printed out as they are added (1..2..3.. ... ..123). Thanks in advance!
func someFunction()
{
let url:URL = URL(string: "...")
let task = URLSession.shared.dataTask(with: URLRequest(url: url))
{
data, response, error in
if error != nil
{
print("ERROR IN API REQUEST: \(error!.localizedDescription)")
}
else
{
do
{
if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
{
if let layerOne = parsedData["one"] as? [String: Any]
{
if let layerTwo = layerOne["two"] as? [[String: Any]]
{
for layerThree in layerTwo
{
if let variableName = layerThree["value"] as? String
{
let innerUrl:URL = URL(string: "...")!
let innerTask = URLSession.shared.dataTask(with: URLRequest(url: innerUrl))
{
data, response, error in
if error != nil
{
print("ERROR IN API REQUEST: \(error!.localizedDescription)")
}
else
{
do
{
if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
{
if let layerA = parsedData["A"] as? [String: Any]
{
if let lat = layerA["Latitude"] as? String, let long = layerA["Longitude"] as? String
{
self.latArray.append(lat)
self.longArray.append(lon)
}
}
}
}
catch
{
print("ERROR IN JSON SERIALIZATION")
}
}
}
innerTask.resume()
}
}
}
}
}
}
catch
{
print("ERROR IN JSON SERIALIZATION")
}
}
}
task.resume()
}
I'm not sure exactly what you're trying to do, but once I thinned out your incredibly verbose code and tried to understand it, I think the conclusion is that you'll only want to record the array counts after the last iteration of your inner loop. For example:
Instead of doing this: for layerThree in layerTwo
do this: for (index, layerThree) in layerTwo.enumerated()
Then, after you append the lat/long values, add this check:
if index == layerTwo.count - 1 //if this is our last inner loop
{
//print the array counts
print("Lat count: \(latArray.count)")
print("Long count: \(longArray.count)")
}
This should work in your case. However, I disagree entirely with the execution of this simply because of the lack of portability and reusability of your code. Additionally, there are quite a few good language constructs which are being ignored. The relentless nested if let blocks could be reduced significantly with a few good guard statements. Furthermore, considering you aren't handling your errors in any catch blocks anyway, might as well just remove them and opt for a try? instead. One much swiftier way of handling things would be to just include a completion handler in the function itself so that the array count printing logic could be handled elsewhere. I'll include some example code of how I would clean things up:
func someFunction(completion: (([String], [String]) -> Void)?)
{
let url = URL(string: "...")!
var latArray: [String] = []
var longArray: [String] = []
let task = URLSession.shared.dataTask(with: URLRequest(url: url),
completionHandler: { (data, response, error) -> Void in
guard error == nil else
{
print("ERROR IN API REQUEST: \(error?.localizedDescription)")
return
}
guard let parsedData = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments),
let parsedDict = parsedData as? [String: Any],
let layerOne = parsedDict["one"] as? [String: Any],
let layerTwo = layerOne["two"] as? [[String: Any]] else
{
print("JSON OBJECT DOES NOT MATCH EXPECTED PATTERN")
return
}
for (index, layerThree) in layerTwo.enumerated()
{
guard let _ = layerThree["value"] as? String else
{
print("Skip this iteration (I guess?)")
continue
}
let innerUrl = URL(string: "...")!
let innerTask = URLSession.shared.dataTask(with: URLRequest(url: innerUrl),
completionHandler: { (data, response, error) -> Void in
guard error == nil else
{
print("ERROR IN API REQUEST: \(error?.localizedDescription)")
return
}
guard let parsedData = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments),
let parsedDict = parsedData as? [String: Any],
let layerA = parsedDict["A"] as? [String: Any],
let lat = layerA["Latitude"] as? String,
let long = layerA["Longitude"] as? String else
{
print("Something went wrong")
return
}
latArray.append(lat)
longArray.append(long)
if index == layerTwo.count - 1 //if this is our last inner loop
{
completion?(latArray, longArray)
}
}
)
innerTask.resume()
}
}
)
task.resume()
}
someFunction(completion: { (latArray, longArray) -> Void in
//print the array counts
print("Lat count: \(latArray.count)")
print("Long count: \(longArray.count)")
})
This could still be improved much further, though based on your question I don't see that I personally should be putting more time into constructing this for you. It would be best if you come up with a few methods of your own to build an application with more readable and reusable code.
Can't access json object which is array inside json object
i want to access data from json object which have array inside array
and that json file is also uploaded
so pls can anyone check and help me how to get "weather.description"
data
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "http://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=13ae70c6aefa867c44962edc13f94404")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print("some error occured")
} else {
if let urlContent = data {
do{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers)
let newValue = jsonResult as! NSDictionary
print(jsonResult)
let name = newValue["name"]
//Here i am getting name as variable value
//this is not working
let description = newValue["weather"]??[0]["description"]
//this is not working
let description = newValue["weather"]!![0]["description"]
print()
}catch {
print("JSON Preocessing failed")
}
}
}
}
task.resume()
}
I have edited your code a bit, and added a few comments. Basiclly, lets check for the types of your response structure, and get the desired value.
let url = URL(string: "http://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=13ae70c6aefa867c44962edc13f94404")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print("some error occured")
} else {
if let urlContent = data {
do{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers)
// I would not recommend to use NSDictionary, try using Swift types instead
guard let newValue = jsonResult as? [String: Any] else {
print("invalid format")
return
}
// Check for the weather parameter as an array of dictionaries and than excess the first array's description
if let weather = newValue["weather"] as? [[String: Any]], let description = weather.first?["description"] as? String {
print(description)
}
}catch {
print("JSON Preocessing failed")
}
}
}
}
task.resume()