본문 바로가기
공부/스위프트

[스위프트] SwiftUI에서 NSSavePanel로 파일 저장하기

by 초코팅촉 2024. 6. 6.
728x90

SwiftUI에서 파일을 저장할땐 NSSavePanel을 써야 합니다.

하지만 이거는 AppKit에 있는거니까 끌어와서 써야겠죠?

(해당 예시 코드는 macOS전용이며 만약 타겟에 iOS를 추가할 시엔 iOS에는 NSSavePanel이 없기 때문에 반드시 에러가 납니다.)

 

아래는 예시 코드입니다.

import SwiftUI

struct ContentView: View {
    
    @State private var textString = ""
    
    var body: some View {
        VStack {
            TextEditor(text: $textString)
            Button("저장") {
                saveFile()
            }
        }
        
    }
    
    private func saveFile() {
        let savePanel = NSSavePanel()
        savePanel.allowedContentTypes = [.plainText]
        savePanel.canCreateDirectories = true
        savePanel.isExtensionHidden = false
        savePanel.title = "저장 위치를 선택하세요." // 타이틀바 내용
        savePanel.message = "저장할 파일의 위치를 선택하세요."  // 타이틀바 바로 밑에 안에 창의 내용
        savePanel.nameFieldStringValue = "blank"
        
        savePanel.begin { result in
            if result == .OK {
                guard let url = savePanel.url else { return }
                do {
                    try textString.write(to: url, atomically: true, encoding: .utf8)
                    
                } catch {
                    print(error.localizedDescription)
                }
            }
        }
    }
}

 

어려워보일수도 있겠지만 생각보다 쉽습니다.

 

밑의 saveFile() 메서드를 봅시다.

 

우선 savePanel이라는 이름의 NSSavePanel 객체를 하나 만들어줍니다.

그리고 그 밑으로는 그냥 savePanel에 옵션들을 만들어주는 그런겁니다.

첫번째는 저장되는 파일의 타입을 무엇으로 할지,(종류가 매우 다양합니다. 참고로 `.plainText`로 해야 .txt파일로 저장됩니다. 그냥 `.text`로 하면 아무런 확장자가 붙지 않습니다.)

두번째는 savePanel이 경로를 만들수 있는지,

세번째는 savePanel이 확장자를 안보이게 할지,

네번째는 타이틀, 다섯번째는 타이틀 밑의 메시지를 지정해주는것이며

마지막으로 디폴트 이름을 무엇으로 할지를 결정합니다.

 

33번째 줄은 설정이 완료되었으니 해당 설정들이 적용된 상태의 savePanel을 시작하고,

여기서 나오는 후행클로저의 result가 바로 설정 패널에서의 결과를 나타내는 값인데

이 친구는 NSApplication.ModalResponse 인스턴스입니다.

따라서 종류가 매우 많은데요, 현재 쓸 수 있는 결과들은 아래와 같이 있다고 합니다.

NSApplication.ModalResponse의 종류

아무튼 우리는 현재 패널이 끝나면 저장해주는 작업을 해야해서 `.OK`를 쓸겁니다.

 

해서 35번째 줄에서 savePanel의 경로값이 URL로 나오기 때문에 언래핑을 해주고 37번째줄에서 해당 경로에 기존에 textEditor에서 쓴 내용을 저장합니다.

여기서 파라미터중에 두번째에 atomically가 있는데 이거는 읽어보니까 데이터가 안전하게 저장할 수 있도록 해주기 위해 임시파일을 생성할지 말지를 결정하는것 같습니다. 정확하게 이해한건 아니라 좀더 찾아봐야할거같아요.

 

마지막으로 에러가 발생하면 에러를 catch 합니다.