I am trying to get a subview's bound size in viewDidLoad: (the canvas.bounds)
Initially I did not use the DispatchQueue.main.async wrapper, and the size is not returned correctly. So by experiment, I wrapped the statement in main thread queue. Then it worked.
I know there is a guideline saying that "UI related operation needs to be placed in main thread". But how does this translates into actual coding rule of thumb:
If I am changing a UI property, e.g. change the bounds size, do I need to wrap it inside the main thread queue? (likely yes I guess)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// stack views
view.addSubview(photoView)
view.addSubview(canvas)
DispatchQueue.main.async {
self.canvas.startPoint = CGPoint.zero
self.canvas.endPoint = CGPoint(x: self.canvas.bounds.width / 2.0, y: self.canvas.bounds.height)
self.canvas.setNeedsDisplay()
}
Actually this leads to another question I want to ask naturally: having to wrap code in dispatch main looks “unclean”. If u have to wrap it , doesn’t it mean ‘viewDidLoad’ is not the correct life cycle to use? There should be a more appropriate life cycle that doesn’t require dispatch main wrapper?
Your issue is that viewDidLoad is not the correct place to get the size of anything. It's too soon.
Using DispatchQueue.main.async simply delays that code just enough that the size has been updated (maybe).
The proper solution is to get the size in the proper place. Use either viewDidAppear or viewDidLayoutSubviews.