swift - order of functions - which code runs when?











up vote
0
down vote

favorite












I have an issue with my code and I think it could be related to the order in which code is called.



import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {

private var tasks = [Task]()

override func willActivate() {
let taskUrl = "http://myjsonurl.com"
downloadJsonTask(url: taskUrl)
print(tasks.count) // EMPTY
super.willActivate()
}

func downloadJsonTask(url: String) {
var request = URLRequest(url: URL(string: url)!)
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
URLSession.shared.dataTask(with: request) { data, urlResponse, error in

guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
return
}

do
{
let decoder = JSONDecoder()
let downloadedTasks = try decoder.decode(Tasks.self, from: data)
self.tasks = downloadedTasks.tasks
print(downloadedTasks.tasks.count) //4

} catch {
print("somehting went wrong after downloading")
}

}.resume()
}
}


I'm defining the private var tasks and fill it with the downloadJsonTask function but after the function ran the print(tasks.count) gives 0.
When I call print(downloadedTasks.tasks.count) it gives 4.



I think that in sequence of time the tasks variable is empty when I print it and it is filled later on.










share|improve this question
























  • dataTask(with:) in WatchKit, macOS and iOS is asynchrone. The guard let data = data, ie the completion of the method is called whenever you got the the result of the request. I can differs (bad connection etc) and is async to avoid blocking the current thread (and if it's the main one, that's all your UI that is blocked)
    – Larme
    Nov 10 at 20:52








  • 4




    Unrelated but never ever print pointless literal strings like "something is wrong" when an error occurred. That's pretty silly. Print the error instance to get a meaningful error description.
    – vadian
    Nov 10 at 20:58










  • @Larme I'm still about to learn swift and my code is written after reading tutorials. I'm still to new to transfer your comment to a solution. I think doing asynchrone requests is correct and it is my issue as the same time. If it was not asynchrone I was able to have the print(tasks.count) with 4, as well. But it should be asynchrone, so what is your proposed solution for me in detail? @vadian same here. I'm to new to transfer year answer in code. I googled and found catch let error and then print(error). Is this what you mean?
    – T. Karter
    Nov 10 at 21:20










  • catch let error is redundant. Just print(error). In your code put the things you want to do after the data has been received into the completion handler (replacing the working print line).
    – vadian
    Nov 10 at 21:22












  • Look for "Swift + Async + Closure" to know how manage Asynchrone. In a nutshell, dataTask(with:) use a closure to manage it, do the same by creating a closure on your method that will be called when the URLSession one will be called.
    – Larme
    Nov 11 at 8:47















up vote
0
down vote

favorite












I have an issue with my code and I think it could be related to the order in which code is called.



import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {

private var tasks = [Task]()

override func willActivate() {
let taskUrl = "http://myjsonurl.com"
downloadJsonTask(url: taskUrl)
print(tasks.count) // EMPTY
super.willActivate()
}

func downloadJsonTask(url: String) {
var request = URLRequest(url: URL(string: url)!)
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
URLSession.shared.dataTask(with: request) { data, urlResponse, error in

guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
return
}

do
{
let decoder = JSONDecoder()
let downloadedTasks = try decoder.decode(Tasks.self, from: data)
self.tasks = downloadedTasks.tasks
print(downloadedTasks.tasks.count) //4

} catch {
print("somehting went wrong after downloading")
}

}.resume()
}
}


I'm defining the private var tasks and fill it with the downloadJsonTask function but after the function ran the print(tasks.count) gives 0.
When I call print(downloadedTasks.tasks.count) it gives 4.



I think that in sequence of time the tasks variable is empty when I print it and it is filled later on.










