Not able to iterate through SPTPlaylistList items - swift

I am trying to access all the playlists of a Spotify user
let request2: URLRequest = try! SPTPlaylistList.createRequestForGettingPlaylists(forUser: self.username, withAccessToken: accessToken)
print(request2)
SPTRequest.sharedHandler().perform(request2) { (error, response, data) in
if error == nil {
print(response)
let playlists = try! SPTPlaylistList(from: data, with: response)
}else{
print(error)
}
}
And I can see the playlists if I print 'playlists'
some([<SPTPartialPlaylist: 0x10aa854d0>: john mayer [2 tracks] (spotify:user:virajdeshpande88:playlist:3BLBrqb3CURu5KFPqdYqd1), <SPTPartialPlaylist: 0x10aa922a0>: beatles [2 tracks] (spotify:user:virajdeshpande88:playlist:2t6z8KEhZGzY7Tqvy8QoW4)])
But I can't access the playlists individually or iterate through playlists.items. If I do the following:
print (playlists.items[0])
I get 'Unexpectedly found nil while unwrapping an Optional value'.
Update: I tried using playlistsForUser:withAccessToken:callback: and I am able to access all the user's playlists now. But it only seems to work if the following block of code is inside the if {} block of the piece of code I posted above. If this block is placed just by itself, I get the nil value error again.
SPTPlaylistList.playlists(forUser: self.username, withAccessToken: accessToken, callback: {(error, playlist_list) in
if error == nil {
let list = playlist_list as! SPTPlaylistList
print(list.items[0])
print(list.items[1])
let playlist = list.items[0] as! SPTPartialPlaylist
print(playlist.name)
}else{
print("latest error")
}
})

You should avoid using force unwrap !.
if let request2: URLRequest = try? SPTPlaylistList.createRequestForGettingPlaylists(forUser: self.username, withAccessToken: accessToken){
print(request2)
SPTRequest.sharedHandler().perform(request2) { (error, response, data) in
if error == nil {
print(response)
if let playlists = try? SPTPlaylistList(from: data, with: response) {
playlists.forEach{ playlist in
print(playlist)
// do thing with your each playlist
}
}
}else{
print(error)
}
}
}

Related

Swift scoping outside of a function

I have a singleton URLSession that is parsing the response data into a dictionary. I want to use a single value from that dictionary in a subsequent piece of code, but cannot figure out how to pass the value out from the scope it's currently in.
Here is the code as it stands now:
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
debugPrint ("error: \(error!)")
return
}
guard let content = data else {
debugPrint("No data")
return
}
guard let json = (try? JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [String: Any] else {
debugPrint("Not containing JSON")
return
}
if let idToken = json["id_token"] as? String {
let privateToken = idToken;
debugPrint("Gotten json response dictionary is \(idToken)")
}
}
task.resume()
return privateToken
Currently there is an IDE error on return privateToken saying that I am using an unresolved identifier: privateToken.
How can I take the string idToken and return it as a privateToken for use elsewhere?
Could you use a completion handler like:
func getPrivateToken(completion: #escaping(String) -> (), failure: #escaping (Error) -> ()) {
URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
debugPrint ("error: \(error!)")
failure(error)
return
}
guard let content = data else {
debugPrint("No data")
failure(NSError(domain: "Your error message here.", code: 401, userInfo: nil))
return
}
guard let json = (try? JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [String: Any] else {
debugPrint("Not containing JSON")
failure(NSError(domain: "Your error message here.", code: 401, userInfo: nil))
return
}
if let idToken = json["id_token"] as? String {
completion(idToken)
debugPrint("Gotten json response dictionary is \(idToken)")
}
}.resume()
}
And use it like so:
func exampleFunction() {
self.getPrivateToken(completion: { (token) in
// Do what ever you need with the token here.
print("ID token is: \(token)")
}) { (error) in
// Present error here
}
}

Swift Function Not Continuing after completion of Json Decoder within - "else if" issue?

