iOS App Crash for optimised builds generated by Xcode above 11.3

The app crashes with Thread 1: EXCBADINSTRUCTION (code=EXCI386INVOP, subcode=0x0)
when I add the instance of the below mentioned view as subview to any VC's view.

Reason : the lblContainer gets deallocated after being assigned by a local var object .
The crash doesn't reproduce when I use a let variable to create the view and assign it to lblContainer.

Code Block
class HorizontalViewMore: UIView {
    private weak var lblContainer : UIView!
    override init(frame: CGRect) {
        super.init(frame: frame)
        createViews()
}
  
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
}
  
    func createViews() {
//it crashes only when the object is declared as var not let
        var view : UIView = UIView.init(frame: CGRect.zero)
        self.lblContainer = view;
        self.lblContainer.isUserInteractionEnabled = false
//it often crashes here with
//Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
        self.lblContainer.translatesAutoresizingMaskIntoConstraints = false;
        self.addSubview(self.lblContainer)
        self.lblContainer.backgroundColor = UIColor.clear;
        self.lblContainer.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true;
        self.lblContainer.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true;
        self.lblContainer.leftAnchor.constraint(greaterThanOrEqualTo: self.leftAnchor, constant: 8.0).isActive = true
        self.lblContainer.rightAnchor.constraint(lessThanOrEqualTo: self.rightAnchor, constant: -8.0).isActive = true
}
   deinit {
        print("MemTest : HorizontalViewMore is deinitialized")
    }
}


Also the crash happens only in the optimised builds compiled with Xcode version above 11.3.
The optimisation settings are :
Apple CLang Code Generation
Optimization Level: Fastest, Smallest [-Os]
Swift Compiler - Code Generation
Optimization Level: Optimize for speed [-O]

You can find my sample project here

Could anyone please explain this behaviour to me ?
Answered by OOPer in 648321022

it doesn't crash if I change the line 32

Thanks for testing.

Could anyone please explain this behaviour to me ?

In optimized code, local variables may be released at any time where the values will not be used any more.
Of course this applies to both var and let, but what affects this behavior is sort of implementation details and you should better not rely on some specific implementation.

In your original code shown, the local variable view (which holds a strong reference to the UIView) is never used after line 24.
Thus, if optimizer decided to release the variable there, there's no strong reference to the UIView. A weak reference to it gets nil, and bang.

In some implementations of compilers or slight changes other than var to let might generate a code which works as you expect,
but generally, you should keep strong reference to an instance explicitly while it is needed.
Can you test what may happen if you change line 32 to self.addSubview(view) ?
@OOPer it doesn't crash if I change the line 32 to
Code Block
self.addSubview(view)

Accepted Answer

it doesn't crash if I change the line 32

Thanks for testing.

Could anyone please explain this behaviour to me ?

In optimized code, local variables may be released at any time where the values will not be used any more.
Of course this applies to both var and let, but what affects this behavior is sort of implementation details and you should better not rely on some specific implementation.

In your original code shown, the local variable view (which holds a strong reference to the UIView) is never used after line 24.
Thus, if optimizer decided to release the variable there, there's no strong reference to the UIView. A weak reference to it gets nil, and bang.

In some implementations of compilers or slight changes other than var to let might generate a code which works as you expect,
but generally, you should keep strong reference to an instance explicitly while it is needed.
@OOPer Earlier as suggested by the Apple local variables are strong variables and will be live till the function scope. As per your suggestion this implementation got changed after Xcode 11.3 above?

If this has changed, Then there are many places we write code assuming local variables are live till the function scope. We have to change everywhere were we have such implementation. But I really feel this is bug introduced in above Xcode 11.3.

 local variables are strong variables 

YES.

will be live till the function scope

Unfortunately, it is not right.

this implementation got changed after Xcode 11.3 above?

NO, not after Xcode 11.3 above. It had been changing through versions. Ii is just by luck that your code had worked in pre-11.3 versions.

Then there are many places we write code assuming local variables are live till the function scope. 

Then you need to fix all of them.

I really feel this is bug introduced in above Xcode 11.3.

I do feel this is your responsibility to write a code having this compiler's behavior in mind.


You can send a bug report to Apple if you think this is a bug.

Thanks @OOPer, for such detailed information.
iOS App Crash for optimised builds generated by Xcode above 11.3
 
 
Q