Есть ли способ обновить объект в базовой модели данных, нажав элемент кнопки панели?

#swift #core-data #uinavigationbar #crud #nsmanagedobject

#swift #core-data #uinavigationbar #crud #nsmanagedobject

Вопрос:

Моя цель здесь — обновить объект в моих основных данных, нажав кнопку готово после редактирования текста.

Кнопка готово и текстовые поля ниже:

введите описание изображения здесь

Вот некоторые из моих кодов,

 @objc func doneTapped() {

    
    do {
        try context.save()
    } catch {
        print("Error saving the new information (error)")
    }
    
    dateEditableTextF.resignFirstResponder()
    selectedEventDate = dateEditableTextF.text
    dateEditableTextF.isEnabled = false
    
    costEditableTextF.resignFirstResponder()
    selectedEventCost = costEditableTextF.text
    costEditableTextF.isEnabled = false
    
    
    gradesEditableTextF.resignFirstResponder()
    selectedEventGrade = gradesEditableTextF.text
    gradesEditableTextF.isEnabled = false
    
    navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editTapped))
    
  
}
 

Я ожидал, что когда я нажму кнопку готово во время запуска приложения после редактирования текстовых полей, информация обновится, и когда я вернусь к контроллеру представления, информация будет такой же, и моя база данных core data будет обновлена с помощью атрибута обновления для этого объекта.

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

Я просмотрел около 4 видеороликов YouTube о методах crud, и все они были разными сценариями и не совпадали с моими, поэтому я надеялся, что кто-нибудь здесь сможет помочь. Заранее спасибо.

Вот остальная часть моего контроллера представления.

     @IBOutlet weak var costEditableTextF: UITextField!
    @IBOutlet weak var dateEditableTextF: UITextField!
    @IBOutlet weak var gradesEditableTextF: UITextField!
    
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    
    
    var updateTheEvents = [Event]()
    
    var selectedEventName: String?
    var selectedEventDate: String?
    var selectedEventCost: String?
    var selectedEventGrade: String?
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        
        navigationItem.title = selectedEventName
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editTapped))
     
        
     
        
        if let dateToLoad = selectedEventDate {
            dateEditableTextF.text = selectedEventDate
        }
        
        if let costToLoad = selectedEventCost {
            costEditableTextF.text = selectedEventCost
        }
        
        if let gradesToLoad = selectedEventGrade {
            gradesEditableTextF.text = selectedEventGrade
        }

        // Do any additional setup after loading the view.
    }
    
    
   @objc func editTapped() {
    
   
    dateEditableTextF.becomeFirstResponder()
    dateEditableTextF.isEnabled = true
    costEditableTextF.isEnabled = true
    gradesEditableTextF.isEnabled = true
    navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped))
    
        
    }
 

Комментарии:

1. Эй, как ты справляешься со своим постоянным контейнером? Я предлагаю вам не делать этого в appdelegate, а создать класс, в котором вы вместо этого управляете всеми операциями. Чтобы обновить объект, вам нужно будет создать функцию, в которой вы извлекаете его, а затем обновляете. Чтобы отредактировать его в вашем контроллере представления, вам нужно будет создать там функцию, в которой вы обновляете нужные значения и передаете их в ранее созданную функцию. Кстати, мне нужно больше деталей, чтобы помочь вам

2. @Marybnq ладно, звучит неплохо, я добавлю еще немного кода.

3. Я бы настоятельно рекомендовал не использовать Core Data для этого. Это не технология для начинающих …!

4. @Мэтт, так что же мне делать? Я действительно не хочу удалять все приложение целиком, я не против расширить свой кругозор по этому вопросу.

Ответ №1:

Сначала вам нужно создать хранилище для управления вашим persistentContainer и операциями CRUD:

 class PersistenceManager {
lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "your_xcdatamodeld_name") //Here you should type the name of your xcdatamodeld file without the extension .xcdatamodeld
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error (error), (error.userInfo)")
        }
    })
    container.viewContext.automaticallyMergesChangesFromParent = true
    container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
    return container
}()
}
 

Теперь для сохранения данных вам понадобится контекст. Я настоятельно рекомендую вам использовать глобальный. У меня было несколько проблем с доступом к контексту хранилища из внешних функций (т. Е. материал не был добавлен / отредактирован). Обратите внимание, что, несмотря на то, что это отлично работает для меня, я не уверен, что глобальный контекст является лучшей практикой. Однако я пока не сталкивался с какими-либо проблемами.

Внутри вашего PersistenceManager класса перед persistentContainer поместите следующий код

 static let shared = PersistenceManager()
var managedObjectContext: NSManagedObjectContext {
    persistentContainer.viewContext
}
 

И перед классом и за его пределами поместите следующее

 let context = PersistenceManager.shared.managedObjectContext
...
class PersistenceManager { [...] }
 

Теперь вам нужно будет создать свою функцию сохранения следующим образом:

 func saveContext () {
      if context.hasChanges {
          do {
              try context.save()
          } catch {
              let nserror = error as NSError
              fatalError("Unresolved error (nserror), (nserror.userInfo)")
          }
      }
 

Это происходит внутри PersistenceManager класса.

Теперь начинается самое интересное: вам нужно будет создать функции CRUD. Все это будет находиться внутри вашего класса PersistenceManager. Я собираюсь показать вам небольшую демонстрацию о создании и редактировании объектов.

Предположим, у вас есть объект с именем «Item», и у него есть атрибуты name и price.
Чтобы сохранить каждый элемент, у вас будет функция, подобная следующей:

 func creaateNewItem(name: String, price: Int) -> Item {
        let entity = NSEntityDescription.entity(forEntityName: Item, in: context)
        let newItem = Item(entity: entity!, insertInto: context)
        
        newItem.name = name
        newItem.price = price
        
        self.saveContext()
        return newItem
    }
 

Чтобы отредактировать элемент, вам нужно будет извлечь его, а затем присвоить ему новые значения:

 func editItem(currentItem: Item, newName: String, newPrice: Int) {
    
    let currentName: String = currentItem.name! //Current name
    
    //Looking for the item to edit
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Item")
    request.predicate = NSPredicate(format: "name = %@", currentName)
    request.returnsObjectsAsFaults = false
    
    do { //Editing the item
        let editedItem = (try context.fetch(request))[0] as! Item
        
        editedItem.name = newName
        editedItem.price = newPrice
       
        self.saveContext()
       
    } catch let error {
        print("Error n ((error))")
    }
 
}
 

Как вы видите здесь, я передал некоторые параметры, которые позволят вам настраивать ваши элементы. Очевидно, что если вам нужно назначить значения по умолчанию, вы можете удалить эти параметры.

Теперь в вашем контроллере представления вы создадите объект Item array:

 my item : [Item]? 
 

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

 @objc func editMyItem(){
let newName = "Edited Item"
let newPrice = 15

PersistenceManager().editItem(currentItem: item[indexOfYourChoice], newName: newName, newPrice: newPrice)
}
 

И ваш товар будет отредактирован!
Обратите внимание, что если вы хотите, чтобы текст был взят из текстового поля newPrice , константа будет равна, например, тексту этого текстового поля.