I am using this function to call json information from a database - it gets the information fine.
But it does not continue after the "getHistoricalMonthlyData". so it will not get to the print("****** line 55"). (yes, I plan on making this a func once I figure out the issue.)
it will print the "print(i.stock)" fine.
I can share the "getHistoricalMonthlyData" code but it works fine and I doubt that is the issue.
I am not great with the completion handlers and I suspect that is the issue?
below is the "getHistoricalMonthlyData" function that I can not get past.
func calculateMonthPerformance (setting: settings) {
let set = setting
let u = User.getUser()
var i = Indexes()
getHistoricalMonthlyData(symbol: symbol, beg: set.monthBeg, end: set.monthEnd) { (json, error ) in
if let error = error {
print ("error", error)
} else if let json = json {
print ("success")
i.stock = json
print(47)
}
// this is fine
print(50)
print(i.stock)
}
// nothing at this point
print("****** line 55")
}
This is how the json function is set up and works great in another project.
it has a resume.
func getHistoricalMonthlyData(symbol: String, beg: Date, end: Date, completionHandler: #escaping ([HistoricalData]?, Error?) -> Void) {
let beg = beg.dateAtStartOf(.month).toFormat("yyyy-MM-dd")
let end = end.dateAtEndOf(.month).toFormat("yyyy-MM-dd")
let jsonUrl = "https://eodhistoricaldata.com/api/eod/\(symbol).US?from=\(beg)&to=\(end)&api_token=\(EOD_KEY)&period=eom&fmt=json"
guard let url = URL(string: jsonUrl) else {
print("Error: cannot create URL")
let error = BackendError.urlError(reason: "Could not create URL")
completionHandler(nil, error)
return
}
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard error == nil else {
completionHandler(nil, error!)
return
}
guard let jasonData = data else {
print("Error: did not receive data")
let error = BackendError.objectSerialization(reason: "No data in response")
completionHandler(nil, error)
return
}
do {
let historical = try JSONDecoder().decode([HistoricalData].self, from: jasonData )
completionHandler(historical, nil)
} catch let jsonErr {
print ("Error serializing json", jsonErr )
let error = BackendError.objectSerialization(reason: "Couldn't create a todo object from the JSON")
completionHandler(nil, error)
}
}.resume()
}
thanks.
if someone knows a better answer would love to hear about it.
I added a DispatchSemaphore to the code and it seems to work.
cheers.
let semaphore = DispatchSemaphore(value: 0)
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard error == nil else {
completionHandler(nil, error!)
return
}
guard let jasonData = data else {
let error = BackendError.objectSerialization(reason: "No data in response")
completionHandler(nil, error)
return
}
do {
let historical = try JSONDecoder().decode([HistoricalData].self, from: jasonData )
completionHandler(historical, nil)
} catch let jsonErr {
let error = BackendError.objectSerialization(reason: "Couldn't create a todo object from the JSON")
completionHandler(nil, error)
}
semaphore.signal()
}.resume()
_ = semaphore.wait(timeout: .distantFuture)

Swift function produces a "SIGILL" on it's return statement

I am writing a piece of code in Swift to hit a public API endpoint to pull back data in JSON and use it in the application. I am using URLSession to do the request and am using an async/await similar paradigm to extract data out of the URLSession callback and place it in a local variable. Then, the function returns the optional dictionary returned by JSONSerialization to the caller.
This code executes perfectly fine outside of a function and run as part of the main program, but as soon as it is moved to a function, the return statement produces a "SIGILL" exit.
I breakpointed to the return statement and found that it is exactly what is throwing this error. Since this is an optional dictionary, I tried just returning an unwrapped version of the dictionary and found the same results. I also tried just returning a blank dictionary and I still get a SIGILL
Functioning:
let url = URL(string: <endpointURL>)!
var tenant: [String: Any]? = nil;
let sem = DispatchSemaphore(value: 1)
sem.wait()
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
if let json = json {
print(json)
tenant = json
sem.signal()
} else {
print("ERR: Null JSON")
}
} catch let error as NSError {
print("ERR: " + error.localizedDescription)
}
} else if let error = error {
print("ERR: " + error.localizedDescription);
} else {
print("ERR: Unknown")
}
}
print("resuming")
task.resume()
print("waiting: ")
sem.wait()
print("done waiting")
print(tenant!["tenant_name"]!)
Fails:
let _ = HttpHelper.getTenantFor(tenantId: <someUUID>)
class HttpHelper {
static func getTenantFor(tenantId: String) -> [String:Any]? {
let url = URL(string: <endpointURL>)!
var tenant: [String: Any]? = nil;
let sem = DispatchSemaphore(value: 1)
sem.wait()
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
if let json = json {
print(json)
tenant = json
sem.signal()
} else {
print("ERR: Null JSON")
}
} catch let error as NSError {
print("ERR: " + error.localizedDescription)
}
} else if let error = error {
print("ERR: " + error.localizedDescription);
} else {
print("ERR: Unknown")
}
}
print("resuming")
task.resume()
print("waiting: ")
sem.wait()
print("done waiting")
return [String:Any]()
}
}
On the functioning code, the app outputs the proper value for the "tenant_name" key in the JSON object and in the failed code I get the following:
Process finished with exit code 132 (interrupted by signal 4: SIGILL)

Alamofire causes crash on iPhone 5

