Как вы обновляете запись CoreData, которая уже была сохранена в Swift?
Я не уверен, что я делаю неправильно здесь, но когда я впервые сохраняю в coredata, он работает отлично. Когда я пытаюсь перезаписать это, это не так.
func testStuff() {
var token = loadLoginData()
println("Token \(token)")
saveLoginData("New Token")
var newToken = loadLoginData()
println("Token \(newToken)")
}
func saveLoginData(accessToken: String) {
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context: NSManagedObjectContext = appDel.managedObjectContext!
// save data to core data
var loginData = NSEntityDescription.insertNewObjectForEntityForName("LoginData", inManagedObjectContext: context) as NSManagedObject
loginData.setValue(accessToken, forKey: "accessToken")
context.save(nil)
println("Done saving user")
}
/* Output
Token Optional("12345")
Done saving user
Token Optional("12345")
*/
Загрузить данные входа Func
функция, которая вызывает данные saveLogin
func loadLoginData() -> String? {
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context: NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "LoginData")
request.returnsObjectsAsFaults = false
var results: NSArray = context.executeFetchRequest(request, error: nil)!
if (results.count > 0) {
var userData: NSManagedObject = results[0] as NSManagedObject
var accessToken: String = userData.valueForKey("accessToken") as String
return accessToken.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
} else {
println("0 results returned, potential error")
return nil
}
}
Ответы
Ответ 1
Поскольку batchupdate более полезен в больших кусках данных, я думаю, что это более тонкий подход.
func saveLoginData(accessToken: String, userName: String) {
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context: NSManagedObjectContext = appDel.managedObjectContext!
var fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "LoginData")
fetchRequest.predicate = NSPredicate(format: "userName = %@", userName)
if let fetchResults = appDel.managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [NSManagedObject] {
if fetchResults.count != 0{
var managedObject = fetchResults[0]
managedObject.setValue(accessToken, forKey: "accessToken")
context.save(nil)
}
}
}
Я попытался немного перевести его в вашу ситуацию, если я не ошибаюсь, но не проверял его.
fetchRequest.predicate
основном устанавливает фильтр по атрибуту userName
из сущности LoginData
, с именем (пользователем), которое вы вводите при вызове функции. Предполагая, что в этом примере у вас есть только одно username
с тем же именем. Затем он выполняет fetchrequest
с заданным фильтром, поэтому вы можете изменить его значение с помощью setValue
с помощью accesToken
вы также вводите при вызове функции. Код после: if fetchResults.count != 0
, выполняется только if fetchResults.count != 0
имени username
.
Ответ 2
Обновлено для Swift 4 & XCode 9.2
Чтобы ответить на ваш вопрос...
Как вы обновляете запись CoreData, которая уже была сохранена в Swift?
Сначала вам нужно получить ссылку на ваш AppDelegate
и viewContext
. Затем вам нужно настроить NSFetchRequest
для NSFetchRequest
вы хотите обновить, в моем примере, который будет "Alert". Затем вы настраиваете свою выборку, чтобы найти результат, который вы ищете. В этом примере мой результат обнаружил оповещения по дате создания и типу предупреждения.
Чтобы узнать, как запросить использование предиката. Пример и документация Apple
Затем я context.fetch(fetchRequest)
, устанавливаю результаты в значение, которое я хотел обновить, и имел дело с ошибками в try catch. Наконец, я context.save()
.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Alert")
fetchRequest.predicate = NSPredicate(format: "creationDate = %@ AND alertType = %&",
argumentArray: [creationDate, alertType])
do {
let results = try context.fetch(fetchRequest) as? [NSManagedObject]
if results?.count != 0 { // Atleast one was returned
// In my case, I only updated the first item in results
results[0].setValue(yourValueToBeSet, forKey: "yourCoreDataAttribute")
}
} catch {
print("Fetch Failed: \(error)")
}
do {
try context.save()
}
catch {
print("Saving Core Data Failed: \(error)")
}
Ответ 3
Swift> = 2 теперь метод возвращает необязательный параметр и выдает ошибку в случае ошибки, который должен обрабатываться с помощью try-catch:
let context = self.fetchedResultsController.managedObjectContext
let entity = self.fetchedResultsController.fetchRequest.entity!
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:entity.name!)
fetchRequest.predicate = NSPredicate(format: "notificationId = 13")
do {
let list = try context.executeFetchRequest(fetchRequest) as? [NSManagedObject]
if list!.count == 0 // Check notificationId available then not save
{
let newManagedObject = NSEntityDescription.insertNewObjectForEntityForName(entity.name!, inManagedObjectContext: context)
newManagedObject.setValue("This is first message13", forKey: "message")
newManagedObject.setValue(1, forKey: "appId")
newManagedObject.setValue(13, forKey: "notificationId")
newManagedObject.setValue("First one", forKey: "tital")
}
// success ...
} catch let error as NSError {
// failure
print("Fetch failed: \(error.localizedDescription)")
}
Ответ 4
Вы создаете несколько новых объектов LoginData
, но ваш метод loadLoginData
всегда возвращает тот же объект, первый из результатов запроса выборки.
Вы хотите продолжать обновление одного и того же объекта, поэтому вам нужно изменить свой метод saveLoginDetails
.
Вместо создания нового объекта (который является тем, что insertNewObjectForEntityName
), используйте метод loadLoginDetails
, чтобы получить свой существующий, и измените там свойство.
Ответ 5
var context:NSManagedObjectContext = appDel.managedObjectContext!
var en = NSEntityDescription.entityForName("ENTITIES_NAME", inManagedObjectContext: context)
let batchUpdateRequest = NSBatchUpdateRequest(entity: en!)
batchUpdateRequest.resultType = NSBatchUpdateRequestResultType.UpdatedObjectIDsResultType
batchUpdateRequest.propertiesToUpdate = ["OBJECT_KEY": "NEWVALUE"]
var batchUpdateRequestError: NSError?
context.executeRequest(batchUpdateRequest, error:&batchUpdateRequestError)
if let error = batchUpdateRequestError {println("error")}
удача
Ответ 6
Это сработало для меня, вы должны попробовать это:
let managedContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Students", in: managedContext)
let request = NSFetchRequest<NSFetchRequestResult>()
request.entity = entity
let predicate = NSPredicate(format: "(name = %@)", txtName.text!)
request.predicate = predicate
do {
var results =
try managedContext.fetch(request)
let objectUpdate = results[0] as! NSManagedObject
objectUpdate.setValue(txtName.text!, forKey: "name")
objectUpdate.setValue(txtPhone.text!, forKey: "phone")
objectUpdate.setValue(txt_Address.text!, forKey: "address")
do {
try managedContext.save()
txtName.text = ""
txtPhone.text = ""
txt_Address.text = ""
labelStatus.text = "Updated"
}catch let error as NSError {
labelStatus.text = error.localizedFailureReason
}
}
catch let error as NSError {
labelStatus.text = error.localizedFailureReason
}
Ответ 7
Появилась новая функция, называемая пакетными обновлениями.
Я думаю, эта статья поможет вам:
http://www.bignerdranch.com/blog/new-in-core-data-and-ios-8-batch-updating/
В основном вы используете NSBatchUpdateRequest
вместо NSFetchRequest
, фильтруйте результаты с помощью NSPredicate
, измените значение в результатах и сохраните данные.
Еще один учебник в быстрой версии:
http://code.tutsplus.com/tutorials/ios-8-core-data-and-batch-updates--cms-22164
Ответ 8
Это сработало для меня, вы должны попробовать:
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return}
let managedContext = appDelegate.persistentContainer.viewContext
// if object nil is checked if new entity will be created or created one will be updated
if object == nil {
// create new entity:
let entityObj = NSEntityDescription.entity(forEntityName: "EntityName", in: managedContext)!
let entity = NSManagedObject(entity: entityObj, insertInto: managedContext)
entity("new value", forKeyPath: "entityValue")
do {
try managedContext.save()
entities.append(entity)
self.navigationController?.popViewController(animated: true)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
else {
// the created entity will be updated selected object is entity -> came from previous view controller:
self.entity?.setValue("updated value", forKey: "entityValue")
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
self.navigationController?.popViewController(animated: true)
}
Ответ 9
Шаг: 1 - создайте новый проект и выберите "Использовать базовые данные"
пройти: "https://medium.com/@ankurvekariya/core-data-crud-with-swift-4-2-for-beginners-40efe4e7d1cc"
Шаг: 2 - Inside ViewController (userList)
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDelegate , UITableViewDataSource {
var arrUser = Array<Any>()
@IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "User List"
self.tableView.separatorStyle = .none
self.retrieveData(Delete: false, indexpath: 0)
let logoutBarButtonItem = UIBarButtonItem(image: UIImage(named: "addImage"), style: .done, target: self, action: #selector(addNewUser))
self.navigationItem.rightBarButtonItem = logoutBarButtonItem
}
override func viewDidAppear(_ animated: Bool)
{
super.viewDidDisappear(animated)
self.retrieveData(Delete: false, indexpath: 0)
}
@objc func addNewUser(){
let userVC = self.storyboard?.instantiateViewController(withIdentifier: "AddUser_VC") as! AddUser_VC
self.navigationController?.pushViewController(userVC, animated: true)
}
//MARK: - TableView DataSource Delegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrUser.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell") as! UserCell
cell.selectionStyle = .none
let dictData = self.arrUser[indexPath.row] as? NSManagedObject
cell.lblName.text = dictData?.value(forKey: "name") as? String ?? ""
cell.lblPost.text = dictData?.value(forKey: "post") as? String ?? ""
cell.lblEmail.text = dictData?.value(forKey: "email") as? String ?? ""
cell.lblPhone.text = String(dictData?.value(forKey: "phone") as? Int ?? 0)
cell.imageData?.image = UIImage(data: dictData?.value(forKey: "image") as? Data ?? Data())
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 140
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let dictData = self.arrUser[indexPath.row] as? NSManagedObject
let AddUserVC = self.storyboard?.instantiateViewController(withIdentifier: "AddUser_VC") as! AddUser_VC
AddUserVC.isEdit = true
AddUserVC.dictObj = dictData
self.navigationController?.pushViewController(AddUserVC, animated: true)
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
//self.deleteData(indexpath: indexPath.row)
self.retrieveData(Delete: true, indexpath: indexPath.row)
}
}
//MARK: - retrieveData
func retrieveData(Delete:Bool , indexpath:Int) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UserTable")
if (Delete == true)
{
do
{
let test = try managedContext.fetch(fetchRequest)
let objectToDelete = test[indexpath] as! NSManagedObject
managedContext.delete(objectToDelete)
do{
try managedContext.save()
self.retrieveData(Delete: false, indexpath: 0)
}
catch
{
print(error)
}
}
catch
{
print(error)
}
}
do {
self.arrUser = try managedContext.fetch(fetchRequest)
self.tableView.reloadData()
print(self.arrUser)
} catch {
print("Failed")
}
}
}
Шаг 3 - Внутри UserCell
import UIKit
class UserCell: UITableViewCell {
@IBOutlet var lblName: UILabel!
@IBOutlet var lblEmail: UILabel!
@IBOutlet var lblPost: UILabel!
@IBOutlet var lblPhone: UILabel!
@IBOutlet var imageData: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
self.imageData.layer.cornerRadius = self.imageData.frame.height / 2
self.imageData.layer.borderWidth = 1.0
self.imageData.layer.borderColor = UIColor.lightGray.cgColor
self.imageData.layer.masksToBounds = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Шаг 4 - Внутри AddUserVC
import UIKit
import CoreData
class AddUser_VC: UIViewController ,UIImagePickerControllerDelegate ,UINavigationControllerDelegate {
var dictObj: NSManagedObject!
var isEdit:Bool = false
@IBOutlet var imageData: UIImageView!
@IBOutlet var txtName: UITextField!
@IBOutlet var txtEmail: UITextField!
@IBOutlet var txtPost: UITextField!
@IBOutlet var txtPhone: UITextField!
@IBOutlet var btnAddUser: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.imageData.layer.cornerRadius = self.imageData.frame.height / 2
self.imageData.layer.borderWidth = 1.0
self.imageData.layer.borderColor = UIColor.lightGray.cgColor
self.imageData.layer.masksToBounds = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
self.imageData.isUserInteractionEnabled = true
self.imageData.addGestureRecognizer(tapGestureRecognizer)
if (self.isEdit == true)
{
self.txtName.text = dictObj.value(forKey: "name") as? String ?? ""
self.txtEmail.text = dictObj.value(forKey: "email") as? String ?? ""
self.txtPost.text = dictObj.value(forKey: "post") as? String ?? ""
self.txtPhone.text = String(dictObj.value(forKey: "phone") as? Int ?? 0)
self.imageData?.image = UIImage(data: dictObj?.value(forKey: "image") as? Data ?? Data())
self.btnAddUser.setTitle("UPDATE", for: .normal)
}
}
//MARK: - btnAddUserAction Method -
@IBAction func btnAddUserAction(_ sender: Any) {
let arrData = [self.txtName,self.txtEmail,self.txtPost,self.txtPhone]
for txt in arrData
{
if (txt?.text == "")
{
let alert = UIAlertController(title: "Alert", message: "Please Enter All Fields", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
return
}
}
self.createData()
}
//MARK: - Image Tap Method -
@objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
let alert = UIAlertController(title: "Choose Image", message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: { _ in
self.openCamera()
}))
alert.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { _ in
self.openGallery()
}))
alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
func openCamera()
{
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerController.SourceType.camera
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
else
{
let alert = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
func openGallery()
{
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary){
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true
imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
self.present(imagePicker, animated: true, completion: nil)
}
else
{
let alert = UIAlertController(title: "Warning", message: "You don't have permission to access gallery.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard (info[.originalImage] as? UIImage) != nil else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
self.imageData.image = info[.originalImage] as? UIImage
picker.dismiss(animated: true, completion: nil)
}
//MARK: - createData
func createData(){
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let userEntity = NSEntityDescription.entity(forEntityName: "UserTable", in: managedContext)!
var user = NSManagedObject()
if(isEdit == true)
{
user = self.dictObj
}
else
{
user = NSManagedObject(entity: userEntity, insertInto: managedContext)
}
let image = self.imageData.image!.jpegData(compressionQuality: 0.5)as NSData?
user.setValue(self.txtName.text, forKeyPath: "name")
user.setValue(self.txtEmail.text, forKey: "email")
user.setValue(self.txtPost.text, forKey: "post")
user.setValue(Int(self.txtPhone.text!), forKey: "phone")
user.setValue(image, forKey: "image")
do {
try managedContext.save()
self.navigationController?.popViewController(animated: true)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
Ответ 10
Это сработало для меня. Сначала я установил фильтр по заданному атрибуту "имя_задачи" с fetchRequest.predicate. Затем я получаю данные, которые уже были сохранены, и устанавливаю значение "status" для обновления этого объекта.
func updateTaskStatus(status: Bool){
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
let predicate = NSPredicate(format: "(taskName = %@)", (task?.taskName)!)
fetchRequest.predicate = predicate
do {
let result = try managedContext.fetch(fetchRequest)
task = result[0] as NSManagedObject as? Task
task?.setValue(status, forKey: "status")
do {
try managedContext.save()
}catch let error as NSError {
print("\(error)")
}
}catch let error as NSError {
print("\(error)")
}
}
Ответ 11
В Swift 4 или Swift 5 вы можете использовать как ниже
func update(accessToken:String,username:String){
//1
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
//2
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "LoginData")
// 3
let predicate = NSPredicate(format: "%K == %@", "username", username)
fetchRequest.predicate = predicate
//3
do {
let rs = try managedContext.fetch(fetchRequest)
for result in rs as [NSManagedObject] {
// update
do {
var managedObject = rs[0]
managedObject.setValue(accessToken, forKey: "accessToken")
try managedContext.save()
print("update successfull")
} catch let error as NSError {
print("Could not Update. \(error), \(error.userInfo)")
}
//end update
}
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}