Repository: NativeScript/NativeScript
File: packages/core/ui/frame/index.ios.ts (TypeScript)

Code before:
	private _owner: WeakRef<Frame>;

	public static initWithOwner(owner: WeakRef<Frame>): UINavigationControllerImpl {
		const controller = <UINavigationControllerImpl>UINavigationControllerImpl.new();
		controller._owner = owner;

		return controller;
	}

	get owner(): Frame {
		return this._owner.get?.();
	}

	@profile
	public viewWillAppear(animated: boolean): void {
		super.viewWillAppear(animated);
		const owner = this._owner.get?.();
		if (owner && !owner.isLoaded && !owner.parent) {
			owner.callLoaded();
		}
	}

	@profile
	public viewDidDisappear(animated: boolean): void {
		super.viewDidDisappear(animated);
		const owner = this._owner.get?.();
		if (owner && owner.isLoaded && !owner.parent && !this.presentedViewController) {
			owner.callUnloaded();
			owner._tearDownUI(true);
		}
	}

	private animateWithDuration(navigationTransition: NavigationTransition, nativeTransition: UIViewAnimationTransition, transitionType: string, baseCallback: Function): void {
		const duration = navigationTransition.duration ? navigationTransition.duration / 1000 : _defaultTransitionDuration;
		const curve = _getNativeCurve(navigationTransition);

		const transitionTraced = Trace.isCategorySet(Trace.categories.Transition);
		let transitionDelegate: TransitionDelegate;
		if (transitionTraced) {
			const id = _getTransitionId(nativeTransition, transitionType);
			transitionDelegate = TransitionDelegate.initWithOwnerId(id);
		}

		UIView.animateWithDurationAnimations(duration, () => {
			if (transitionTraced) {
				UIView.setAnimationDelegate(transitionDelegate);
			}

			UIView.setAnimationWillStartSelector('animationWillStart');
			UIView.setAnimationDidStopSelector('animationDidStop');
			UIView.setAnimationCurve(curve);

Review comment (bug):
@edusperoni would you mind adding the optional chaining after the _owner? as well? - may sound odd but I have seen cases (especially on destroy where the owner weakref itself has already been cleaned up. We just patched a similar case where a crash was observed exactly on that case here:
https://github.com/NativeScript/NativeScript/commit/a5fd53b0168ab90d66d056973592ea64d821e016

So like this to be totally safe:

```
this._owner?.get?.();
```

Code after:
	private _owner: WeakRef<Frame>;

	public static initWithOwner(owner: WeakRef<Frame>): UINavigationControllerImpl {
		const controller = <UINavigationControllerImpl>UINavigationControllerImpl.new();
		controller._owner = owner;

		return controller;
	}

	get owner(): Frame {
		return this._owner.get?.();
	}

	@profile
	public viewWillAppear(animated: boolean): void {
		super.viewWillAppear(animated);
		const owner = this._owner.get?.();
		if (owner && !owner.isLoaded && !owner.parent) {
			owner.callLoaded();
		}
	}

	@profile
	public viewDidDisappear(animated: boolean): void {
		super.viewDidDisappear(animated);
		const owner = this._owner?.get?.();
		if (owner && owner.isLoaded && !owner.parent && !this.presentedViewController) {
			owner.callUnloaded();
			owner._tearDownUI(true);
		}
	}

	private animateWithDuration(navigationTransition: NavigationTransition, nativeTransition: UIViewAnimationTransition, transitionType: string, baseCallback: Function): void {
		const duration = navigationTransition.duration ? navigationTransition.duration / 1000 : _defaultTransitionDuration;
		const curve = _getNativeCurve(navigationTransition);

		const transitionTraced = Trace.isCategorySet(Trace.categories.Transition);
		let transitionDelegate: TransitionDelegate;
		if (transitionTraced) {
			const id = _getTransitionId(nativeTransition, transitionType);
			transitionDelegate = TransitionDelegate.initWithOwnerId(id);
		}

		UIView.animateWithDurationAnimations(duration, () => {
			if (transitionTraced) {
				UIView.setAnimationDelegate(transitionDelegate);
			}

			UIView.setAnimationWillStartSelector('animationWillStart');
			UIView.setAnimationDidStopSelector('animationDidStop');
			UIView.setAnimationCurve(curve);