share|improve this question
























  • dataTask(with:) in WatchKit, macOS and iOS is asynchrone. The guard let data = data, ie the completion of the method is called whenever you got the the result of the request. I can differs (bad connection etc) and is async to avoid blocking the current thread (and if it's the main one, that's all your UI that is blocked)
    – Larme
    Nov 10 at 20:52








  • 4




    Unrelated but never ever print pointless literal strings like "something is wrong" when an error occurred. That's pretty silly. Print the error instance to get a meaningful error description.
    – vadian
    Nov 10 at 20:58










  • @Larme I'm still about to learn swift and my code is written after reading tutorials. I'm still to new to transfer your comment to a solution. I think doing asynchrone requests is correct and it is my issue as the same time. If it was not asynchrone I was able to have the print(tasks.count) with 4, as well. But it should be asynchrone, so what is your proposed solution for me in detail? @vadian same here. I'm to new to transfer year answer in code. I googled and found catch let error and then print(error). Is this what you mean?
    – T. Karter
    Nov 10 at 21:20










  • catch let error is redundant. Just print(error). In your code put the things you want to do after the data has been received into the completion handler (replacing the working print line).
    – vadian
    Nov 10 at 21:22












  • Look for "Swift + Async + Closure" to know how manage Asynchrone. In a nutshell, dataTask(with:) use a closure to manage it, do the same by creating a closure on your method that will be called when the URLSession one will be called.
    – Larme
    Nov 11 at 8:47













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have an issue with my code and I think it could be related to the order in which code is called.



import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {

private var tasks = [Task]()

override func willActivate() {
let taskUrl = "http://myjsonurl.com"
downloadJsonTask(url: taskUrl)
print(tasks.count) // EMPTY
super.willActivate()
}

func downloadJsonTask(url: String) {
var request = URLRequest(url: URL(string: url)!)
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
URLSession.shared.dataTask(with: request) { data, urlResponse, error in

guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
return
}

do
{
let decoder = JSONDecoder()
let downloadedTasks = try decoder.decode(Tasks.self, from: data)
self.tasks = downloadedTasks.tasks
print(downloadedTasks.tasks.count) //4

} catch {
print("somehting went wrong after downloading")
}

}.resume()
}
}


I'm defining the private var tasks and fill it with the downloadJsonTask function but after the function ran the print(tasks.count) gives 0.
When I call print(downloadedTasks.tasks.count) it gives 4.



I think that in sequence of time the tasks variable is empty when I print it and it is filled later on.










share|improve this question















I have an issue with my code and I think it could be related to the order in which code is called.



import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {

private var tasks = [Task]()

override func willActivate() {
let taskUrl = "http://myjsonurl.com"
downloadJsonTask(url: taskUrl)
print(tasks.count) // EMPTY
super.willActivate()
}

func downloadJsonTask(url: String) {
var request = URLRequest(url: URL(string: url)!)
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
URLSession.shared.dataTask(with: request) { data, urlResponse, error in

guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
return
}

do
{
let decoder = JSONDecoder()
let downloadedTasks = try decoder.decode(Tasks.self, from: data)
self.tasks = downloadedTasks.tasks
print(downloadedTasks.tasks.count) //4

} catch {
print("somehting went wrong after downloading")
}

}.resume()
}
}


I'm defining the private var tasks and fill it with the downloadJsonTask function but after the function ran the print(tasks.count) gives 0.
When I call print(downloadedTasks.tasks.count) it gives 4.



I think that in sequence of time the tasks variable is empty when I print it and it is filled later on.







swift watchkit






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 10 at 20:51









rmaddy

235k27306372




235k27306372










asked Nov 10 at 20:48









T. Karter

51




