Как сохранить текстовое поле в основных данных с помощью swiftui - PullRequest
0 голосов
/ 06 января 2020

Я не могу выполнить задачу, чтобы сохранить значение с базовыми данными при вводе в TextField и снова отображаться при входе в представление. Возможно ли это?

Мне нужно хранить name и surname. Для этого я создал ProfileData модель данных, но не могу найти соответствующую информацию. о том, как заставить это работать должным образом.

Пожалуйста, найдите ниже код:

import SwiftUI
import CoreData

struct ProfileView: View {
    @State private var name: String = ""
    @State private var surname: String = ""
    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(
        entity: ProfileData.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \ProfileData.name, ascending: true),
            NSSortDescriptor(keyPath: \ProfileData.surname, ascending: true),

        ]
    ) var profile: FetchedResults<ProfileData>
    @EnvironmentObject var profile1: ProfileData

    var body: some View {
        VStack {
            HStack {
                VStack {
                    HStack {
                        Text("Meno:")
                            .font(.headline)
                            .padding()
                        TextField("", text: $name, onCommit: {
                        self.profile1.name = self.name
                        try? self.managedObjectContext.save()})
                    .onAppear {
                        self.name = self.profile.name != nil ? "\(self.profile.name!)" : "Zadajte meno" //here I get error Value of type 'FetchedResults<ProfileData>' has no member 'name'
                    }
                    .onDisappear {
                        self.profile1.name = self.name
                        try? self.managedObjectContext.save()
                    }
                        }   .padding(.leading, 37)
                    }
                    HStack {
                        Text("Priezvisko:")
                            .font(.headline)
                            .padding()
                        TextField("Zadajte priezvisko", text: $surname)
                    }
                }
            }
        }
        .navigationBarTitle(Text("Profil"))
    }
}

Вот мои ProfileData + CoreClassData.swift:

import Foundation
import CoreData

@objc(ProfileData)
public class ProfileData: NSManagedObject {

}

А вот мои ProfileData + CoreDataProperties.swifft

//
//  ProfileData+CoreDataProperties.swift
//  UcmMap
//
//  Created by Jakub Adamec on 06/01/2020.
//  Copyright © 2020 Jakub Adamec. All rights reserved.
//
//

import Foundation
import CoreData


extension ProfileData {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<ProfileData> {
        return NSFetchRequest<ProfileData>(entityName: "ProfileData")
    }

    @NSManaged public var name: String?
    @NSManaged public var surname: String?

}

1 Ответ

1 голос
/ 07 января 2020

Вот полный код:

import SwiftUI
import CoreData

@objc(ProfileData)
public class ProfileData: NSManagedObject, Identifiable {
    public var id = UUID()
}


extension ProfileData {


    @NSManaged public var name: String?
    public var wrappedName: String{
        get{name ?? "NoName"}
        set{name = newValue}
    }
    @NSManaged public var surname: String?
    public var wrappedSurname: String{
        get{surname ?? "NoSurname"}
        set{surname = newValue}
    }
}

