Holding a Strong ref to local object that uses closure [Swift] - ios

I have a question regarding holding a Strong ref to local object that uses closure.
I have the following code, which object B uses a method with closure of a local object of type A.
The method in object A, uses async action to perform some network task and then return the closure to object b.
Since object A is local in a method in B and since i'm using [weak self] in the the object A async task (to prevent retain cycle), the object gets released.
What should i change in the following code in order to ensure the local A object will get released only when the closure is done?
This is part of the important code:
class A {
var restAPI: RestAPI?
func fetchNews(completion: (_ json: [String:Any])->()) {
// .....
self.restAPI.fetch(url: url, results: { [weak self] (json) in //
completion(json)
})
// .....
}
}
class B {
// ....
// ... call to updateNews()
func updateNews() {
let aFetcher: A()
aFetcher.fetchNews(completion : {
// <<<< // aFetcher gets released and closue never called
// parse...
}
}
}

You declare aFetcher as a let in the scope of func updateNews()
When the scope of updateNews() reaches its end aFetcher will be released.
Your have [weak self] in your internal fetch function.
On this stage aFetcher will be released because updateNews() finish its executing and there are no strong references to this object.
You just need to add variable aFetcher to class B to ensure you have strong reference to aFetcher.
class B {
// MARK: - Vars
private let aFetcher = A()
// MARK: - Public
func updateNews() {
aFetcher.fetchNews(completion : {
// parse...
}
}
}

You need a strong reference on the top level of the class.
However not to keep the reference permanently and to retain and release it reliably add a optional stored property in class B and set it to nil in the completion closure:
class B {
var fetcher : A?
// MARK: - Public
func updateNews() {
fetcher = A()
fetcher!.fetchNews(completion : { [unowned self] in
// parse...
self.fetcher = nil
}
}
}

Related

How do you write a Swift completion block that can only be called once?

Let's say I have a Swift class that stores a completion block, and does a few asynchronous tasks.
I want that block to be called by whichever of the tasks finishes first, but only that one - I don't want it to be called again when the second task finishes.
How can I implement this in a clean way?
As long as you don't need this to be thread safe, you can solve this problem with a fairly straightforward #propertyWrapper.
#propertyWrapper
struct ReadableOnce<T> {
var wrappedValue: T? {
mutating get {
defer { self._value = nil }
return self._value
}
set {
self._value = newValue
}
}
private var _value: T? = nil
}
Mark the completion block var with #ReadableOnce, and it will be destroyed after the first time it's value is read.
Something like this:
class MyClass {
#ReadableOnce private var completion: ((Error?) -> Void)?
init(completion: #escaping ((Error?) -> Void)) {
self.completion = completion
}
public func doSomething() {
// These could all be invoked from different places, like your separate tasks' asynchronous callbacks
self.completion?(error) // This triggers the callback, then the property wrapper sets it to nil.
self.completion?(error) // This does nothing
self.completion?(error) // This does nothing
}
}
I wrote up more of a detailed discussion of this here but the key thing to be aware of is that reading the value sets it to nil, even if you don't invoke the closure! This might be surprising to someone who isn't familiar with the clever property wrapper you've written.
There is already a standard expression of onceness. Unfortunately the standard Objective-C is unavailable in Swift (GCD dispatch_once), but the standard Swift technique works fine, namely a property with a lazy define-and-call initializer.
Exactly how you do this depends on the level at which you want onceness to be enforced. In this example it's at the level of the class instance:
class MyClass {
// private part
private let completion : (() -> ())
private lazy var once : Void = {
self.completion()
}()
private func doCompletionOnce() {
_ = self.once
}
// public-facing part
init(completion:#escaping () -> ()) {
self.completion = completion
}
func doCompletion() {
self.doCompletionOnce()
}
}
And here we'll test it:
let c = MyClass() {
print("howdy")
}
c.doCompletion() // howdy
c.doCompletion()
let cc = MyClass() {
print("howdy2")
}
cc.doCompletion() // howdy2
cc.doCompletion()
If you promote the private stuff to the level of the class (using a static once property), the completion can be performed only once in the lifetime of the entire program.

Swift closure is still in memory after VC deinit is called

I have a bluetooth class which passes when a char value is updated to a closure in a view controller (as well as the same closure in a singleton class). when the VC deinit is called, the closure in the VC is still being executed when the char value is updated. I am using [weak self] for the closure in the VC. I'd like to be able to stop this VC closure from being called when the view is deinitialised. But I also don't understand why the other callback in the singleton is not being executed after the VC is presented!
Included below is the syntax for the closure inside the VC
bluetooth.updatedCharacteristicsValue { [weak self] char in
[weak self] does not mean that the closure can be discarded, it only prevents the closure from retaining the VC (and therefore preventing the VC from being deinited).
Simply begin your closure with:
guard let self = self else { return }
... to exit early if the VC no longer exists.
As for why the closure supplied by the VC is being called but the one in the singleton isn't, it sounds like your bluetooth class doesn't understand the concept of multiple 'users'. Whoever registers their callback last is the one that is called.
An approach to handling your own observer registration with convenient self-unregistering tokens:
class ObserverToken {
let id = UUID()
private let onDeinit: (UUID) -> ()
init(onDeinit: #escaping (UUID) -> ()) {
self.onDeinit = onDeinit
}
deinit {
onDeinit(id)
}
}
class BluetoothThing {
// Associate observers with the .id of the corresponding token
private var observers = [UUID: (Int) -> ()]()
func addObserver(using closure: #escaping (Int) -> ()) -> ObserverToken {
// Create a token which sets the corresponding observer to nil
// when it is deinit'd
let token = ObserverToken { [weak self] in self?.observers[$0] = nil }
observers[token.id] = closure
return token
}
func tellObserversThatSomethingHappened(newValue: Int) {
// However many observers we currently have, tell them all
observers.values.forEach { $0(newValue) }
}
deinit {
print("👋")
}
}
// I've only made this var optional so that it can later be set to nil
// to prove there's no retain cycle with the tokens
var bluetooth: BluetoothThing? = BluetoothThing()
// For as long as this token exists, updates will cause this closure
// to be called. As soon as this token is set to nil, it's deinit
// will automatically deregister the closure
var observerA: ObserverToken? = bluetooth?.addObserver { newValue in
print("Observer A saw: \(newValue)")
}
// Results in:
// Observer A saw: 42
bluetooth?.tellObserversThatSomethingHappened(newValue: 42)
// A second observer
var observerB: ObserverToken? = bluetooth?.addObserver { newValue in
print("Observer B saw: \(newValue)")
}
// Results in:
// Observer A saw: 123
// Observer B saw: 123
bluetooth?.tellObserversThatSomethingHappened(newValue: 123)
// The first observer goes away.
observerA = nil
// Results in:
// Observer B saw: 99
bluetooth?.tellObserversThatSomethingHappened(newValue: 99)
// There is still one 'live' token. If it is retaining the
// Bluetooth object then this assignment won't allow the
// Bluetooth to deinit (no wavey hand)
bluetooth = nil
So if your VC stores it's token as a property, when the VC goes away, the token goes away and the closure is deregistered.

Closure recursion and retain cycles

My closure retains itself. It causes capturing all other objects inside. I can pass such objects using weak reference, but it doesn't solve the problem of retain cycle. What's the right way to do recursion with closures without retain cycles?
class Foo {
var s = "Bar"
deinit {
print("deinit") // Won't be executed!
}
}
class TestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo() // Weak works, but not the right solution.
var closure: () -> Void = { return }
closure = {
print(foo.s)
if true {
return
} else {
closure()
}
}
}
}
You have an unusual setup where your closure retains itself. Note that Swift doesn't allow you to create a weak reference to a closure.
To break the retain cycle, set closure to { } in the base case of the recursion. Here's a test macOS command-line program:
func test() {
var closure: ((Int) -> ()) = { _ in }
closure = { i in
if i < 10 {
closure(i + 1)
} else {
// Comment out this line for unbounded memory consumption.
closure = { _ in }
}
}
closure(0)
}
while true {
test()
}
If you run this, its memory consumption is flat.
If you comment out the line in the base case that resets closure, its memory consumption grows without bound.
Your closure is holding foo instance reference.
foo will be released as soon as the closure is released.
closure is calling itself. If we pass weak self inside closure then that should be fine. OR by resetting closure
below code should work fine.
var closure: () -> Void = { return }
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
closure = { [weak self] in
print(foo.s)
if true {
return
} else {
self?.closure()
}
}
}
OR initialize foo inside closure
override func viewDidLoad() {
super.viewDidLoad()
var closure: () -> Void = { return }
closure = { [weak self] in
let foo = Foo()
print(foo.s)
if true {
return
} else {
self?.closure()
}
}
}
Turn your closure into a nested function:
class Foo {
var s = "Bar"
deinit {
print("deinit")
}
}
class TestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
func nestedFunction() {
print(foo.s)
if true {
return
} else {
nestedFunction()
}
}
nestedFunction()
}
}
In Swift nested functions can refer to themselves synchronously (recursive functions) or asynchronously (typically for asynchronous iteration), can do so without any reference cycle, and can capture variables just as well as closures do. You can even have mutually recursive nested functions.
You could instead reset the closure-containing variable to a dummy closure once done, I am not saying this does not work, but this is very error-prone, especially when the closure calls itself asynchronously: the reset has to be done asynchronously as well in that case. Better have the lack of a reference cycle be ensured statically, as can be done most everywhere else in Swift.
(The concept used to have a bad rap due to an implementation in the C language by gcc that introduced security holes as a result of attempting to squeeze a closure reference into a C function pointer i.e. a code address, but Swift nested functions have nothing to do with that)

