0

I have been trying to debug this for several days now but I can't seem to understand how it happens. I might be missing some information on how child view controllers are called.

I have a map that opens a child view controller on longpress. This works most of the time. Sometimes though, the app crashes. The console tells me:

Fatal error: Attempted to read an unowned reference but object 0x283f3cf80 was already deallocated

Note that this does not happen most of the time. It is rare and sometimes I need to trigger the long-press many times until it comes up. This is why I cannot use breakpoints. To help me debug, I have added many prints starting from "CHECK 1" to "CHECK 16". These print in the correct order when everything works well. When it breaks, it breaks between "CHECK 14" and "CHECK 15".

I use this code to call my ChildVC:

let slideVC = TripOverviewVC(customer: myCustomer, route: myRoute, panelController: panelController!, annotationManager: annotationManager!, mapview: mapView!)
slideVC.view.roundCorners([.topLeft, .topRight], radius: 22)
slideVC.view.layer.zPosition = 15
print("CHECK 8")
add(slideVC)
print("CHECK 13")

let height = view.frame.height
let width = view.frame.width
slideVC.view.frame = CGRectMake(0, self.view.frame.maxY, width, height)
print("CHECK 14")

And this is my add(_ child) function:

func add(_ child: UIViewController) {
    addChild(child)
    print("CHECK 9")
    view.addSubview(child.view)
    print("CHECK 11")
    child.didMove(toParent: self)
    print("CHECK 12")
}

On my child VC, the viewWillAppear prints "CHECK 10" which is called correctly. However, after the child has been added using my add function, I guess that viewDidAppear should be called. But it never does. This is my viewDidAppear:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    print("CHECK 15")
    UIView.animate(withDuration: 0.3) { [weak self] in
        let frame = self?.view.frame
        let yComponent = UIScreen.main.bounds.height - self!.view.frame.height*0.5
        self?.view.frame = CGRectMake(0, yComponent, frame!.width, frame!.height)
    }
    tmpOrigin = self.view.frame.origin
    print("CHECK 16")
}

This means that something breaks between adding the child as a subview, and before it is displayed on the screen, which is exactly what I can see on my app. What I don't understand is: What is being called between the two steps? Have I misunderstood the view lifecycle?

HangarRash
  • 7,314
  • 5
  • 5
  • 32
Jan L
  • 233
  • 1
  • 10
  • Show the `viewWillAppear` method. Show the symbolicated stack trace from the crash. Show the complete "long press" handler method. – HangarRash Jan 31 '23 at 16:22
  • Try to provide a [mre]. Quick testing - stripping your code down to a minimum - and I can't reproduce the issue. – DonMag Jan 31 '23 at 16:33

1 Answers1

-1

Here the force unwrapping is the problem which may lead to crash when the self is released before the execution of the animation which is delayed by 3 sec

let yComponent = UIScreen.main.bounds.height - self!.view.frame.height*0.5 
self?.view.frame = CGRectMake(0, yComponent, frame!.width, frame!.height)

Instead it can be updated as

    UIView.animate(withDuration: 0.3) { [weak self] in 
    guard let this = self else { return }
        let frame = this.view.frame
        let yComponent = UIScreen.main.bounds.height - this.view.frame.height *0.5
        this.view.frame = CGRectMake(0, yComponent, frame.width, frame.height)
    }
vignesh
  • 994
  • 10
  • 12
  • this did not fix the error. Also, since the print "CHECK 15" right before that is never called, the issue must occur just before that. – Jan L Jan 31 '23 at 14:57
  • @JanL you may [refer](https://developer.apple.com/documentation/xcode/investigating-crashes-for-zombie-objects) to check which object is getting released. Also can you update your question that print "CHECK 15" never called, based on the question we interpret that its crashing in viewDidAppear! – vignesh Feb 01 '23 at 05:57