51












  • dataTask(with:) in WatchKit, macOS and iOS is asynchrone. The guard let data = data, ie the completion of the method is called whenever you got the the result of the request. I can differs (bad connection etc) and is async to avoid blocking the current thread (and if it's the main one, that's all your UI that is blocked)
    – Larme
    Nov 10 at 20:52








  • 4




    Unrelated but never ever print pointless literal strings like "something is wrong" when an error occurred. That's pretty silly. Print the error instance to get a meaningful error description.
    – vadian
    Nov 10 at 20:58










  • @Larme I'm still about to learn swift and my code is written after reading tutorials. I'm still to new to transfer your comment to a solution. I think doing asynchrone requests is correct and it is my issue as the same time. If it was not asynchrone I was able to have the print(tasks.count) with 4, as well. But it should be asynchrone, so what is your proposed solution for me in detail? @vadian same here. I'm to new to transfer year answer in code. I googled and found catch let error and then print(error). Is this what you mean?
    – T. Karter
    Nov 10 at 21:20










  • catch let error is redundant. Just print(error). In your code put the things you want to do after the data has been received into the completion handler (replacing the working print line).
    – vadian
    Nov 10 at 21:22












  • Look for "Swift + Async + Closure" to know how manage Asynchrone. In a nutshell, dataTask(with:) use a closure to manage it, do the same by creating a closure on your method that will be called when the URLSession one will be called.
    – Larme
    Nov 11 at 8:47


















  • dataTask(with:) in WatchKit, macOS and iOS is asynchrone. The guard let data = data, ie the completion of the method is called whenever you got the the result of the request. I can differs (bad connection etc) and is async to avoid blocking the current thread (and if it's the main one, that's all your UI that is blocked)
    – Larme
    Nov 10 at 20:52








  • 4




    Unrelated but never ever print pointless literal strings like "something is wrong" when an error occurred. That's pretty silly. Print the error instance to get a meaningful error description.
    – vadian
    Nov 10 at 20:58










  • @Larme I'm still about to learn swift and my code is written after reading tutorials. I'm still to new to transfer your comment to a solution. I think doing asynchrone requests is correct and it is my issue as the same time. If it was not asynchrone I was able to have the print(tasks.count) with 4, as well. But it should be asynchrone, so what is your proposed solution for me in detail? @vadian same here. I'm to new to transfer year answer in code. I googled and found catch let error and then print(error). Is this what you mean?
    – T. Karter
    Nov 10 at 21:20










  • catch let error is redundant. Just print(error). In your code put the things you want to do after the data has been received into the completion handler (replacing the working print line).
    – vadian
    Nov 10 at 21:22












  • Look for "Swift + Async + Closure" to know how manage Asynchrone. In a nutshell, dataTask(with:) use a closure to manage it, do the same by creating a closure on your method that will be called when the URLSession one will be called.
    – Larme
    Nov 11 at 8:47
















dataTask(with:) in WatchKit, macOS and iOS is asynchrone. The guard let data = data, ie the completion of the method is called whenever you got the the result of the request. I can differs (bad connection etc) and is async to avoid blocking the current thread (and if it's the main one, that's all your UI that is blocked)
– Larme
Nov 10 at 20:52






dataTask(with:) in WatchKit, macOS and iOS is asynchrone. The guard let data = data, ie the completion of the method is called whenever you got the the result of the request. I can differs (bad connection etc) and is async to avoid blocking the current thread (and if it's the main one, that's all your UI that is blocked)
– Larme
Nov 10 at 20:52






4




4




Unrelated but never ever print pointless literal strings like "something is wrong" when an error occurred. That's pretty silly. Print the error instance to get a meaningful error description.
– vadian
Nov 10 at 20:58




Unrelated but never ever print pointless literal strings like "something is wrong" when an error occurred. That's pretty silly. Print the error instance to get a meaningful error description.
– vadian
Nov 10 at 20:58












@Larme I'm still about to learn swift and my code is written after reading tutorials. I'm still to new to transfer your comment to a solution. I think doing asynchrone requests is correct and it is my issue as the same time. If it was not asynchrone I was able to have the print(tasks.count) with 4, as well. But it should be asynchrone, so what is your proposed solution for me in detail? @vadian same here. I'm to new to transfer year answer in code. I googled and found catch let error and then print(error). Is this what you mean?
– T. Karter
Nov 10 at 21:20




