Issue with global variables and Alamofire - ios

So, I am trying to do a Alamofire request, then, I'd take the information I need from the JSON data and put it into a global variable, here's my code.
struct myVariables {
static var variableOne = ""
}
func function() {
Alamofire.request(.GET, "API URL").responseJSON { response in
if let rawJSON = response.result.value {
// Here I just take the JSON and put it into dictionaries and parse the data.
myVariables.variableOne = String("data")
}
}
}
Ok, so basically, I am trying to access variableOne's data from another Swift file. Let's say I made two Swift files and in one of those files I had a function that edited the value of global variable, in the other file, if I attempted to print that global variable, I'd see the edited value. But whenever I use Alamofire, when I try to edit a global variable, the other Swift file doesn't see the changed value. So if I tried to edit the global variable within the Alamofire request block of code, I don't see the change whenever I print the variable from another file.
If anyone knows a better way to phrase that, please do correct it.

I suspect the problem isn't that you're not seeing the value change, but rather an issue arising from the fact that you're dealing with an asynchronous method. For example, when you call function, it returns immediately, but your variableOne may not be updated immediately, but rather later. I bet you're checking it before this asynchronous response closure had a chance to be called.
You wouldn't have this problem if, rather than using this "global" (which is a bad idea, anyway), you instead adopted the completion handler pattern yourself.
func performRequest(completionHandler: #escaping (String?, Error?) -> Void) {
Alamofire.request("API URL").responseJSON { response in
switch response.result {
case .failure(let error):
completionHandler(nil, error)
case .success(let responseObject):
let dictionary = responseObject as? [String: Any]
let string = dictionary?["someKey"] as? String
completionHandler(string, nil)
}
}
}
An you'd call this like so:
performRequest() { string, error in
guard let string = string, error == nil else {
// handle error here
return
}
// use `string` here
}
// but not here, because the above closure runs asynchronously (i.e. later)
By using this completion handler pattern, we solve the "how do I know when the asynchronous method is done" problem. And by passing the necessary data back as a parameter of the closure, we can excise the use of globals, keeping the scope of our data as narrow as possible.
Clearly, you should change the parameter of the closure to match whatever is appropriate in your case. But hopefully this illustrates the basic idea.
See previous revision of this answer for Swift 2/Alamofire 3 answer.

Related

Swift Closures and order of execution

I'm struggling a little bit trying to create an application for my own education purposes using Swift.
Right now I have the following (desired) order of execution:
TabView
FirstViewController - TableView
Check into CoreData
If data exists update an array using a closure
If data doesn't exists then download it using Alamofire from API and store it into Core Data
SecondViewController - CollectionView
Checks if data of images exists in Core Data, if it does, loads it from there, otherwise download it.
The problem that I'm struggling the most is to know if the code after a closure is executed after (synchronously) the closure ends or it might be executed before or while the closure is executed.
For example:
FirstViewController
var response: [DDGCharacter]
//coreData is an instance of such class
coreData.load(onFinish: { response in //Custom method in another class
print("Finished loading")
self.response = response
})
print("Executed after loading data from Core Data")
//If no data is saved, download from API
if response.count == 0 {
//Download from API
}
I have done the above test with the same result in 10 runs getting:
Finished loading
Executed after loading data from Core Data
In all 10, but it might be because of load is not taking too much time to complete and thus, appear to be synchronous while it's not.
So my question is, is it going to be executed in that order always independent of amount of data? Or it might change? I've done some debugging as well and both of them are executed on the main thread as well. I just want to be sure that my suppositions are correct.
As requested in the comments, here's the implementation done in the load() method:
func load(onFinish: ([DDGCharacter]) -> ()) {
var characters: [DDGCharacter] = []
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject> (entityName: "DDGCharacter")
do {
characters = try managedContext.fetch(fetchRequest) as! [DDGCharacter]
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
onFinish(characters)
}
Your implementation of load(onFinish:) is very surprising and over-complicated. Luckily, though, that helps demonstrate the point you were asking about.
A closure is executed when something calls it. So in your case, onFinish is called at the end of the method, which makes it synchronous. Nothing about being "a closure" makes anything asynchronous. It's just the same as calling a function. It is completely normal to call a closure multiple times (map does this for instance). Or it might never be called. Or it might be called asynchronously. Fundamentally, it's just like passing a function.
When I say "it's slightly different than an anonymous function," I'm just referring to the "close" part of "closure." A closure "closes over" the current environment. That means it captures variables in the local scope that are referenced inside the closure. This is slightly different than a function (though it's more about syntax than anything really deep; functions can actually become closures in some cases).
The better implementation would just return the array in this case.

#escaping closure actually runs before return

I am implementing download request from a remote source and i ran into the notion of #escaping function. As Apple says:
A closure is said to escape a function when the closure is passed as
an argument to the function, but is called after the function returns.
But I actually noticed (with the breakpoint tool) that it calls and implements before return statement.
static func fetchFeaturedApps(completionHandler: #escaping ([AppCategory]) -> ()) {
let urlString = "https://api.letsbuildthatapp.com/appstore/featured"
URLSession.shared.dataTask(with: URL(string: urlString)!) {
(data, response,error) -> Void in
if error != nil {
print(error?.localizedDescription)
return
}
do {
let json = try(JSONSerialization.jsonObject(with: data!, options: .mutableContainers)) as! Dictionary<String, Any>
var appCategories = [AppCategory]()
// invokes before return [![enter image description here][1]][1]
completionHandler(appCategories)
for dict in json["categories"] as! [[String: Any]] {
let appCategory = AppCategory()
appCategory.setValuesForKeys(dict)
appCategories.append(appCategory)
}
print(appCategories)
DispatchQueue.main.async {
// completionHandler(appCategories)
}
} catch let error as NSError {
print(error.localizedDescription)
}
}.resume()
}
Then and of course after it deals with "completionHandler" it goes on implementing function further, as if i send it plain closure. It turns out #escaping closure call before return statement, strictly in the place where I call it in function body.
But I think maybe I am wrong? Maybe Apple keeps in mind another scenario? Please how do I need to understand #escaping notation with Apples quote about calling them after return? Actually in the example it calls before return , why?
You said:
It turns out #escaping closure [is called] strictly in the place where I call it in function body.
Yep, that's exactly what happens. It's called wherever you place it in your code. If you happen to call it before you return from the method, that's what it's going to do.
As others have pointed out, the fact that it is declared as #escaping means that it can be called later, not that it will necessarily be called later.
In fact, this pattern of calling an #escaping closure synchronously (i.e. before the method returns) is not uncommon. For example, you'll see this if you're dealing with network requests where responses can be cached. In that scenario, you might check your cache and call the closure immediately if the resource has already been retrieved, but call the closure asynchronously if it wasn't previously cached and you have to now retrieve the resource asynchronously from the web. E.g., you might have something like:
func fetchImage(for identifier: String, completion: #escaping (UIImage?) -> Void) {
if let image = cache.retrieveImage(for: identifier) {
completion(image)
return
}
webService.fetchImageAsynchronously(for: identifier) { image in
completion(image)
}
}
Note, just because the closure is designated as #escaping, that doesn't mean that my code path is required to call it asynchronously, regardless. I can call the closure either synchronously or asynchronously, whatever makes sense.
That having been said, if you have a method where you know that you will always call the closure synchronously, you would not use the #escaping designation. Not only would gratuitous use of #escaping in non-escaping scenarios make one's code unclear, but the #escaping designation prevents the compiler from performing certain types of optimizations. So we only use #escaping where it's needed, i.e. in those cases that we know it will or can be called asynchronously.
As it is said in documentation:
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write #escaping before the parameter’s type to indicate that the closure is allowed to escape.
Declaring a closure #escaping does not make it execute after your function returns. It just means that it may or may not execute after function returns, which completely depends on your code.
Concerning your code, your closure is directly called in the function context, so it is no wonder that closure is executed before the function returns. If you would like to make it execute after the function returns, you may want to use some multithreading mechanism, like GCD or OperationQueue.

Closure cannot implicitly capture a mutating self parameter

I am using Firebase to observe event and then setting an image inside completion handler
FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.img = UIImage(named:"Some-image")!
} else {
self.img = UIImage(named: "some-other-image")!
}
})
However I am getting this error
Closure cannot implicitly capture a mutating self parameter
I am not sure what this error is about and searching for solutions hasn't helped
The short version
The type owning your call to FirebaseRef.observeSingleEvent(of:with:) is most likely a value type (a struct?), in which case a mutating context may not explicitly capture self in an #escaping closure.
The simple solution is to update your owning type to a reference once (class).
The longer version
The observeSingleEvent(of:with:) method of Firebase is declared as follows
func observeSingleEvent(of eventType: FIRDataEventType,
with block: #escaping (FIRDataSnapshot) -> Void)
The block closure is marked with the #escaping parameter attribute, which means it may escape the body of its function, and even the lifetime of self (in your context). Using this knowledge, we construct a more minimal example which we may analyze:
struct Foo {
private func bar(with block: #escaping () -> ()) { block() }
mutating func bax() {
bar { print(self) } // this closure may outlive 'self'
/* error: closure cannot implicitly capture a
mutating self parameter */
}
}
Now, the error message becomes more telling, and we turn to the following evolution proposal was implemented in Swift 3:
SE-0035: Limiting inout capture to #noescape contexts
Stating [emphasis mine]:
Capturing an inout parameter, including self in a mutating
method, becomes an error in an escapable closure literal, unless the
capture is made explicit (and thereby immutable).
Now, this is a key point. For a value type (e.g. struct), which I believe is also the case for the type that owns the call to observeSingleEvent(...) in your example, such an explicit capture is not possible, afaik (since we are working with a value type, and not a reference one).
The simplest solution to this issue would be making the type owning the observeSingleEvent(...) a reference type, e.g. a class, rather than a struct:
class Foo {
init() {}
private func bar(with block: #escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
Just beware that this will capture self by a strong reference; depending on your context (I haven't used Firebase myself, so I wouldn't know), you might want to explicitly capture self weakly, e.g.
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
Sync Solution
If you need to mutate a value type (struct) in a closure, that may only work synchronously, but not for async calls, if you write it like this:
struct Banana {
var isPeeled = false
mutating func peel() {
var result = self
SomeService.synchronousClosure { foo in
result.isPeeled = foo.peelingSuccess
}
self = result
}
}
You cannot otherwise capture a "mutating self" with value types except by providing a mutable (hence var) copy.
Why not Async?
The reason this does not work in async contexts is: you can still mutate result without compiler error, but you cannot assign the mutated result back to self. Still, there'll be no error, but self will never change because the method (peel()) exits before the closure is even dispatched.
To circumvent this, you may try to change your code to change the async call to synchronous execution by waiting for it to finish. While technically possible, this probably defeats the purpose of the async API you're interacting with, and you'd be better off changing your approach.
Changing struct to class is a technically sound option, but doesn't address the real problem. In our example, now being a class Banana, its property can be changed asynchronously who-knows-when. That will cause trouble because it's hard to understand. You're better off writing an API handler outside the model itself and upon finished execution fetch and change the model object. Without more context, it is hard to give a fitting example. (I assume this is model code because self.img is mutated in the OP's code.)
Adding "async anti-corruption" objects may help
I'm thinking about something among the lines of this:
a BananaNetworkRequestHandler executes requests asynchronously and then reports the resulting BananaPeelingResult back to a BananaStore
The BananaStore then takes the appropriate Banana from its inside by looking for peelingResult.bananaID
Having found an object with banana.bananaID == peelingResult.bananaID, it then sets banana.isPeeled = peelingResult.isPeeled,
finally replacing the original object with the mutated instance.
You see, from the quest to find a simple fix it can become quite involved easily, especially if the necessary changes include changing the architecture of the app.
If someone is stumbling upon this page (from search) and you are defining a protocol / protocol extension, then it might help if you declare your protocol as class bound. Like this:
protocol MyProtocol: class {
...
}
You can try this! I hope to help you.
struct Mutating {
var name = "Sen Wang"
mutating func changeName(com : #escaping () -> Void) {
var muating = self {
didSet {
print("didSet")
self = muating
}
}
execute {
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 15, execute: {
muating.name = "Wang Sen"
com()
})
}
}
func execute(with closure: #escaping () -> ()) { closure() }
}
var m = Mutating()
print(m.name) /// Sen Wang
m.changeName {
print(m.name) /// Wang Sen
}
Another solution is to explicitly capture self (since in my case, I was in a mutating function of a protocol extension so I couldn't easily specify that this was a reference type).
So instead of this:
functionWithClosure(completion: { _ in
self.property = newValue
})
I have this:
var closureSelf = self
functionWithClosure(completion: { _ in
closureSelf.property = newValue
})
Which seems to have silenced the warning.
Note this does not work for value types so if self is a value type you need to be using a reference type wrapper in order for this solution to work.

Unable Return String from CLGeocoder reverseGeocodeLocation

I want to write a function to reverse geocode a location and assign the resulting string into a variable. Following this post i've got something like this:
extension CLLocation {
func reverseGeocodeLocation(completion: (answer: String?) -> Void) {
CLGeocoder().reverseGeocodeLocation(self) {
if let error = $1 {
print("[ERROR] \(error.localizedDescription)")
return
}
if let a = $0?.last {
guard let streetName = a.thoroughfare,
let postal = a.postalCode,
let city = a.locality else { return }
completion(answer: "[\(streetName), \(postal) \(city)]")
}
}
}
}
For calling this function i've just got something like this:
location.reverseGeocodeLocation { answer in
print(answer)
}
But instead i want to assign the string value of answer to a variable and i don't know how to pass that data out of the closure. What is the best way to do something like this?
The problem is that it runs asynchronously, so you can't return the value. If you want to update some property or variable, the right place to do that is in the closure you provide to the method, for example:
var geocodeString: String?
location.reverseGeocodeLocation { answer in
geocodeString = answer
// and trigger whatever UI or model update you want here
}
// but not here
The entire purpose of the closure completion handler pattern is that is the preferred way to provide the data that was retrieved asynchronously.
Short answer: You can't. That's not how async programming works. The function reverseGeocodeLocation returns immediately, before the answer is available. At some point in the future the geocode result becomes available, and when that happens the code in your closure gets called. THAT is when you do something with your answer. You could write the closure to install the answer in a label, update a table view, or some other behavior. (I don't remember if the geocoding methods' closures get called on the main thread or a background thread. If they get called on a background thread then you would need to wrap your UI calls in dispatch_async(dispatch_get_main_queue()).)

How do I access a json array created in a function across my application?

This has to be easy and I'm just missing something. I have a function in my application that is posting to a server, getting a response, and turning that response into an NSDictionary, and then turning one of the values sets in that NSDictionary into an NSArray. I need to access the values in this array outside of the scope of the function that created them. How can I make a json response available to my whole application if it is created within a specific function? Thanks!
There's a few ways you can do this, one of them is, as #GoodSp33d mentioned, NSUserDefaults another way is by using a completion handler and if you are open to using singletons, that's an option as well.
NSUserDefaults
// settings
var jo : [NSObject : AnyObject] = [
"a" : "1.0",
"b" : "2.0"
]
// store your value
userDefaults.setObject(jo, forKey: akey)
// optionally synchronize
var isOk = userDefaults.synchronize()
// safely retrieve your value
if let data0 = userDefaults.dictionaryForKey(akey) {
print(data0)
} else {
print("not set")
}
(source: Martin R)
note: this method actually persists the data to local storage making
it available across multiple sessions
#diatrevolo added:
It should be stated for consistency purposes that NSUserDefaults are
not always persistent across platforms. tvOS user defaults, for
example, get purged by the system
Singleton Method
There are a lot of people, myself included, that prefer not to use this approach but other consider this perfectly valid. This is the singleton approach. Setting your value to this property makes it globally available within your app.
struct sharedResult {
static var sharedDict: NSDictionary = nil
}
(more singleton approaches)
note: this method holds your data for the session only.
Completion Handler
However, I personally like to wrap my HTTP Requests in a closure / completion handler and when I have my object back from the server, I pass it into the completion handler.
// definition
func HTTPConnect(completion: (result: Bool)->()) {
// make http request {
// once you have your result pass it back
completion(result: myResult)
// }
}
// call from where you need the data
HTTPConnect() { (result) -> () in
// do stuff with the result
print(result)
}
Note: this method doesn't hold your data at all. It does, however, make it
easy for you to pass your value from one controller to another.

Resources