Add property observer to global variable inside class in Swift

I have a variable globalVariable declared at global scope that may change at any time.
Different ViewControllers in my app need to react differently, when globalVariable changes.
Thus it would be desirable to add a property observer in each ViewController that execute the needed code when globalVariable changes.
I cannot seem to achieve it with override or extension. What is the way to go here?
If your goal is to simply know when your global variable changed, you could have it post a notification upon change:
extension NSNotification.Name {
static let globalVariableChanged = NSNotification.Name(Bundle.main.bundleIdentifier! + ".globalVariable")
}
var globalVariable: Int = 0 {
didSet {
NotificationCenter.default.post(name: .globalVariableChanged, object: nil)
}
}
Then any object can add an observer for that notification:
class ViewController: UIViewController {
private var observer: NSObjectProtocol!
override func viewDidLoad() {
super.viewDidLoad()
// add observer; make sure any `self` references are `weak` or `unowned`; obviously, if you don't reference `self`, that's not necessary
observer = NotificationCenter.default.addObserver(forName: .globalVariableChanged, object: nil, queue: .main) { [weak self] notification in
// do something with globalVariable here
}
}
deinit {
// remember to remove it when this object is deallocated
NotificationCenter.default.removeObserver(observer)
}
}
Note, this didSet mechanism will not detect changes if (a) the global variable is a reference type, i.e. a class; and (b) it merely mutates the object that the global variable references rather than replacing it with a new instance. To identify that scenario, you need to use KVO or other mechanism to detect mutation.
There can be only one didSet{} function for your global variable and it must belong to the variable itself. What you can do is make the variable's didSet{} function call a list of functions from other objects.
You could use notifications for this or you could build your own mechanism.
Here's an example of how you could create your own mechanism:
(note that this is pretty generic and could work for any variable types or singleton instance)
// Container for an observer's function reference
// - will be used to call the observer's code when the variable is set
// - Separates the object reference from the function reference
// to avoid strong retention cycles.
struct GlobalDidSet<T>
{
weak var observer:AnyObject?
var didSetFunction:(AnyObject)->(T)->()
init(_ observer:AnyObject, didSet function:#escaping (AnyObject)->(T)->())
{
self.observer = observer
didSetFunction = function
}
}
// Container for a list of observers to be notified
// - maintains the list of observers
// - automatically clears entries that non longer have a valid object
// - calls all observers when variable changes
// - erases type of observer to allow generic use of GlobalDidSet<>
struct GlobalDidSets<T>
{
var observers : [GlobalDidSet<T>] = []
mutating func register<O:AnyObject>(_ observer:O, didSet function:#escaping (O)->(T)->())
{
let observer = GlobalDidSet<T>(observer)
{ (object:AnyObject) in function(object as! O) }
observers.append(observer)
}
mutating func notifyDidSet(_ oldValue:T)
{
observers = observers.filter{$0.observer != nil}
observers.forEach{ $0.didSetFunction($0.observer!)(oldValue) }
}
}
...
// To use this, you will need a second variable to manage the list of observers
// and your global variable's didSet{} must use that observer list
// to perform the multiple function calls
//
var globalVariableDidSets = GlobalDidSets<String>()
var globalVariable : String = "Initial Value"
{
didSet { globalVariableDidSets.notifyDidSet(oldValue) }
}
// In your view controllers (or any other class), you need to setup the
// reaction to the global variable changes by registering to the observer list
//
class MyVC:UIViewController
{
override func viewDidLoad()
{
globalVariableDidSets.register(self){ $0.handleVariableChange }
// ...
}
func handleVariableChange(_ oldValue:String)
{
//...
}
}

Using 'self' on RxSwift closures... What about instance methods as param?

In other stack overflow questions, it was emphasized that the capture [weak self] should be used for closures that aren't owned by the class because self could be nil before the closure completes. An alternative when the closure is owned by the class itself is [unowned self].
My question is do I need to use [unowned self] when the function I pass as a parameter is an instance method of the current class?
Example
import RxSwift
class Person {
var name = "Default name"
class func getPersons() -> Observable<Person> {
// ...
}
}
class MyController: UIViewController {
let disposeBag = DisposeBag()
// I know this right
func unownedDisplayPeople() {
Person.getPersons()
.subscribeNext { [unowned self ] person in
self.displayName(person)
}
.addDisposableToBag(disposeBag)
}
// But what about this?
func whatAboutThisDisplayPeople() {
Person.getPersons()
.subscribeNext(displayName)
.addDisposableToBag(disposeBag)
}
// Or this?
func orThisDisplayPeople() {
Person.getPersons()
.subscribeNext(self.displayName)
.addDisposableToBag(disposeBag)
}
func displayName(person: Person) {
print("Person name is \(person.name)")
}
}
If I still need to think about the reference counting when I just pass an instance method, how do I do it? Where do i put the [unowned self]? Or is it considered [unowned self] already when I just pass the instance method?
Unfortunately, passing an instance method to subscribeNext will retain self. To be more generic, storing a reference to an instance method will increase the retain count of the instance.
let instance = ReferenceType()
print(CFGetRetainCount(instance)) // 1
let methodReference = instance.method
print(CFGetRetainCount(instance)) // 2
The only solution here is do what you have done in unownedDisplayPeople.
let instance = ReferenceType()
print(CFGetRetainCount(instance)) // 1
let methodReference = { [unowned instance] in instance.method() }
print(CFGetRetainCount(instance)) // 1

Resources