@Larme I'm still about to learn swift and my code is written after reading tutorials. I'm still to new to transfer your comment to a solution. I think doing asynchrone requests is correct and it is my issue as the same time. If it was not asynchrone I was able to have the print(tasks.count) with 4, as well. But it should be asynchrone, so what is your proposed solution for me in detail? @vadian same here. I'm to new to transfer year answer in code. I googled and found catch let error and then print(error). Is this what you mean?
– T. Karter
Nov 10 at 21:20












catch let error is redundant. Just print(error). In your code put the things you want to do after the data has been received into the completion handler (replacing the working print line).
– vadian
Nov 10 at 21:22






catch let error is redundant. Just print(error). In your code put the things you want to do after the data has been received into the completion handler (replacing the working print line).
– vadian
Nov 10 at 21:22














Look for "Swift + Async + Closure" to know how manage Asynchrone. In a nutshell, dataTask(with:) use a closure to manage it, do the same by creating a closure on your method that will be called when the URLSession one will be called.
– Larme
Nov 11 at 8:47




Look for "Swift + Async + Closure" to know how manage Asynchrone. In a nutshell, dataTask(with:) use a closure to manage it, do the same by creating a closure on your method that will be called when the URLSession one will be called.
– Larme
Nov 11 at 8:47












2 Answers
2






active

oldest

votes

















up vote
0
down vote



accepted










When you are trying to print number of tasks in willActivate(), function downloadJsonTask(url: String) hasn't been completed yet, so you have empty array because tasks haven't been set yet.



You should add completion handler to downloadJsonTask just like this:



(don't forget to pass completion as parameter of function)



func downloadJsonTask(url: String, completion: @escaping () -> Void) {
var request = URLRequest(url: URL(string: url)!)
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
URLSession.shared.dataTask(with: request) { data, urlResponse, error in

guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
completion()
return
}

do {
let decoder = JSONDecoder()
let downloadedTasks = try decoder.decode(Tasks.self, from: data)
self.tasks = downloadedTasks.tasks
print(downloadedTasks.tasks.count) //4
} catch {
print("something went wrong after downloading")
}
completion() // This is moment when code which you write inside closure get executed

}.resume()
}


In your willActivate() use this function like this:



downloadJsonTask(url: taskUrl) { 
print(tasks.count)
}


So that means when you get your data, your code inside curly braces will get executed.






share|improve this answer























  • It says Use of unresolved identifier 'completion'; did you mean 'Collection'?
    – T. Karter
    Nov 10 at 21:29










  • You have to pass completion: @escaping () -> Void as parameter of downloadJsonTask function
    – Robert Dresler
    Nov 10 at 21:31


















up vote
0
down vote













You’re correct in your assumption that tasks has not yet been assigned a value when it’s first printed.



The thing is network requests are performed asynchronously. It means that iOS does not wait until downloadJsonTask(url:) is finished but continues executing the code right away (i.e. it calls print(tasks.count) immediately after the network request started, without waiting for it to produce any results).



The piece of code inside brackets after URLSession.shared.dataTask(with:) is called a completion handler. This code gets executed once the network request is competed (hence the name). The tasks variable is assigned a value only when the request is finished. You can make sure it works by adding print(self.tasks.count) after self.tasks = downloadedTasks.tasks:



self.tasks = downloadedTasks.tasks
print(self.tasks)
print(downloadedTasks.tasks.count)





