[SwiftUI] テキストエディタでテキストの読み書き

入力編集ができるテキストエディタを作る

    @State private var theText: String = """
    春はあけぼの。やうやう白くなりゆく山ぎは、すこしあかりて、紫だちたる
    雲のほそくたなびきたる。
    // 省略
    さらでもいと寒きに、火など急ぎおこして、炭もて渡るもいとつきづきし。
    昼になりて、ぬるくゆるびもていけば、火桶の火も白き灰がちになりてわろし。
    """
    var body: some View {
        TextEditor(text: $theText)
            .lineSpacing(10)
            .border(Color.gray)
            .padding()
    }

テキストエディタ

    @State var theText: String = ""
    
    var body: some View {
        NavigationView {
            TextEditor(text: $theText)
                .lineSpacing(10)
                .border(Color.gray)
                .padding([.leading, .bottom, .trailing])
                .navigationTitle("メモ")
        }
    }

保存・読み込みができるようにする
L ユーザが作って読み書きするファイルはDocumentsフォルダ内に保存する
  L DocumentsフォルダまでのURLはFileManager.defaultでfileManagerオブジェクトを作り、fileManager.url()で取得する
  L appendingPathComponent(fileName)で保存ファイル名を追加したURLを作り、そのURLをdocURL(fileName)の値として返す

import SwiftUI

func saveText(_ textData:String, _ fileName:String){
    guard let url = docURL(fileName) else {
        return
    }
    
    do {
        let path = url.path
        try textData.write(toFile: path, atomically: true, encoding: .utf8)
    } catch let error as NSError {
        print(error)
    }
}

func docURL(_ fileName:String) -> URL? {
    let fileManager = FileManager.default
    do {
        let docsUrl = try fileManager.url(
            for: .documentDirectory,
            in: .userDomainMask,
               appropriateFor: nil,
               create: false)
        let url = docsUrl.appendingPathComponent(fileName)
        return url
    } catch {
        return nil
    }
}

func loadText(_ fileName:String) -> String? {
    
    guard let url = docURL(fileName) else {
        return nil
    }
    
    do {
        let textData = try String(contentsOf: url, encoding: .utf8)
        return textData
    } catch {
        return nil
    }
}

struct ContentView: View {
    @FocusState var isInputActive: Bool
    @State var theText: String = ""
    
    var body: some View {
        NavigationView {
            TextEditor(text: $theText)
                .lineSpacing(10)
                .border(Color.gray)
                .padding([.leading, .bottom, .trailing])
                .navigationTitle("メモ")
                .focused($isInputActive)
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing){
                        Button("読み込む"){
                            if let data = loadText("sample.txt"){
                                theText = data
                            }
                        }
                    }
                    ToolbarItem(placement: .navigationBarTrailing){
                        Button("保存"){
                            saveText(theText, "sample.txt")
                        }
                    }
                }
        }
    }
}

### do-try-catchの例外処理

enum KeyError: Error {
    case uniqueError
    case lengthError
}

func keyMaker(_ key1:String, _ key2:String) throws -> String {
    guard key1 != key2 else {
        throw KeyError.uniqueError
    }
    guard (5...10).contains(key1.count)&&(5...10).contains(key2.count) else {
        throw KeyError.lengthError
    }
    let result = (key1 + key2).shuffled()
    return String(result)
}

func testKeyMake1(_ key1:String, _ key2:String){
    do {
        let result = try keyMaker(key1, key2)
        print(result)
    } catch {
        print("エラー")
    }
}

testKeyMake1("Swift", "1234567")
testKeyMake1("Swift", "Swift")
testKeyMake1("Swift", "UI")

func testKeyMake2(_ key1:String, _ key2:String){
    do {
        let result = try keyMaker(key1, key2)
        print(result)
    } catch KeyError.uniqueError {
        print("2つのキーが同じエラー")
    } catch KeyError.lengthError {
        print("文字数エラー")
    } catch {
        print("エラー")
    }
}
testKeyMake2("Swift", "1234567")
testKeyMake2("Swift", "Swift")
testKeyMake2("Swift", "UI")

これは半端ないわ
凄い