private weak var _delegate: SomeClassDelegate?
weak var delegate: SomeClassDelegate? {
get {
return _delegate
}
set {
_delegate = newValue
}
}
This is valid code. Is there is any sense in using weak keyword with computed delegate property? Logically no; how compiler will process through this code?
Is there is any sense in using weak keyword with computed delegate property?
Not only is it sensible to do so, but it’s important to do so. This computed property is your public interface to this private hidden property. If the computed property lacks the weak qualifier, callers will draw incorrect conclusions about the underlying semantics.
Consider:
class SomeClass {
private weak var _delegate: SomeClassDelegate?
var delegate: SomeClassDelegate? { // whoops; this should be `weak`
get { return _delegate }
set { _delegate = newValue }
}
}
And
class CustomDelegate: SomeClassDelegate { ... }
Then
let object = SomeClass()
object.delegate = CustomDelegate()
In the absence of the the weak qualifier on the computed property and without diving into the implementation details, the programmer might incorrectly conclude that the above is fine. But it’s not. Because the underlying _delegate is weak, this CustomDelegate() instance will be deallocated immediately, and the object will end up with no delegate object. And there’s no compiler warning about this behavior.
If, however, we fix SomeClass like so:
class SomeClass {
private weak var _delegate: SomeClassDelegate?
weak var delegate: SomeClassDelegate? { // great; matches underlying semantics
get { return _delegate }
set { _delegate = newValue }
}
}
Then the programmer will receive a very helpful warning:
let object = SomeClass()
object.delegate = CustomDelegate() // results in "Instance will be immediately deallocated because property 'delegate' is 'weak'"
They’ll then correctly deduce that they should keep their own strong reference to this CustomDelegate for the code to work properly.
So, bottom line, you don’t technically need the weak qualifier on the computed property that is backed by a private weak stored property, but it’s prudent to do so to avoid mysterious bugs and/or misunderstandings about the underlying semantics.
Computed properties aren't retain by ARC, so you don't need to mark it as weak.
Only one pros that I know about is to ensure that property could be nil in future. You cannot declare it as:
weak var youProperty: YourType {
get {
return _yourProperty
}
set {
_yourProperty = newValue
}
}
Related
Let's consider following code:
// Just for easier testing
protocol Printer {
var delayer: Delayer { get }
}
// Retain cycle
class Printer1: Printer {
private func action() {
print("action")
}
private(set) lazy var delayer: Delayer = {
return Delayer(action)
}()
deinit {
print("deinit")
}
}
// Works fine, but weak mess
class Printer2: Printer {
private func action() {
print("action")
}
private(set) lazy var delayer: Delayer = {
return Delayer { [weak self] in self?.action() }
}()
deinit {
print("deinit")
}
}
// Questionable hack, but works fine
class Printer3: Printer {
private func action() {
print("action")
}
private(set) lazy var delayer: Delayer = {
return Delayer(weakAction)
}()
// computed property or function is also fine here
private lazy var weakAction: () -> Void = {
return { [weak self] in
self?.action()
}
}()
deinit {
print("deinit")
}
}
// Retain cycle
class Printer4: Printer {
private func action() {
print("action")
}
private(set) lazy var delayer: Delayer = {
weak var welf: Printer4? = self
return Delayer(welf?.action ?? {})
}()
deinit {
print("deinit")
}
}
// Works fine
class Printer5: Printer {
private func action() {
print("action")
}
private(set) lazy var delayer: Delayer = {
weak var welf: Printer5? = self
return Delayer { welf?.action() }
}()
deinit {
print("deinit")
}
}
class Delayer {
private var action: () -> Void
init(_ action: #escaping () -> Void) {
self.action = action
}
func run() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in
self?.action()
}
}
}
So we have a Printer class which contains a Delayer class that takes the action on Printer and performs it delayed.
We call it something like this:
var printer: Printer? = PrinterX()
printer?.delayer.run()
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
printer = nil
}
It is clear why Printer1 creates retain cycle. Action is passed into delayer with implicit strong self which cannot be released because Delayer is owned by Printer.
Printer2 is the intended way in my opinion. Obviously doesn't create retain cycle, but it is kind of mess to write all the time. Thats why I started experimenting with other solution.
I don't understand why Printer3 doesn't create retain cycle. Because weakAction is property on self, so passing it like that into Delayer should create strong reference like in Printer1.
I also don't understand why Priner4 does create retain cycle. welf is local weak reference to self, so it should not increase the reference count when passing it into the Delayer.
Strangely enough using the welf inside closure in Printer5 doesn't create retain cycle.
Questions
Can anyone please explain to me this weird behavior on Printer3, Printer4 and Printer5
I am tempted to use the Printer3 solution. Is it safe to use? As it seems almost like a bug, can I use it without worrying about it being fixed in future versions and therefore creating retain cycle in my app?
First of all, all printers are creating and retaining their own Delayer. The delayer takes a closure and, in turn, retains that closure.
Let's try to walk through them one by one.
Printer1
As you stated yourself, it's pretty clear why it's creating a retain cycle. You are passing the self.action instance method as the closure to the Delayer, and since all closures are reference types, passing self.action will retain its surrounding scope (which is Printer1).
Printer2
Again, pretty obvious here. You're explicitly capturing a weak reference to self inside the closure you're passing to Delayer, hence not creating a retain cycle.
Printer3
Here, a retain cycle is not created, because the self.weakAction property is called immediately, and its result (a closure which holds a weak reference to self) is passed on to Delayer. This, in effect, is the exact same thing as what's happening in Printer2.
Printer4
First, you're capturing a weak reference to self, and then fetching welf?.action and passing the result into Delayer. Again, welf?.action is called immediately, and the result (a pointer to an instance method) is passed on to Delayer. The weak reference to self is only kept for the duration of the surrounding scope (the lazy var creation scope), and passing the action instance method will retain self. This is identical to Printer1.
Printer5
Here, you're first creating a weak reference to self, and then you're capturing that weak reference inside a new closure that is passed to Delayer. Since self is never directly referenced in the passed closure, it will not capture self in that scope, only the welf weak reference. This is pretty much identical to Printer2, but with a slightly different syntax.
Personally, I would opt for the Printer2 way (creating a new closure, retaining a weak reference to self and using that to call self?.action). It makes for the easiest code to follow (as opposed to retaining a variable with a closure that weakly captures self). But, depending on what you're actual use case is, it might of course make sense.
My view model is as such:
public class MainTabBarViewModel: MainTabBarInputs {
unowned var output: MainTabBarOutputs
...
}
where the view controller is this:
class ViewController: MainTabBarOutputs {
var viewModel: MainTabBarInputs!
}
I'm trying to write a unit test to test for the retain cycle:
class MainTabBarViewModelTests: XCTestCase {
var viewModel: MainTabBarViewModel!
var viewController: MockMainTabBarViewController!
func testRetainViewController() {
viewController = nil
// TODO how do you test this
expect(self.viewModel.output).to(beNil())
// crashes because I can't
// reference an unowned pointer that's deallocated.
}
I know if I changed my reference to be weak I could test this, but what if I wanted to leave it as unowned?
You can use a weak reference to the controller in the unit test, and if that reference becomes nil, then you don't have a retain cycle:
func testRetainViewController() {
weak var testRef = viewController
viewController = nil
expect(testRef).to(beNil())
}
You can easily validate the above approach by changing from unowned to strong and see that the test fails.
In Swift, if I create a delegate protocol, it can be conformed to by class and struct.
protocol MyDelegate {
// Can be conformed to by class or struct
}
The issue comes up when I declare the delegate. If the delegate is a class instance, I want the variable to be weak to avoid retain cycle. If it is a struct, there is no such need - in fact, Swift won't allow me to make the delegate variable weak. Note: I know how to create a weak delegate, but the key question is - if you create a delegate protocol that can be weak, unless you make it class-conforming only, you cannot enforce retain cycle.
class MyClass {
// Want weak var here to avoid cyclical reference
// but Swift won't allow it because MyDelegate can be
// conformed by struct as well. Dropping weak means
// cyclical reference cannot be prevented
weak var delegate: MyDelegate?
}
class MyConformingClass: MyDelegate {
}
or
struct MyConformingStruct: MyDelegate {
}
It seems like we need to declare the protocol to be for class only at all times like this because a non regular delegate protocol cannot prevent retain cycles:
protocol MyDelegate: class {
}
The fact that Swift allows you to shoot yourself in the foot this way seems to go against its design philosophy in safety.
If you really want to support a protocol on a class or struct you can always store the delegate in separate underlying variables. That way you can have one weak for when the delegate is a class. Along the lines of the following:
protocol MyDelegate {
// Can be conformed to by class or struct
}
class MyClass {
private weak var delegateFromClass: AnyObject?
private var delegateFromStruct: MyDelegate?
var delegate: MyDelegate? {
get {
return (delegateFromClass as? MyDelegate) ?? delegateFromStruct
}
set {
if newValue is AnyObject {
delegateFromClass = newValue as? AnyObject
delegateFromStruct = nil
} else {
delegateFromClass = nil
delegateFromStruct = newValue
}
}
}
}
class MyConformingClass: MyDelegate {
}
struct MyConformingStruct: MyDelegate {
}
print(" \(MyConformingClass() is AnyObject) \(MyConformingStruct() is AnyObject)")
It takes two to have a retain cycle...
If you really want to do it this way, then why not leave out the weak and just make it a strong reference. You would only have a problem if the delegate also maintained a strong reference to the object that it was delegating for.
So it becomes the duty of the delegate to make sure any reciprocal references are weak, which should be possible all of the time since MyClass is a class, and therefore you can always declare a weak reference to it.
I have a simple class below
import Foundation
public class UsefulClass: NSObject{
var test:NSNumber{
get{return self.test}
set{
println(newValue)
self.test = newValue
}
}
override init() {
super.init()
self.test = 5;
}
}
and I'm initializing it here
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var testClass = UsefulClass()
}
}
But it results in xcode printing out 200 5s and then crashing due to EXC_BAD_ACCESS code = 2. Why does this happen?
#vadian has provided a solution in his answer, which should fix your problem. Let me just explain what's happening.
You have created a computed property, i.e. a property which is not backed by a variable, instead both the getter and the setter do some processing, usually on another stored property, in order to respectively return a value and set a new value.
This is your computed property:
var test: NSNumber {
get { return self.test }
set {
println(newValue)
self.test = newValue
}
}
Look at the getter implementation:
return self.test
What does it do? It reads the test property of the current instance, and returns it. Which is the test property? It's this one:
var test: NSNumber {
get { return self.test }
set {
println(newValue)
self.test = newValue
}
}
Yes, it's the same property. What your getter does is to recursively and indefinitely calling itself, until a crash happen at runtime.
The same rule applies to the setter:
self.test = newValue
it keeps invoking itself, until the app crashes.
Swift variables are synthesized properties by default.
In the most cases this is sufficient (it's recommended to prefer Swift types)
var test: Int
override init() {
super.init()
test = 5
}
If you need to do something after a variable is set, use
var test: Int {
didSet{
println("\(oldValue) - \(newValue)")
}
}
your code sets the variable permanently by calling the setter which calls the setter which …
It's an infinite loop; your setter is recursively calling itself.
var test: NSNumber {
set {
test = newValue
}
}
This compiles fine, and an Objective-C programmer might expect no loop due to instead setting a "backing ivar" such as _test rather than re-calling the setter method.
But property-backing instance variable _ivars do not exist in Swift for computed properties unless you create them yourself.
Cyclic references getting formed in this example, however I can't apply unowned or weak to protocol variables, what's the workaround in this situation.
protocol Report {
func done()
}
class Employee {
unowned var report: Report? //error here with using unowned or weak
func whenIAmDone() {
report.done()
}
}
class Supervisor: Report {
var employees: [Employee]?
init() {
for i in 1...5 {
var employee = Employee()
employee.report = self
employees?.append(employee)
}
}
func done() {
println("work done by...")
}
}
You need to declare your Report protocol as class-only by adding class to its declaration:
protocol Report: class {
func done()
}
You have a separate issue there, with disagreement between your choice of "weak" keywords and the report property being optional. Here's the rule: weak instances are always optional, unowned instances are never optional. Employee should look like this:
class Employee {
weak var report: Report? //error here with using unowned or weak
func whenIAmDone() {
report?.done()
}
}
or if you want report to be unowned, it would need to be a non-Optional, but then you need an initializer that can give it a value.
You have to declare your protocol as class-only like below.
protocol Report : class {
func done()
}
class Employee {
weak var report: Report?
func whenIAmDone() {
report?.done()
}
}
Read this to learn the difference between weak and unowned. What is the difference between a weak reference and an unowned reference?