struct ProfileView: View {
    @State private var name: String = ""
    @State private var surname: String = ""
    @Environment(\.managedObjectContext) var moc: NSManagedObjectContext // it will need you to add new examples of youre entities and save all changes
    @FetchRequest(
        entity: ProfileData.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \ProfileData.name, ascending: true),
            NSSortDescriptor(keyPath: \ProfileData.surname, ascending: true),

        ]
    ) var profileList: FetchedResults<ProfileData>
    //fetchRequest is a list of all objects off type ProfileData - saved and unsaved

    var body: some View {
        NavigationView{

            List{
                ForEach(profileList){profile in
                    NavigationLink(destination: profileUpdateView(profile: profile)){
                        Text("\(profile.wrappedName) \(profile.wrappedSurname) ")
                    }
                }
                HStack{
                    Image(systemName: "plus.circle.fill")
                        .foregroundColor(.green)
                        .imageScale(.large)
                    Button("add a new profile"){
                        let newProfile = ProfileData(context: self.moc)
                        newProfile.wrappedName = "Name"
                        newProfile.wrappedSurname = "Surname"
                        }

                }
             }

                .navigationBarTitle(Text("Profile"))
                .navigationBarItems(trailing: Button("save"){
                if self.moc.hasChanges{
                    do{try self.moc.save()}
                    catch{print("Cant save changes: \(error)")}
                }
            })

        }
    }
}
struct profileUpdateView: View {
    @ObservedObject var profile: ProfileData
    var body: some View{
        VStack {
              HStack {
                  Text("Meno:")
                      .font(.headline)
                      .padding()
                TextField("Zadajte meno", text: $profile.wrappedName)
              }
              HStack {
                  Text("Priezvisko:")
                      .font(.headline)
                      .padding()
                    TextField("Zadajte priezvisko", text: $profile.wrappedSurname)
              }
          }
    }
}
struct ProfileView_Previews: PreviewProvider {
    static var previews: some View {
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        let newProfile = ProfileData(context: context)
        newProfile.wrappedName = "Name"
        newProfile.wrappedSurname = "Surname"
        return ProfileView().environment(\.managedObjectContext, context)
    }
}

обратите внимание на несколько вещей:

  1. FetchRequest возвращает вам список объектов определенного вами типа. Может быть один предмет, несколько предметов или их может не быть.
  2. Если вы что-то получаете, вам нужно иметь ForEach l oop, чтобы показать результат (большую часть времени).
  3. Для этого я добавил id к вашей сущности. Он не подключен к CoreData, и каждый раз, когда FetchRequest получает новые результаты, идентификатор будет меняться, но это нормально. Единственная цель этого - дать ForEach знать, какая часть l oop связана именно с объектом. Поэтому ForEach может изменить его и показать вам обновления
  4. Не забудьте изменить свойство codegen ваших сущностей в модели данных на manual/none. Для этого откройте DataModel как, выберите вашу сущность и go для инспектора модели данных (правая часть экрана). Если вы этого не сделаете, компилятор создаст эти файлы в самой компиляции, и этот класс будет определен дважды.
  5. Если вы хотите создать новый объект вашего типа - вам нужно использовать MO C. Это единственный способ создания объектов типа NSManagedObject.
  6. в TextField, вы можете поместить объект BindableObject. Вы пытались использовать @State для этой цели, но вам это не нужно. Вы можете изменить свойство обычных объектов следующим образом: TextField("Zadajte meno", text: $profile.wrappedName) Символ $ должен обернуть это свойство @Binding. Это означает, что все изменения, сделанные внутри этого View, будут немедленно преобразованы в этот объект.
  7. Вы не можете просто поместить свойство @NSManaged, потому что большинство из них имеют необязательный тип, такой как String ?. Я сделал вычисленное свойство wrappedName, чтобы использовать его просто в Views.
  8. Я использую оболочку @ObservedObject в обновлении View. Это как @State, но для занятий. вы используете его, когда хотите мгновенно обновить View при изменении этого объекта. Это также помогает создать Binding. Ваш класс должен соответствовать требованиям протокола ObservableObject, но NSManagedObject уже соответствует требованиям, поэтому вам не нужно об этом беспокоиться. Все атрибуты @NSManaged уже @Published.
  9. Существует способ использовать Canvas, даже если вы используете CoreData. Просто получите контекст из AppDelegate, создайте любые тестовые объекты. Но помните, что сохраненные изменения добавят в ваш предварительный просмотр.
  10. И, наконец, вам нужно сохранить все изменения с помощью moc.save(). Может выдать исключение, поэтому вы должны сделать это в try-catch. Полезно проверить, действительно ли есть несохраненные изменения.

Удачи в изучении SwiftUI. Существует не так много информации об использовании SwiftUI и CoreData. Попробуйте проверить это на hackingwithswift , там много полезной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...