[macOS] 윈도우 위치와 크기를 자동으로 저장하고 복원하기

AppKit 을 활용해 만든 macOS 용 앱 윈도우의 크기와 위치를 보존하려면 autosave 이름을 지정해 주면 된다.

방법은 매우 쉽다. 스토리보드(인터페이스 빌더)에서 윈도우(NSWindow)를 선택하고 Autosave 속성에 아무 이름을 넣어주면 된다.

NSWindow 'Autosave' Attributes

근데 동작 안된다!

이렇게 간단한 내용이면 글을 안썼을지도 모르겠다. 인터페이스 빌더의 버그인지 OS의 버그인지 잘 모르겠지만, 정상적으로 동작하지 않는 경우를 제법 겪었다. 이런 경우의 케이스와 해결법을 보자.

NSWindowController

도큐먼트(Document) 기반 앱이 아니고 NSWindowController 를 쓰는 앱이라면 아마 이 케이스가 가장 확률이 높을 것이다. 이럴 때는 인터페이스 빌더에서 지정한 이름을 지우고 대신 코드를 이용해 직접 windowFrameAutosaveName 의 이름을 정해주는 방법이 효과를 봤다. (참고로 이름을 인터페이스 빌더에서 지었던 것과는 다르게 지어야 효과가 있다는 제보가 있다)

아래 코드는 NSWindowController 하위클래스의 windowDidLoad 메소드 구현한 내용이다.
override func windowDidLoad() {
  super.windowDidLoad()
  ...
  windowFrameAutosaveName = "MyGoodAppWindowSetting"
  ...
}
최신 버전의 Xcode 라면 앱 프로젝트를 생성하면 윈도우 컨트롤러 기반의 스토리보드를 생성해주니 아마도 이 방법이 대중적(?)일 듯 하다.

Document App

도큐먼트 기반 멀티윈도우를 지원하는 앱이라면 cacade 에 대한 설정이 추가로 들어가야 제대로 동작하는 경우가 있다. 아래 코드는 위의 예제와 동일하게 NSWindowController 의 하위클래스 코드인데 한 줄이 추가되었다.
override func windowDidLoad() {
  super.windowDidLoad()
  ...
  shouldCascadeWindows = false
  windowFrameAutosaveName = "MyGoodAppWindowSetting"
  ...
}

NSSplitView

혹시 윈도우에 붙어있는 뷰(View) 중 스플릿뷰(NSSplitView)가 있다면 이 녀석의 Autosave 이름을 지정해 주는 것도 시험해 보자. 아래 코드는 NSSplitViewController의 하위클래스에서 구현된 내용이다.
override func viewDidLoad() {
  super.viewDidLoad()
  ...  
  splitView.autosaveName = "MyGoodAppSplitView"
  ...
}
NSSplitViewController 는 splitView 프로퍼티를 통해 NSSplitView 인스턴스에 접근할 수 있어서 위 처럼 썼는데, 직접 NSSplitView 를 박아서 쓰는 형태라면 해당 인스턴스의 autosaveName 에다가 이름을 지어줘도 된다.

이 외에도 스플릿뷰와 비슷하게 사용자가 크기를 조절할 수 있게 만든 뷰 컴포넌트에는 Autosave 이름이 있을 걸로 추측되니 문제가 있다면 찾아보자.

댓글

이 블로그의 인기 게시물

소수점 제거 함수 삼총사 ceil(), floor(), round()

버전(Version)을 제대로 이해하기