I currently give some users access to my app via TestFlight so that they can test it. On every iPhone the App works perfectly without any problems but on the iPhone 5 the app crashes every time. In the xCode simulator everything works properly but not on a real device.
It looks like Alamofire causes the crash. The problem is in Alamofire>Source>Features>ResponseSerialization.swift>response(queue:completionHandler:)
Here is the code from the function:
/// Adds a handler to be called once the request has finished.
///
/// - parameter queue: The queue on which the completion handler is dispatched.
/// - parameter completionHandler: The code to be executed once the request has finished.
///
/// - returns: The request.
#discardableResult
public func response(queue: DispatchQueue? = nil, completionHandler: #escaping (DefaultDataResponse) -> Void) -> Self {
delegate.queue.addOperation {
(queue ?? DispatchQueue.main).async {
var dataResponse = DefaultDataResponse(
request: self.request,
response: self.response,
data: self.delegate.data,
error: self.delegate.error
)
dataResponse.add(self.delegate.metrics)
completionHandler(dataResponse)
}
}
return self
}
completionHandler(dataResponse) looks like it is the problem.
Below there is also a screenshot from xCode
Is this a Alamofire related problem? Because on every other device (5s, 6 Plus, 7 Plus, SE and 7) it works without any problems. The crash occur when the iPhone is connected to WiFi and when it uses the mobile network.
Thanks for any tips!
EDIT:
This should be the code section that is called when starting the application:
Alamofire.request("https://app.site.tld/mobile/ios", parameters: parameters).response { response in
print("Request: \(response.request)")
print("Response: \(response.response)")
print("Error: \(response.data)")
if response.response != nil{
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)")
let weatherDataArr = utf8Text.components(separatedBy: "~")
guard let hash = String(weatherDataArr[0]) else {
completion(nil)
return
}
do {
//working with received data.
//let currData: wData = try wData(hash: hash, ....)
completion(currData)
} catch {
print("error creating Object: \(error)")
completion(nil)
}
}
else {
completion(nil)
}
}else {
completion(nil)
}
}
Just found a warning in xCode that says:
'catch' block is unreachable because no errors are thrown in 'do' block
First simplify to remove clutter
Alamofire.request("https://app.site.tld/mobile/ios", parameters: parameters).response { response in
print("Request: \(response.request)")
print("Response: \(response.response)")
print("Error: \(response.data)")
var result: wData? = nil
defer { completion(result) }
guard response.response != nil else { return }
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)")
let weatherDataArr = utf8Text.components(separatedBy: "~")
guard let hash = String(weatherDataArr[0]) else { return }
//working with received data.
//let currData: wData = try wData(hash: hash, ....)
result = currData
}
}
Then we can ask ourselves
How are you 100% sure there are elements in weatherDataArr? If not, use guard let hash = weatherDataArr.first else { return }
What happens under //working with received data.?

Error in POST Request in swift

I wanted to be a type of variable to send to the dictionary server but But on the line I was faced with the problem let task = session.dataTaskWithRequest(todosUrlRequest) error : Cannot convert value of type 'NSURL' to expected argument type 'NSURLRequest'
I had two questions
1) What is this error?
2)Is there a procedure that I used for POST is that right? doesn't need anything else. ??
thank you for help
func data_request (){
let url = "http://sample.com/api/Flight/GetTicketInformation"
guard let todosUrlRequest = NSURL(string: url) else {
print("Error: cannot create URL")
return
}
let request = NSMutableURLRequest(URL: todosUrlRequest)
request.HTTPMethod = "POST"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
let newTodo = ["Roundtrip": roundTrip,
"OneWay": oneWay,
"MultiWay": multiWay,
"Adult": numberAdults,
"Child": numberchild,
"Baby": numberinfant,
"SourceCityId": cityIDOrigin,
"DestinationCityId": cityIDPurpose,
"DepartingDate": raftDate,
"ReturningDate": bargashtDate ]
let jsonTodo: NSData
do {
jsonTodo = try NSJSONSerialization.dataWithJSONObject(newTodo, options: [])
request.HTTPBody = jsonTodo
} catch {
print("Error: cannot create JSON from todo")
return
}
request.HTTPBody = jsonTodo
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(todosUrlRequest) {
(data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
}
guard error == nil else {
print("error calling POST on /todos/1")
print(error)
return
}
// parse the result as JSON, since that's what the API provides
do {
guard let receivedTodo = try NSJSONSerialization.JSONObjectWithData(responseData,
options: []) as? [String: AnyObject] else {
print("Could not get JSON from responseData as dictionary")
return
}
print("The todo is: " + receivedTodo.description)
} catch {
print("error parsing response from POST on /todos")
return
}
}
task.resume()
}
request instead of todosUrlRequest on the line let task = session.dataTaskWithRequest(todosUrlRequest)
for the second question, no idea . sorry
I can recommend you Alamofire for all requests, instead of writing all code on your own.
https://github.com/Alamofire/Alamofire