share|improve this answer





















  • Thank you. But still, how can I access the variable within willActivate()? My example is just print the count but in my real app I want to fill a table view and so on.
    – T. Karter
    Nov 10 at 21:31










  • You can add a completion handler to downloadJsonTask(url:) and make it @escaping (the function declaration will look like func downloadJsonTask(url: String, completionHandler: @escaping () -> Void). After self.tasks = downloadedTasks.tasks, call completion(). This will effectively pass the completion handler on from URLSession.shared.dataTask(with:) to downloadJsonTask(url:). If you’d like the results to be displayed in a table view, you’d have to refresh the table view once the network request is finished.
    – Yakov M.
    Nov 10 at 21:35












  • @T.Karter how can I access the variable within willActivate()? Not at all. Once again: Put the code to populate the table view in the completion handler of dataTask. An additional completion handler is actually not needed.
    – vadian
    Nov 10 at 21:43












  • That is true. You don’t necessarily need another completion handler. However, putting all the code in one place makes it look messy.
    – Yakov M.
    Nov 10 at 21:46













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',
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
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53243262%2fswift-order-of-functions-which-code-runs-when%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
0
down vote



accepted










When you are trying to print number of tasks in willActivate(), function downloadJsonTask(url: String) hasn't been completed yet, so you have empty array because tasks haven't been set yet.



You should add completion handler to downloadJsonTask just like this:



(don't forget to pass completion as parameter of function)



func downloadJsonTask(url: String, completion: @escaping () -> Void) {
var request = URLRequest(url: URL(string: url)!)
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
URLSession.shared.dataTask(with: request) { data, urlResponse, error in

guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
completion()
return
}

do {
let decoder = JSONDecoder()
let downloadedTasks = try decoder.decode(Tasks.self, from: data)
self.tasks = downloadedTasks.tasks
print(downloadedTasks.tasks.count) //4
} catch {
print("something went wrong after downloading")
}
completion() // This is moment when code which you write inside closure get executed

}.resume()
}


In your willActivate() use this function like this:



downloadJsonTask(url: taskUrl) { 
print(tasks.count)
}


So that means when you get your data, your code inside curly braces will get executed.






share|improve this answer























  • It says Use of unresolved identifier 'completion'; did you mean 'Collection'?
    – T. Karter
    Nov 10 at 21:29










  • You have to pass completion: @escaping () -> Void as parameter of downloadJsonTask function
    – Robert Dresler
    Nov 10 at 21:31















up vote
0
down vote



accepted










When you are trying to print number of tasks in willActivate(), function downloadJsonTask(url: String) hasn't been completed yet, so you have empty array because tasks haven't been set yet.



You should add completion handler to downloadJsonTask just like this:



(don't forget to pass completion as parameter of function)



func downloadJsonTask(url: String, completion: @escaping () -> Void) {
var request = URLRequest(url: URL(string: url)!)
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
URLSession.shared.dataTask(with: request) { data, urlResponse, error in

guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
completion()
return
}

do {
let decoder = JSONDecoder()
let downloadedTasks = try decoder.decode(Tasks.self, from: data)
self.tasks = downloadedTasks.tasks
print(downloadedTasks.tasks.count) //4
} catch {
print("something went wrong after downloading")
}
completion() // This is moment when code which you write inside closure get executed

}.resume()
}


In your willActivate() use this function like this:



downloadJsonTask(url: taskUrl) { 
print(tasks.count)
}


So that means when you get your data, your code inside curly braces will get executed.






share|improve this answer























  • It says Use of unresolved identifier 'completion'; did you mean 'Collection'?
    – T. Karter
    Nov 10 at 21:29










  • You have to pass completion: @escaping () -> Void as parameter of downloadJsonTask function
    – Robert Dresler
    Nov 10 at 21:31













up vote
0
down vote



accepted







up vote
0
down vote



accepted






When you are trying to print number of tasks in willActivate(), function downloadJsonTask(url: String) hasn't been completed yet, so you have empty array because tasks haven't been set yet.



You should add completion handler to downloadJsonTask just like this:



(don't forget to pass completion as parameter of function)



func downloadJsonTask(url: String, completion: @escaping () -> Void) {
var request = URLRequest(url: URL(string: url)!)
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
URLSession.shared.dataTask(with: request) { data, urlResponse, error in

guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
completion()
return
}

do {
let decoder = JSONDecoder()
let downloadedTasks = try decoder.decode(Tasks.self, from: data)
self.tasks = downloadedTasks.tasks
print(downloadedTasks.tasks.count) //4
} catch {
print("something went wrong after downloading")
}
completion() // This is moment when code which you write inside closure get executed

}.resume()
}


In your willActivate() use this function like this:



downloadJsonTask(url: taskUrl) { 
print(tasks.count)
}


So that means when you get your data, your code inside curly braces will get executed.






share|improve this answer














When you are trying to print number of tasks in willActivate(), function downloadJsonTask(url: String) hasn't been completed yet, so you have empty array because tasks haven't been set yet.



You should add completion handler to downloadJsonTask just like this:



(don't forget to pass completion as parameter of function)



func downloadJsonTask(url: String, completion: @escaping () -> Void) {
var request = URLRequest(url: URL(string: url)!)
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
URLSession.shared.dataTask(with: request) { data, urlResponse, error in

guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
completion()
return
}

do {
let decoder = JSONDecoder()
let downloadedTasks = try decoder.decode(Tasks.self, from: data)
self.tasks = downloadedTasks.tasks
print(downloadedTasks.tasks.count) //4
} catch {
print("something went wrong after downloading")
}
completion() // This is moment when code which you write inside closure get executed

}.resume()
}


In your willActivate() use this function like this:



downloadJsonTask(url: taskUrl) { 
print(tasks.count)
}


So that means when you get your data, your code inside curly braces will get executed.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 10 at 21:48

























answered Nov 10 at 21:22









Robert Dresler

79811




79811












  • It says Use of unresolved identifier 'completion'; did you mean 'Collection'?
    – T. Karter
    Nov 10 at 21:29










  • You have to pass completion: @escaping () -> Void as parameter of downloadJsonTask function
    – Robert Dresler
    Nov 10 at 21:31


















  • It says Use of unresolved identifier 'completion'; did you mean 'Collection'?
    – T. Karter
    Nov 10 at 21:29










  • You have to pass completion: @escaping () -> Void as parameter of downloadJsonTask function
    – Robert Dresler
    Nov 10 at 21:31
















It says Use of unresolved identifier 'completion'; did you mean 'Collection'?
– T. Karter
Nov 10 at 21:29




It says Use of unresolved identifier 'completion'; did you mean 'Collection'?
– T. Karter
Nov 10 at 21:29












You have to pass completion: @escaping () -> Void as parameter of downloadJsonTask function
– Robert Dresler
Nov 10 at 21:31




You have to pass completion: @escaping () -> Void as parameter of downloadJsonTask function
– Robert Dresler
Nov 10 at 21:31












up vote
0
down vote













You’re correct in your assumption that tasks has not yet been assigned a value when it’s first printed.



The thing is network requests are performed asynchronously. It means that iOS does not wait until downloadJsonTask(url:) is finished but continues executing the code right away (i.e. it calls print(tasks.count) immediately after the network request started, without waiting for it to produce any results).



The piece of code inside brackets after URLSession.shared.dataTask(with:) is called a completion handler. This code gets executed once the network request is competed (hence the name). The tasks variable is assigned a value only when the request is finished. You can make sure it works by adding print(self.tasks.count) after self.tasks = downloadedTasks.tasks:



self.tasks = downloadedTasks.tasks
print(self.tasks)
print(downloadedTasks.tasks.count)





share|improve this answer





















  • Thank you. But still, how can I access the variable within willActivate()? My example is just print the count but in my real app I want to fill a table view and so on.
    – T. Karter
    Nov 10 at 21:31










  • You can add a completion handler to downloadJsonTask(url:) and make it @escaping (the function declaration will look like func downloadJsonTask(url: String, completionHandler: @escaping () -> Void). After self.tasks = downloadedTasks.tasks, call completion(). This will effectively pass the completion handler on from URLSession.shared.dataTask(with:) to downloadJsonTask(url:). If you’d like the results to be displayed in a table view, you’d have to refresh the table view once the network request is finished.
    – Yakov M.
    Nov 10 at 21:35












  • @T.Karter how can I access the variable within willActivate()? Not at all. Once again: Put the code to populate the table view in the completion handler of dataTask. An additional completion handler is actually not needed.
    – vadian
    Nov 10 at 21:43












  • That is true. You don’t necessarily need another completion handler. However, putting all the code in one place makes it look messy.
    – Yakov M.
    Nov 10 at 21:46

















up vote
0
down vote













You’re correct in your assumption that tasks has not yet been assigned a value when it’s first printed.



The thing is network requests are performed asynchronously. It means that iOS does not wait until downloadJsonTask(url:) is finished but continues executing the code right away (i.e. it calls print(tasks.count) immediately after the network request started, without waiting for it to produce any results).



The piece of code inside brackets after URLSession.shared.dataTask(with:) is called a completion handler. This code gets executed once the network request is competed (hence the name). The tasks variable is assigned a value only when the request is finished. You can make sure it works by adding print(self.tasks.count) after self.tasks = downloadedTasks.tasks:



self.tasks = downloadedTasks.tasks
print(self.tasks)
print(downloadedTasks.tasks.count)





share|improve this answer





















  • Thank you. But still, how can I access the variable within willActivate()? My example is just print the count but in my real app I want to fill a table view and so on.
    – T. Karter
    Nov 10 at 21:31










  • You can add a completion handler to downloadJsonTask(url:) and make it @escaping (the function declaration will look like func downloadJsonTask(url: String, completionHandler: @escaping () -> Void). After self.tasks = downloadedTasks.tasks, call completion(). This will effectively pass the completion handler on from URLSession.shared.dataTask(with:) to downloadJsonTask(url:). If you’d like the results to be displayed in a table view, you’d have to refresh the table view once the network request is finished.
    – Yakov M.
    Nov 10 at 21:35












  • @T.Karter how can I access the variable within willActivate()? Not at all. Once again: Put the code to populate the table view in the completion handler of dataTask. An additional completion handler is actually not needed.
    – vadian
    Nov 10 at 21:43












  • That is true. You don’t necessarily need another completion handler. However, putting all the code in one place makes it look messy.
    – Yakov M.
    Nov 10 at 21:46















up vote
0
down vote










up vote
0
down vote









You’re correct in your assumption that tasks has not yet been assigned a value when it’s first printed.



The thing is network requests are performed asynchronously. It means that iOS does not wait until downloadJsonTask(url:) is finished but continues executing the code right away (i.e. it calls print(tasks.count) immediately after the network request started, without waiting for it to produce any results).



The piece of code inside brackets after URLSession.shared.dataTask(with:) is called a completion handler. This code gets executed once the network request is competed (hence the name). The tasks variable is assigned a value only when the request is finished. You can make sure it works by adding print(self.tasks.count) after self.tasks = downloadedTasks.tasks:



self.tasks = downloadedTasks.tasks
print(self.tasks)
print(downloadedTasks.tasks.count)





share|improve this answer












You’re correct in your assumption that tasks has not yet been assigned a value when it’s first printed.



The thing is network requests are performed asynchronously. It means that iOS does not wait until downloadJsonTask(url:) is finished but continues executing the code right away (i.e. it calls print(tasks.count) immediately after the network request started, without waiting for it to produce any results).



The piece of code inside brackets after URLSession.shared.dataTask(with:) is called a completion handler. This code gets executed once the network request is competed (hence the name). The tasks variable is assigned a value only when the request is finished. You can make sure it works by adding print(self.tasks.count) after self.tasks = downloadedTasks.tasks:



self.tasks = downloadedTasks.tasks
print(self.tasks)
print(downloadedTasks.tasks.count)






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 10 at 21:26









Yakov M.

165




165












  • Thank you. But still, how can I access the variable within willActivate()? My example is just print the count but in my real app I want to fill a table view and so on.
    – T. Karter
    Nov 10 at 21:31










  • You can add a completion handler to downloadJsonTask(url:) and make it @escaping (the function declaration will look like func downloadJsonTask(url: String, completionHandler: @escaping () -> Void). After self.tasks = downloadedTasks.tasks, call completion(). This will effectively pass the completion handler on from URLSession.shared.dataTask(with:) to downloadJsonTask(url:). If you’d like the results to be displayed in a table view, you’d have to refresh the table view once the network request is finished.
    – Yakov M.
    Nov 10 at 21:35












  • @T.Karter how can I access the variable within willActivate()? Not at all. Once again: Put the code to populate the table view in the completion handler of dataTask. An additional completion handler is actually not needed.
    – vadian
    Nov 10 at 21:43












  • That is true. You don’t necessarily need another completion handler. However, putting all the code in one place makes it look messy.
    – Yakov M.
    Nov 10 at 21:46




















  • Thank you. But still, how can I access the variable within willActivate()? My example is just print the count but in my real app I want to fill a table view and so on.
    – T. Karter
    Nov 10 at 21:31










  • You can add a completion handler to downloadJsonTask(url:) and make it @escaping (the function declaration will look like func downloadJsonTask(url: String, completionHandler: @escaping () -> Void). After self.tasks = downloadedTasks.tasks, call completion(). This will effectively pass the completion handler on from URLSession.shared.dataTask(with:) to downloadJsonTask(url:). If you’d like the results to be displayed in a table view, you’d have to refresh the table view once the network request is finished.
    – Yakov M.
    Nov 10 at 21:35












  • @T.Karter how can I access the variable within willActivate()? Not at all. Once again: Put the code to populate the table view in the completion handler of dataTask. An additional completion handler is actually not needed.
    – vadian
    Nov 10 at 21:43












  • That is true. You don’t necessarily need another completion handler. However, putting all the code in one place makes it look messy.
    – Yakov M.
    Nov 10 at 21:46


















Thank you. But still, how can I access the variable within willActivate()? My example is just print the count but in my real app I want to fill a table view and so on.
– T. Karter
Nov 10 at 21:31




Thank you. But still, how can I access the variable within willActivate()? My example is just print the count but in my real app I want to fill a table view and so on.
– T. Karter
Nov 10 at 21:31












You can add a completion handler to downloadJsonTask(url:) and make it @escaping (the function declaration will look like func downloadJsonTask(url: String, completionHandler: @escaping () -> Void). After self.tasks = downloadedTasks.tasks, call completion(). This will effectively pass the completion handler on from URLSession.shared.dataTask(with:) to downloadJsonTask(url:). If you’d like the results to be displayed in a table view, you’d have to refresh the table view once the network request is finished.
– Yakov M.
Nov 10 at 21:35






You can add a completion handler to downloadJsonTask(url:) and make it @escaping (the function declaration will look like func downloadJsonTask(url: String, completionHandler: @escaping () -> Void). After self.tasks = downloadedTasks.tasks, call completion(). This will effectively pass the completion handler on from URLSession.shared.dataTask(with:) to downloadJsonTask(url:). If you’d like the results to be displayed in a table view, you’d have to refresh the table view once the network request is finished.
– Yakov M.
Nov 10 at 21:35














@T.Karter how can I access the variable within willActivate()? Not at all. Once again: Put the code to populate the table view in the completion handler of dataTask. An additional completion handler is actually not needed.
– vadian
Nov 10 at 21:43






@T.Karter how can I access the variable within willActivate()? Not at all. Once again: Put the code to populate the table view in the completion handler of dataTask. An additional completion handler is actually not needed.
– vadian
Nov 10 at 21:43














That is true. You don’t necessarily need another completion handler. However, putting all the code in one place makes it look messy.
– Yakov M.
Nov 10 at 21:46






That is true. You don’t necessarily need another completion handler. However, putting all the code in one place makes it look messy.
– Yakov M.
Nov 10 at 21:46




















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53243262%2fswift-order-of-functions-which-code-runs-when%23new-answer', 'question_page');
}
);

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







Popular posts from this blog

Florida Star v. B. J. F.

Danny Elfman

Retrieve a Users Dashboard in Tumblr with R and TumblR. Oauth Issues