Сохранить строку из TextField в UserDefaults с помощью SwiftUI

Как можно сохранить строку из TextField в UserDefaults с помощью SwiftUI?

Я видел этот учебник о том, как сохранить состояние переключателя в UserDefaults, и это выглядит многообещающим, но я не могу понять, как использовать ту же идею для хранения содержимого из TextField: https://www.youtube.com/watch?v=nV-OdfQhStM&list=PLerlU8xuZ7Fk9zRMuh7JCKy1eOtdxSBut&index=3&t=329s

Я по-прежнему хочу иметь возможность обновлять строку, вводя новый текст в TextField, но если я этого не сделаю, я хочу, чтобы строка сохранялась в представлении. Как при смене страницы, так и при полном выходе из приложения.


person oscar    schedule 21.09.2019    source источник
comment
Добро пожаловать в StackOverflow. Покажите, какие исследования вы провели, что уже пробовали, что не сработало, образцы кода и т. Д. Прочтите Как спросить и минимальный воспроизводимый пример и обновить свой вопрос.   -  person Ashley Mills    schedule 21.09.2019
comment
Посмотрите на мое решение, есть ссылка на пример YouTube stackoverflow.com/a/57982560/4067700   -  person Victor Kushnerov    schedule 22.09.2019


Ответы (2)


Для подобных вещей я предлагаю вам использовать .debounce publisher.

import SwiftUI
import Combine

class TestViewModel : ObservableObject {
    private static let userDefaultTextKey = "textKey"
    @Published var text = UserDefaults.standard.string(forKey: TestViewModel.userDefaultTextKey) ?? ""
    private var canc: AnyCancellable!

    init() {
        canc = $text.debounce(for: 0.2, scheduler: DispatchQueue.main).sink { newText in
            UserDefaults.standard.set(newText, forKey: TestViewModel.userDefaultTextKey)            
        }
    }

    deinit {
        canc.cancel()
    }
}

struct ContentView: View {
    @ObservedObject var viewModel = TestViewModel()

    var body: some View {
        TextField("Type something...", text: $viewModel.text)
    }
}

В документации издателя .debounce говорится:

Используйте этот оператор, если вы хотите дождаться паузы в доставке событий от вышестоящего издателя. Например, вызовите debounce для издателя из текстового поля, чтобы получать элементы только тогда, когда пользователь приостанавливает или прекращает печатать. Когда они снова начинают печатать, противодействие задерживает доставку события до следующей паузы.

Вы действительно не хотите сохранять текст в UserDefaults каждый раз, когда пользователь что-то вводит (т.е. для каждого символа, который он / она вводит). Вы просто хотите, чтобы текст в конечном итоге был сохранен в UserDefaults. Издатель debounce ожидает, пока пользователь перестанет печатать, в соответствии со временем, которое вы установили в инициализации debounce (в примере выше 0,2 секунды), а затем пересылает событие подписчику sink, который фактически сохраняет текст. Всегда используйте издателя debounce, когда у вас много событий (например, новый текст, введенный в текстовое поле), которые могут запускать «тяжелые» операции (что бы вы ни думали: что-то, связанное с CoreData, сетевыми вызовами и т. Д.).

person matteopuc    schedule 21.09.2019
comment
Спасибо за ваш комментарий! Я протестировал код, но у меня все еще есть проблема с удалением пользовательского ввода при перезапуске приложения. Сохранение в UserDefaults должно быть в порядке, так как входные данные для этого приложения будут происходить один раз в неделю или реже, поэтому загрузка данных не должна быть слишком большой. Мне все равно нужны лучшие решения, чем сохранение в UserDefaults, если это возможно, поскольку я новичок в кодировании в SwiftUI. - person oscar; 22.09.2019
comment
@oscar Я отредактировал свой ответ, чтобы ваши пользователи видели текст, который они ранее набирали, при запуске приложения. Это просто вопрос чтения пользователя по умолчанию, который вы ранее сохранили. - person matteopuc; 22.09.2019

Вы можете создать настраиваемую привязку, как описано здесь, и вызвать UserDefaults.standard.set, когда привязка текста установлена.

struct ContentView: View {
    @State var location: String = ""

    var body: some View {
        let binding = Binding<String>(get: {
            self.location
        }, set: {
            self.location = $0
            // Save to UserDefaults here...
        })

        return VStack {
            Text("Current location: \(location)")
            TextField("Search Location", text: binding)
        }

    }
}

Скопировано из ответа на «Изменения текстового поля в SwiftUI»

person KB-YYZ    schedule 21.09.2019
comment
Пожалуйста, не публикуйте ответы только по ссылкам. Хотя они могут быть правильными, целостность вашего ответа будет нарушена, если ссылка когда-либо изменится / закроется. Постарайтесь включить в свой ответ важные части этой ссылки. - person Ashley Mills; 21.09.2019
comment
Спасибо за ваш ответ! Теперь у меня вопрос, что писать там, где вы написали «Сохранить в UserDefaults»… Это та часть, в которой я запутался. Я хочу, чтобы входные данные из TextField оставались в представлении даже после закрытия приложения. - person oscar; 21.09.2019