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.
swift watchkit
add a comment |
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.
swift watchkit
dataTask(with:)
in WatchKit, macOS and iOS is asynchrone. Theguard 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 anerror
occurred. That's pretty silly. Print theerror
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 theprint(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 foundcatch let error
and thenprint(error)
. Is this what you mean?
– T. Karter
Nov 10 at 21:20
catch let error
is redundant. Justprint(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 theURLSession
one will be called.
– Larme
Nov 11 at 8:47
add a comment |
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.
swift watchkit
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
swift watchkit
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. Theguard 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 anerror
occurred. That's pretty silly. Print theerror
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 theprint(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 foundcatch let error
and thenprint(error)
. Is this what you mean?
– T. Karter
Nov 10 at 21:20
catch let error
is redundant. Justprint(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 theURLSession
one will be called.
– Larme
Nov 11 at 8:47
add a comment |
dataTask(with:)
in WatchKit, macOS and iOS is asynchrone. Theguard 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 anerror
occurred. That's pretty silly. Print theerror
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 theprint(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 foundcatch let error
and thenprint(error)
. Is this what you mean?
– T. Karter
Nov 10 at 21:20
catch let error
is redundant. Justprint(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 theURLSession
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
add a comment |
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.
It saysUse 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
add a comment |
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)
Thank you. But still, how can I access the variable withinwillActivate()
? 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 todownloadJsonTask(url:)
and make it@escaping
(the function declaration will look likefunc downloadJsonTask(url: String, completionHandler: @escaping () -> Void)
. Afterself.tasks = downloadedTasks.tasks
, callcompletion()
. This will effectively pass the completion handler on fromURLSession.shared.dataTask(with:)
todownloadJsonTask(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 ofdataTask
. 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
add a comment |
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.
It saysUse 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
add a comment |
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.
It saysUse 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
add a comment |
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.
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.
edited Nov 10 at 21:48
answered Nov 10 at 21:22
Robert Dresler
79811
79811
It saysUse 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
add a comment |
It saysUse 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
add a comment |
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)
Thank you. But still, how can I access the variable withinwillActivate()
? 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 todownloadJsonTask(url:)
and make it@escaping
(the function declaration will look likefunc downloadJsonTask(url: String, completionHandler: @escaping () -> Void)
. Afterself.tasks = downloadedTasks.tasks
, callcompletion()
. This will effectively pass the completion handler on fromURLSession.shared.dataTask(with:)
todownloadJsonTask(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 ofdataTask
. 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
add a comment |
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)
Thank you. But still, how can I access the variable withinwillActivate()
? 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 todownloadJsonTask(url:)
and make it@escaping
(the function declaration will look likefunc downloadJsonTask(url: String, completionHandler: @escaping () -> Void)
. Afterself.tasks = downloadedTasks.tasks
, callcompletion()
. This will effectively pass the completion handler on fromURLSession.shared.dataTask(with:)
todownloadJsonTask(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 ofdataTask
. 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
add a comment |
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)
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)
answered Nov 10 at 21:26
Yakov M.
165
165
Thank you. But still, how can I access the variable withinwillActivate()
? 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 todownloadJsonTask(url:)
and make it@escaping
(the function declaration will look likefunc downloadJsonTask(url: String, completionHandler: @escaping () -> Void)
. Afterself.tasks = downloadedTasks.tasks
, callcompletion()
. This will effectively pass the completion handler on fromURLSession.shared.dataTask(with:)
todownloadJsonTask(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 ofdataTask
. 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
add a comment |
Thank you. But still, how can I access the variable withinwillActivate()
? 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 todownloadJsonTask(url:)
and make it@escaping
(the function declaration will look likefunc downloadJsonTask(url: String, completionHandler: @escaping () -> Void)
. Afterself.tasks = downloadedTasks.tasks
, callcompletion()
. This will effectively pass the completion handler on fromURLSession.shared.dataTask(with:)
todownloadJsonTask(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 ofdataTask
. 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
add a comment |
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%2f53243262%2fswift-order-of-functions-which-code-runs-when%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
dataTask(with:)
in WatchKit, macOS and iOS is asynchrone. Theguard 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 anerror
occurred. That's pretty silly. Print theerror
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 foundcatch let error
and thenprint(error)
. Is this what you mean?– T. Karter
Nov 10 at 21:20
catch let error
is redundant. Justprint(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 theURLSession
one will be called.– Larme
Nov 11 at 8:47