set properties on rectangle request. iOS, Swift - ios

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.

Related

Swift closure keeps retaining weakly captured object

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:

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.

ARC Retain Cycles, Grand Central Dispatch and Closures

I understand that if you assign a closure to a property such as:
var someClosure : () -> Void?
let someConstant : Int = 5
And call that closure from its class' init with a reference to self:
someClosure = { print(self.someConstant) }
Then this will result in a retain cycle, so I should use weak to avoid it.
But I couldn't understand the following code which is from a raywenderlich.com tutorial:
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
guard let self = self else {
return
}
self.someFunction()
}
Why a retain cycle exists here - since we didn't create a reference from view to closure (i.e., saving closure as a property) but only from closure to self; shouldn't it be retain cycle-free?
You are right and Ray is wrong:
Grand Central Dispatch closures don't cause retain cycles.
You can delete
[weak self] in
guard let self = self else {
return
}
Please see also https://digitalleaves.com/blog/2015/05/demystifying-retain-cycles-in-arc/

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.

Optimizing capture lists

Is there such a thing? Is there any difference between the two below? Is one more "correct" than the other?
All objects are properties of self (let's say a view controller) and have the same lifetime as self. We can introduce an object with a shorter lifetime than self, which would be weak, but the same question applies.
objectOne.doSomething { [unowned self] in
self.objectTwo.finish()
self.tableView.reloadData()
// self.someDelegate?.didFinishSomething()
}
vs
objectOne.doSomething {
[unowned objectTwo = self.objectTwo,
unowned tableView = self.tableView
// weak someDelegate = self.delegate
] in
objectTwo.finish()
tableView.reloadData()
// someDelegate?.didFinishSomething()
}
Apple has this example in their docs:
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
delegate?.doSomething()
}
In this case, delegate can have a shorter lifetime than self, but why not use it like this?
lazy var someClosure: () -> String = {
[unowned self] in
// closure body goes here
self.delegate?.doSomething()
}
Yes, there is an important difference. In the case of the Apple docs, the code alternative you presented:
lazy var someClosure: () -> String = {
[unowned self] in
// closure body goes here
self.delegate?.doSomething()
}
will look up the current delegate on self when the closure runs.
In the Apple example version:
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
delegate?.doSomething()
}
the weak delegate var in the capture list is copying the delegate pointer on self that exists at the time of closure declaration, not execution. So if the value of self.delegate changes after the closure is declared and is different at the time the closure runs, the Apple version of the closure will have a nil delegate (assumedly since the reference to the old delegate was weak) and do nothing.
So as a general rule, copying values or references in capture lists ([someIdentifier = someProperty]) is how to use the values or references as they exist at the moment the closure is defined. Whereas declaring weak or unowned self in the capture list ([weak self]) and then accessing properties on that weak reference ({ self?.someProperty }) will get the values of the properties as they exist when the closure is executed.
One of the problems that [unowned objectOne = self.objectOne] might cause is with lazy var UIViews and racing conditions: if you aren't careful and the lazy init gets called from different threads, two instances might end up being created. Furthermore, if your superview.addSubview(objectOne) call is in the lazy init, both instances will be added to the superview, and objectOne will point to one of the two instances.

Resources