URL Session Download Task Completion Block Never Called
I am making a web request to the Google Places API to fetch nearby places based off a specific coordinate and thereafter run a task to fetch a photo of those places.
I am able to successfully get place details through the first task, and while the second task of retrieving the photo runs, its completion block is never entered resulting in no photo as I have observed placing breakpoints.
The urlString is correct, my apiKey works correctly since again the first task returns the right response, and I have the photo reference of the place to be able to execute the web request. Any guidance would be appreciated as I am admittedly lost - can provide more detail if needed.
Below are the network calls, which is adapted from ray wenderlich's guide.
typealias PlacesCompletion = ([Place]) -> Void
typealias PhotoCompletion = (UIImage?) -> Void
class DataProvider {
private var photoCache: [String: UIImage] = [:]
private var placesTask: URLSessionDataTask?
private var session: URLSession {
return URLSession.shared
}
//FIRST WEB REQUEST
func fetchPlacesNearCoordinate(_ coordinate: CLLocationCoordinate2D, radius: Double, types: [String], completion: @escaping PlacesCompletion) -> Void {
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=(coordinate.latitude),(coordinate.longitude)&radius=(radius)&rankby=prominence&sensor=true&key=(googleApiKey)"
let typesString = "restaurant"
urlString += "&type=(typesString)"
urlString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? urlString
guard let url = URL(string: urlString) else {
completion()
return
}
if let task = placesTask, task.taskIdentifier > 0 && task.state == .running {
task.cancel()
}
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
placesTask = session.dataTask(with: url) { data, response, error in
var placesArray: [Place] =
defer {
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
completion(placesArray)
}
}
guard let data = data,
let json = try? JSON(data: data, options: .mutableContainers),
let results = json["results"].arrayObject as? [[String: Any]] else {
return
}
results.forEach {
let place = Place(dictionary: $0, acceptedTypes: types)
placesArray.append(place)
if let reference = place.photoReference {
//SECOND WEB REQUEST CALL
self.fetchPhotoFromReference(reference) { image in
place.photo = image
}
}
}
}
placesTask?.resume()
}
//SECOND WEB REQUEST
func fetchPhotoFromReference(_ reference: String, completion: @escaping PhotoCompletion) -> Void {
if let photo = photoCache[reference] {
completion(photo)
} else {
let urlString = "https://maps.googleapis.com/maps/api/place/photo?maxwidth=200&maxheight=200&photoreference=(reference)&key=(googleApiKey)"
guard let url = URL(string: urlString) else {
completion(nil)
return
}
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
session.downloadTask(with: url) { url, response, error in
var downloadedPhoto: UIImage? = nil
defer {
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
completion(downloadedPhoto)
}
}
guard let url = url else {
return
}
guard let imageData = try? Data(contentsOf: url) else {
return
}
downloadedPhoto = UIImage(data: imageData)
self.photoCache[reference] = downloadedPhoto
}
.resume()
}
}
}
ios swift google-places-api nsurlsession nsurlsessiondownloadtask
add a comment |
I am making a web request to the Google Places API to fetch nearby places based off a specific coordinate and thereafter run a task to fetch a photo of those places.
I am able to successfully get place details through the first task, and while the second task of retrieving the photo runs, its completion block is never entered resulting in no photo as I have observed placing breakpoints.
The urlString is correct, my apiKey works correctly since again the first task returns the right response, and I have the photo reference of the place to be able to execute the web request. Any guidance would be appreciated as I am admittedly lost - can provide more detail if needed.
Below are the network calls, which is adapted from ray wenderlich's guide.
typealias PlacesCompletion = ([Place]) -> Void
typealias PhotoCompletion = (UIImage?) -> Void
class DataProvider {
private var photoCache: [String: UIImage] = [:]
private var placesTask: URLSessionDataTask?
private var session: URLSession {
return URLSession.shared
}
//FIRST WEB REQUEST
func fetchPlacesNearCoordinate(_ coordinate: CLLocationCoordinate2D, radius: Double, types: [String], completion: @escaping PlacesCompletion) -> Void {
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=(coordinate.latitude),(coordinate.longitude)&radius=(radius)&rankby=prominence&sensor=true&key=(googleApiKey)"
let typesString = "restaurant"
urlString += "&type=(typesString)"
urlString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? urlString
guard let url = URL(string: urlString) else {
completion()
return
}
if let task = placesTask, task.taskIdentifier > 0 && task.state == .running {
task.cancel()
}
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
placesTask = session.dataTask(with: url) { data, response, error in
var placesArray: [Place] =
defer {
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
completion(placesArray)
}
}
guard let data = data,
let json = try? JSON(data: data, options: .mutableContainers),
let results = json["results"].arrayObject as? [[String: Any]] else {
return
}
results.forEach {
let place = Place(dictionary: $0, acceptedTypes: types)
placesArray.append(place)
if let reference = place.photoReference {
//SECOND WEB REQUEST CALL
self.fetchPhotoFromReference(reference) { image in
place.photo = image
}
}
}
}
placesTask?.resume()
}
//SECOND WEB REQUEST
func fetchPhotoFromReference(_ reference: String, completion: @escaping PhotoCompletion) -> Void {
if let photo = photoCache[reference] {
completion(photo)
} else {
let urlString = "https://maps.googleapis.com/maps/api/place/photo?maxwidth=200&maxheight=200&photoreference=(reference)&key=(googleApiKey)"
guard let url = URL(string: urlString) else {
completion(nil)
return
}
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
session.downloadTask(with: url) { url, response, error in
var downloadedPhoto: UIImage? = nil
defer {
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
completion(downloadedPhoto)
}
}
guard let url = url else {
return
}
guard let imageData = try? Data(contentsOf: url) else {
return
}
downloadedPhoto = UIImage(data: imageData)
self.photoCache[reference] = downloadedPhoto
}
.resume()
}
}
}
ios swift google-places-api nsurlsession nsurlsessiondownloadtask
add a comment |
I am making a web request to the Google Places API to fetch nearby places based off a specific coordinate and thereafter run a task to fetch a photo of those places.
I am able to successfully get place details through the first task, and while the second task of retrieving the photo runs, its completion block is never entered resulting in no photo as I have observed placing breakpoints.
The urlString is correct, my apiKey works correctly since again the first task returns the right response, and I have the photo reference of the place to be able to execute the web request. Any guidance would be appreciated as I am admittedly lost - can provide more detail if needed.
Below are the network calls, which is adapted from ray wenderlich's guide.
typealias PlacesCompletion = ([Place]) -> Void
typealias PhotoCompletion = (UIImage?) -> Void
class DataProvider {
private var photoCache: [String: UIImage] = [:]
private var placesTask: URLSessionDataTask?
private var session: URLSession {
return URLSession.shared
}
//FIRST WEB REQUEST
func fetchPlacesNearCoordinate(_ coordinate: CLLocationCoordinate2D, radius: Double, types: [String], completion: @escaping PlacesCompletion) -> Void {
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=(coordinate.latitude),(coordinate.longitude)&radius=(radius)&rankby=prominence&sensor=true&key=(googleApiKey)"
let typesString = "restaurant"
urlString += "&type=(typesString)"
urlString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? urlString
guard let url = URL(string: urlString) else {
completion()
return
}
if let task = placesTask, task.taskIdentifier > 0 && task.state == .running {
task.cancel()
}
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
placesTask = session.dataTask(with: url) { data, response, error in
var placesArray: [Place] =
defer {
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
completion(placesArray)
}
}
guard let data = data,
let json = try? JSON(data: data, options: .mutableContainers),
let results = json["results"].arrayObject as? [[String: Any]] else {
return
}
results.forEach {
let place = Place(dictionary: $0, acceptedTypes: types)
placesArray.append(place)
if let reference = place.photoReference {
//SECOND WEB REQUEST CALL
self.fetchPhotoFromReference(reference) { image in
place.photo = image
}
}
}
}
placesTask?.resume()
}
//SECOND WEB REQUEST
func fetchPhotoFromReference(_ reference: String, completion: @escaping PhotoCompletion) -> Void {
if let photo = photoCache[reference] {
completion(photo)
} else {
let urlString = "https://maps.googleapis.com/maps/api/place/photo?maxwidth=200&maxheight=200&photoreference=(reference)&key=(googleApiKey)"
guard let url = URL(string: urlString) else {
completion(nil)
return
}
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
session.downloadTask(with: url) { url, response, error in
var downloadedPhoto: UIImage? = nil
defer {
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
completion(downloadedPhoto)
}
}
guard let url = url else {
return
}
guard let imageData = try? Data(contentsOf: url) else {
return
}
downloadedPhoto = UIImage(data: imageData)
self.photoCache[reference] = downloadedPhoto
}
.resume()
}
}
}
ios swift google-places-api nsurlsession nsurlsessiondownloadtask
I am making a web request to the Google Places API to fetch nearby places based off a specific coordinate and thereafter run a task to fetch a photo of those places.
I am able to successfully get place details through the first task, and while the second task of retrieving the photo runs, its completion block is never entered resulting in no photo as I have observed placing breakpoints.
The urlString is correct, my apiKey works correctly since again the first task returns the right response, and I have the photo reference of the place to be able to execute the web request. Any guidance would be appreciated as I am admittedly lost - can provide more detail if needed.
Below are the network calls, which is adapted from ray wenderlich's guide.
typealias PlacesCompletion = ([Place]) -> Void
typealias PhotoCompletion = (UIImage?) -> Void
class DataProvider {
private var photoCache: [String: UIImage] = [:]
private var placesTask: URLSessionDataTask?
private var session: URLSession {
return URLSession.shared
}
//FIRST WEB REQUEST
func fetchPlacesNearCoordinate(_ coordinate: CLLocationCoordinate2D, radius: Double, types: [String], completion: @escaping PlacesCompletion) -> Void {
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=(coordinate.latitude),(coordinate.longitude)&radius=(radius)&rankby=prominence&sensor=true&key=(googleApiKey)"
let typesString = "restaurant"
urlString += "&type=(typesString)"
urlString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? urlString
guard let url = URL(string: urlString) else {
completion()
return
}
if let task = placesTask, task.taskIdentifier > 0 && task.state == .running {
task.cancel()
}
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
placesTask = session.dataTask(with: url) { data, response, error in
var placesArray: [Place] =
defer {
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
completion(placesArray)
}
}
guard let data = data,
let json = try? JSON(data: data, options: .mutableContainers),
let results = json["results"].arrayObject as? [[String: Any]] else {
return
}
results.forEach {
let place = Place(dictionary: $0, acceptedTypes: types)
placesArray.append(place)
if let reference = place.photoReference {
//SECOND WEB REQUEST CALL
self.fetchPhotoFromReference(reference) { image in
place.photo = image
}
}
}
}
placesTask?.resume()
}
//SECOND WEB REQUEST
func fetchPhotoFromReference(_ reference: String, completion: @escaping PhotoCompletion) -> Void {
if let photo = photoCache[reference] {
completion(photo)
} else {
let urlString = "https://maps.googleapis.com/maps/api/place/photo?maxwidth=200&maxheight=200&photoreference=(reference)&key=(googleApiKey)"
guard let url = URL(string: urlString) else {
completion(nil)
return
}
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
session.downloadTask(with: url) { url, response, error in
var downloadedPhoto: UIImage? = nil
defer {
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
completion(downloadedPhoto)
}
}
guard let url = url else {
return
}
guard let imageData = try? Data(contentsOf: url) else {
return
}
downloadedPhoto = UIImage(data: imageData)
self.photoCache[reference] = downloadedPhoto
}
.resume()
}
}
}
ios swift google-places-api nsurlsession nsurlsessiondownloadtask
ios swift google-places-api nsurlsession nsurlsessiondownloadtask
asked Nov 20 at 23:40
Chris
9411
9411
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Try removing the session.download(with: url)
block. In order to download the data from the url, all you need is let imageData = try? Data(contentsOf: url)
.
Also, you are not giving the let imageData = try? Data(contentsOf: url)
time to execute. You make the call and then immediately try to use the results in the downloadedPhoto = UIImage(data: imageData)
line.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53403253%2furl-session-download-task-completion-block-never-called%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Try removing the session.download(with: url)
block. In order to download the data from the url, all you need is let imageData = try? Data(contentsOf: url)
.
Also, you are not giving the let imageData = try? Data(contentsOf: url)
time to execute. You make the call and then immediately try to use the results in the downloadedPhoto = UIImage(data: imageData)
line.
add a comment |
Try removing the session.download(with: url)
block. In order to download the data from the url, all you need is let imageData = try? Data(contentsOf: url)
.
Also, you are not giving the let imageData = try? Data(contentsOf: url)
time to execute. You make the call and then immediately try to use the results in the downloadedPhoto = UIImage(data: imageData)
line.
add a comment |
Try removing the session.download(with: url)
block. In order to download the data from the url, all you need is let imageData = try? Data(contentsOf: url)
.
Also, you are not giving the let imageData = try? Data(contentsOf: url)
time to execute. You make the call and then immediately try to use the results in the downloadedPhoto = UIImage(data: imageData)
line.
Try removing the session.download(with: url)
block. In order to download the data from the url, all you need is let imageData = try? Data(contentsOf: url)
.
Also, you are not giving the let imageData = try? Data(contentsOf: url)
time to execute. You make the call and then immediately try to use the results in the downloadedPhoto = UIImage(data: imageData)
line.
answered Nov 21 at 16:41
Key Hoffman
94
94
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53403253%2furl-session-download-task-completion-block-never-called%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown