@tonioverzeworld Iâve edited the article to use weatherbit.io. Hope youâll give it a try.
Wow!
I got an email from Dark Sky, Apple seems to have acquired it. Thought of updating that here, and seems the tutorial has already been updated to use a different API. Neat!
Thanks, Iâll do it this week-end. Thanks for this quick update !
I have a similar question:
when the submitAction
is declared in the IBAction promptForLocation
in the WeatherViewController, the closure to the UIAlertAction has an unowned
reference to the alert and a weak
reference to the WeatherViewController.
let submitAction = UIAlertAction(
title: "Submit",
style: .default) { [unowned alert, weak self] _ in
according to the swift docs
Use a weak reference when the other instance has a shorter lifetimeâthat is, when the other instance can be deallocated first. âŠ
In contrast, use an unowned reference when the other instance has the same lifetime or a longer lifetime.
Why arenât both of these references declared as unowned?
The alert outlives submitAction
but doesnât the WeatherViewController as well?
Rather than focus on the lifecycle durations, letâs look at what unowned
and weak
really mean. Both will not cause the reference to be retained. Using weak
will treat the reference as optional and make sure that the reference is not nil before attempting to use it. Using unowned
will not check for nil and can cause a crash. So neither is right or wrong, just safer (weak
) and more dangerous (unowned
). When you use unowned
, you must be sure that the reference will always be populated when invoked.
Here is a discussion about weak
vs unowned
at SwiftLee:
The only benefit of using unowned over weak is that you donât have to deal with optionals. Therefore, using weak is always safer in those scenarios.
To gain a better understanding of the Box
class, I abstracted it into an Xcode playground and started testing it with String
types. The one thing Iâm having trouble understanding is how does changing the value on boxedString
trigger my print function to be called? I understand the first call to print function, but the second call confuses me. I also observed the didSet
property calling listener
, but Iâm still not seeing how the magic happens. Here is the code:
final class Box<T> {
typealias Listener = (T) -> Void
private var listener: Listener?
var value: T {
didSet {
listener?(value)
}
}
init(_ value: T) {
self.value = value
}
func bind(listener: Listener?) {
self.listener = listener
listener?(value)
}
}
// Testing Box
let boxedString = Box("Chris")
boxedString.bind { name in
print("Value changed: \(name)")
}
boxedString.value = "Chuck"
When you call bind
on the boxedString
, you provide a function that calls print
and boxedString
retains a copy of that function in the listener
property then immediately calls that listener
.
{ name in
print("Value changed: \(name)")
}
is your listener function.
Then when you change the value of the boxedString
, the didSet
method is immediately invoked, causing the listener
function to be invoked again. For as long as the boxedString
stays in memory, it will keep a copy of the listener
that you provided and invoke it each time the value
changes. That is the magic of using didSet
in Swift.
Hope that answers your question.
Chuck, I had been pounding my head at this for 4 hours yesterday. You helped me understand the whole data binding concept in its entirety. Thank you!
Great tutorial loved it thank you
While going through it I noticed the before app has an error asking for where the âclear-skyâ image is. You go into the storyboard and it indeed is missing.
Also thereâs a typo in the tutorial: âYou must import the app for texting. Immediately below import XCTest
, add the followingâ
Good finds, @kaylanx. As you can see in the discussion above, had to change weather APIs from DarkSky to Weatherbit after the tutorial was released. I guess I missed a few things. Iâll clean then up now. Thanks for bringing them to my attention.
This is one of the best tutorials I have ever seen! Thank you so very much for creating a tutorial that not only covers the pertinent content so thoroughly but also does it in a way that is very easy to understand. Very awesome.
Thank you for taking the time to share some feedback. Very motivating. Iâm truly glad that you found it helpful.
Thanks for the article. I think if we use Delegation method as data binding it is more like MVP than MVVM. since the viewModel is depend on view.
Hi Chuck,
Thank you for the tutorial. I have a question here.
Can we use Boxing as a data binding method for any kind of app (big or small).
I am still in the learning phase of Combine framework.
The best explanation there can be of the Boxing concept. Thank you so much for this tutorial. Really enjoyed it!
I am trying to understand why did the code for presenting the alert may cause retain cycle. I am confused because the alert is not declared as a property in the view controller like the geocoder is. Please let me know if my understanding below is correct.
The alert is presented on the view controller (self) so the view controller holds a strong reference to it and vice versa, thus we need to access self using weak attribute to avoid retain cycle. Likewise the submit action is added onto the alert thereby alert holding a strong reference to it and vice versa. And hence we use unowned alert so as to avoid retain cycle.
Am I correct? Thank You.
You basically have it, though Iâd word it slightly differently. The alert
variable is a stack variable that only exists for the duration of the promptForLocation(_:)
call. The closure for the UIAlertAction
will grab strong references to alert
and to self
unless you make them weak or unowned. In this case, the alert is actually very short lived and really doesnât represent much of a risk of a retain cycle. But it is my practice to use weak references to be cautious whenever the closure is retained by the other type. It truly is a confusing topic and I recommend you study it deeply until it really clicks. Advanced Swift Memory Management is a good tutorial to deep dive into this topic.
You can use boxing in any sized app, but it really is a simplistic approach. The Combine framework is much more robust and will have many advantages if you have the option to use it.