Swift closure keeps retaining weakly captured object - ios

I use VIP cycle architecture in my project, where UIViewController has strong reference to Interator, Interactor has strong reference to Presenter and Presenter has weak reference to UIViewController:
UIViewController -> Interactor -> Presenter - -> UIViewController
After UIViewController dismiss all other module components usually deallocate too.
I have an someSharedService that fetches data from server in background queue and send updates in the queue via 'reactive' someSharedProperty.
Interactor is subscribed to the property:
someSharedService.someSharedProperty.subscribeForUpdate { [weak self] _ in
self?.presenter.sendUpdates()
}
And presenter updates view:
func sendUpdates() {
// this string crashes the app
view!.render()
}
I know that crash is happening because view is force unwrapped, but the root of the problem is that after viewController is dismissed interactor is still alive. But it must be deallocated right after the view deallocated. After checking out memory graph I found out that it's a closure (and only it) holding the interactor, despite it captured weakly.
Here's my implementation of the reactive property:
protocol Subscribable {
associatedtype SubscribeType
typealias UpdateResultsHandler = (_ values: SubscribeType) -> Void
var subscribers: [UpdateResultsHandler?] { get }
func subscribeForUpdate(_ updateHandler: #escaping UpdateResultsHandler)
}
class SubscribableProperty<Type>: Subscribable {
typealias SubscribeType = Type
private(set) var subscribers: [UpdateResultsHandler?] = []
var value: Type {
didSet {
subscribers.forEach {
$0?(value)
}
}
}
init(value: Type) {
self.value = value
}
func subscribeForUpdate(_ updateHandler: #escaping UpdateResultsHandler) {
subscribers.append(updateHandler)
}
}
That's how it looks in memory graph after crash:

Related

About Swift closure captures a weak property

Let us say we have a class A like below
class SomeView {
var didDoneSomething: () -> Void = {}
}
class A {
weak delegate: B?
private lazy var someView: SomeView {
let view = someView()
view.didDoneSomething = { [delegate] in
delegate?.someFunction()
}
return view
}
}
I was reading this article by Sundell
https://www.swiftbysundell.com/articles/swifts-closure-capturing-mechanics/
It looks like you can directly capture any properties as long as those properties either contain reference types (class instances), or immutable value types.
I am not so sure if it has retain cycle problem or not. Should I use [weak delegate] or not?
Any suggestion? Thank you!
Assuming request method is an instance function of ImageLoader, there should not be a retain cycle at all.
On the other hand, if we have something like this:
class ImageLoader {
private let service: ServiceProtocol
private let cache = Cache<URL, Image>()
func loadImage(
from url: URL,
then handler: #escaping (Result<Image, Error>) -> Void
) {
service.request(url) { [cache] result in
do {
let image = try result.decodedAsImage()
cache.insert(image, forKey: url)
handler(.success(image))
} catch {
handler(.failure(error))
}
}
}
}
This indeed creates a retain cycle because ImageLoader will have a strong reference to the service dependency, and service will reference ImageLoader (it calls self.cache) in its closure. In this case, Cache would need to be captured as a weak reference.

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.

iOS/Swift - What is the difference between Closure/Completion blocks and Delegates/functions?

I don't clear about these two, Nowadays the world is shifting to the closure types. But I'm not clearly understanding this. Can someone explain me with a real-time example?
So a real life example of both would be something like this:
protocol TestDelegateClassDelegate: class {
func iAmDone()
}
class TestDelegateClass {
weak var delegate: TestDelegateClassDelegate?
func doStuff() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.delegate?.iAmDone()
}
}
}
class TestClosureClass {
var completion: (() -> Void)?
func doStuff() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.completion?()
}
}
}
class ViewController: UIViewController, TestDelegateClassDelegate {
func iAmDone() {
print("TestDelegateClassDelegate is done")
}
override func viewDidLoad() {
super.viewDidLoad()
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()
let testingClosure = TestClosureClass()
testingClosure.completion = {
print("TestClosureClass is done")
}
testingClosure.doStuff()
}
}
Here we have 2 classes TestDelegateClass and TestClosureClass. Each of them have a method doStuff which waits for 3 seconds and then reports back to whoever is listening where one uses delegate procedure and the other one uses closure procedure.
Although they do nothing but wait you can easily imagine that they for instance upload an image to server and notify when they are done. So for instance you might want to have an activity indicator running while uploading is in progress and stop it when done. It would look like so:
class ViewController: UIViewController, TestDelegateClassDelegate {
#IBOutlet private var activityIndicator: UIActivityIndicatorView?
func iAmDone() {
print("TestDelegateClassDelegate is done")
activityIndicator?.stopAnimating()
}
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator?.startAnimating()
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()
activityIndicator?.startAnimating()
let testingClosure = TestClosureClass()
testingClosure.completion = {
self.activityIndicator?.stopAnimating()
print("TestClosureClass is done")
}
testingClosure.doStuff()
}
}
Naturally you would only use one of the two procedures.
You can see there is a huge difference in code. To do a delegate procedure you need to create a protocol, in this case TestDelegateClassDelegate. A protocol is what defines the interface of a listener. And since an iAmDone method is defined it must be defined in ViewController as well as long as it is defined as TestDelegateClassDelegate. Otherwise it will not compile. So anything declared as TestDelegateClassDelegate will have that method and any class can call it. In our case we have weak var delegate: TestDelegateClassDelegate?. That is why we can call delegate?.iAmDone() without caring what delegate actually is. For instance we can create another class:
class SomeClass: TestDelegateClassDelegate {
func iAmDone() {
print("Something cool happened")
}
init() {
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()
}
}
So a good example for instance is an UITableView that uses a delegate and dataSource (both are delegates, just properties are named differently). And table view will call the methods of whatever class you set to those properties without needing to know what that class is as long as it corresponds to the given protocols.
Same could be achieved with closures. A table view could have been defined using properties giving closures like:
tableView.onNumberOfRows { section in
return 4
}
But that would most likely lead into one big mess of a code. Also closures would in this case be giving many programmers headaches due to potential memory leaks. It is not that closures are less safe or anything, they just do a lot of code you can't see which may produce retain cycles. In this specific case a most likely leak would be:
tableView.onNumberOfRows { section in
return self.dataModel.count
}
and a fix to it is simply doing
tableView.onNumberOfRows { [weak self] section in
return self?.dataModel.count ?? 0
}
which now looks overcomplicated.
I will not go into depths of closures but in the end when you have repeated call to callbacks (like in case of table view) you will need a weak link either at delegate or in closure. But when the closure is called only once (like uploading an image) there is no need for a weak link in closures (in most but not all cases).
In retrospective use closures as much as possible but avoid or use caution as soon as a closure is used as a property (which is ironically the example I gave). But you would rather do just this:
func doSomethingWithClosure(_ completion: #escaping (() -> Void)) {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
completion()
}
}
And use it as
doSomethingWithClosure {
self.activityIndicator?.stopAnimating()
print("TestClosureClass is done")
}
This has now removed all potential risks. I hope this clears a thing or two for you.
In Swift/obj-c the term delegate is used to refer to a protocol that responds to specific selectors.
Thing about it just like calling a method on an object.
E.g.
protocol CalculatorDelegate : class { // : class so it can be made 'weak'
func onCalculation(result: Int) -> Void
}
Now if we have a Calculator class, to use the delegate we'd do something like
class Calculator() {
weak var delegate: CalculatorDelegate?
func calculate(_ a: Int, _ b: Int) -> Int {
let result = a + b
self.delegate?.onCalculation(result: result)
return result
}
}
Then in some other class (e.g. in iOS - a View Controller) we might do:
class MyClass : CalculatorDelegate {
func onCalculation(result: Int) {
print("Delegate method on calculation called with result \(result)")
}
func someButtonPress() {
let calculator = Calculator()
calculator.delegate = self
calculator.calculate(42, 66)
}
}
So you can see how the setup is quite elaborate.
Now closures are simply blocks of code that can be called in other places, so you could change all of the code like so:
class Calculator2() {
weak var delegate: CalculatorDelegate?
func calculate(_ a: Int, _ b: Int, onCalculation: (#escaping (Int) -> Void) -> Int)?) {
let result = a + b
onCalculation?(result)
return result
}
}
class MyClass {
func someButtonPress() {
let calculator = Calculator2()
calculator.calculate(42, 66, onCalculation: { (result: Int) in
print("Closure invoked with \(result)")
})
}
}
However, with closures you need to be aware that it is a lot easier to shoot yourself in the foot by capturing variables (e.g. self) strongly, which will lead to memory leaks even under ARC regime.
Closures are first-class objects so that they can be nested and passed around
Simply,
In swift, functions are primitive data types like int, double or character that is why you can pass a function in the function parameter. In swift mechanism simplify in closures syntax like lambda expression in other languages.
E.g. If you want to call rest API through URSSession or Alamofire and return response data then you should use completionHandler(it's closure).
Void closure : - {(paramter:DataType)->Void}
Return closure : - {(paramter:DataType)->DataType}
e.g. (int, int) -> (int)
https://docs.swift.org/swift-book/LanguageGuide/Closures.html

Why is this a retain cycle?

I have basic understanding of ARC but in the following example I suddenly get really confused.
FeedViewController has a strong reference of NetworkHelper, then the NetworkHelper has a function which takes a closure and call it later.
So here's the confusion:
the closure is passed from FeedViewController to NetworkHelper, And this block is not being retained inside NetworkHelper, so why does NetworkHelper has a strong reference of NetworkHelper? this is stated in an article but I just could't figure out why. It makes sense to me only if NetworkHelper keep a strong reference to the block.
class NetworkHelper {
func getFeed(completion: #escaping ([FeedItem]) -> Void) {
Alamofire.request(…).responseJSON { (response) in
if let value = response.result.value {
if let json = JSON(value)[Constants.items].array {
completion(json.flatMap(FeedItem.init))
}
}
}
}
}
class FeedViewController {
var tableView: UITableViewController
var feedItems: [FeedItem]
var networkHelper: NetworkHelper
override func viewDidLoad() {
...
networkHelper.getFeed() { items in
self.feedItems = items
self.tableView.reloadData()
}
}
}
Technically, there is no cycle.
First of all, NetworkHelper never owns anything, it just passes a closure to Alamofire.
Alamofire holds to that closure, which retains a FeedViewController instance (as self). However, Alamofire is not owned by FeedViewController, therefore there is no cycle.
It's true that while the request is running, FeedViewController cannot be deallocated because the completion callback prevents that, but that could be an expected behavior and there is definitely no ownership cycle.

set properties on rectangle request. iOS, Swift

Im trying to set properties on a rectangle request.
Im trying to set minimum size, aspect ratio and others but get the error below.
Fatal error: Attempted to read an unowned reference but the object was already deallocated2018-08-13 16:08:09.081049+0100 app[4000:1277980] Fatal error: Attempted to read an unowned reference but the object was already deallocated
func performVisionRequest(image: CGImage, orientation: CGImagePropertyOrientation) {
DispatchQueue.global(qos: .userInitiated).async {
do {
let imageRequestHandler = VNImageRequestHandler(cgImage: image, orientation: orientation, options: [:])
try imageRequestHandler.perform(
[VNDetectRectanglesRequest(completionHandler:{ req, err in
self.rectanglesRequest(request:req, error:err)
})]
)
} catch let error as NSError {
self.sliceCompletion([UIImage]())
print("Failed to perform vision request: \(error)")
}
}
}
func rectanglesRequest(request: VNRequest, error: Error?) {
if let err = error as NSError? {
noRect = true
var slices = [imageNo]
self.sliceCompletion(slices as! [UIImage])
slices = []
print("Failed during detection: \(err.localizedDescription)")
return
}
unowned let rectanglesRequestSet = VNDetectRectanglesRequest()
rectanglesRequestSet.minimumSize = 0.07
rectanglesRequestSet.minimumAspectRatio = 0.2
rectanglesRequestSet.maximumAspectRatio = 0.3
rectanglesRequestSet.quadratureTolerance = 22.0
Here it is not good to mark rectanglesRequestSet as unowned, as it is causing it to be released before you can use it and when you attempt to message a released unowned object you will get a crash, which is explains the message you get:
Attempted to read an unowned reference but the object was already deallocated
unowned is used to break retain cycles which occur when a class's property holds a reference back to class itself, often through a closure. For example:
class ViewControllerA: UIViewController {
let viewControllerB = UIViewControllerB()
override func viewDidLoad() {
super.viewDidLoad()
viewControllerB.onSelect = {
self.onSelection()
}
}
func onSelection() {
// do something
}
}
class ViewControllerB: UIViewController {
var onSelect: (() -> Void)?
}
For example the code above creates a retain cycle as vcA -> vcB -> onSelect -> vcA, where vcA is an instance of ViewControllerA and vcB is an instance of ViewControllerB. vcA and vcB will never be released as vcA holds a reference to vcB by virtue of it being a property. And, vcB holds a reference to vcA by virtue of variable capture in the onSelect closure. This happens because in order for closures to execute code in the future they must hold a reference to all of the objects used in the closure, in the example vcA is the only object used so the closure holds a reference to it and vcB holds a reference to the closure. To prevent this retain cycle:
viewControllerB.onSelect = { [unowned self]
self.onSelection()
}
or
viewControllerB.onSelect = { [weak self]
self?.onSelection()
}
will cause the closure to not capture vcA meaning there will be no retain cycle. It is safer to use weak rather than unowned. The closure can't guarantee that un-captured objects will be around at execution weak will allow such objects to be nil, unowned is, in a manner, stipulating that it won't be nil and instructing the program to crash if it is.

Resources