#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
, константа будет равна, например, тексту этого текстового поля.