Je ne suis pas sûr de ce que je fais de mal ici, mais quand je sauve la première fois dans coredata, cela fonctionne très bien. Quand j'essaye d'écraser ça, ça ne marche pas.
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")
*/
Load Login Data Func la fonction qui appelle les données 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
}
}
Étant donné que batchupdate est plus utile dans de plus grandes quantités de données, je pense que cette approche est plus subtile.
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)
}
}
}
J'ai essayé de traduire un peu votre situation si je ne me trompe pas, mais je ne l'ai pas testée.
fetchRequest.predicate
définit essentiellement le filtre sur l'attribut userName
de l'entité LoginData
, avec le nom (utilisateur) que vous entrez lors de l'appel de la fonction. En supposant que, dans cet exemple, vous n’ayez qu’un seul username
portant le même nom. Ensuite, il fait un fetchrequest
avec le filtre donné, vous pouvez donc changer sa valeur avec setValue
avec le accesToken
que vous entrez également lorsque vous appelez la fonction. Le code après: if fetchResults.count != 0
, ne s’exécute que lorsque username
existe.
Swift> = 2 la méthode retourne maintenant un non-optionnel et lève une erreur dans le cas d'erreur, qui doit être gérée avec 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)")
}
Mis à jour pour Swift 4 & XCode 9.2
Pour répondre à ta question...
Comment mettre à jour une entrée CoreData déjà enregistrée dans Swift?
Vous devez d’abord obtenir une référence à vos AppDelegate
et viewContext
. Vous devez ensuite configurer un NSFetchRequest
pour l'entité que vous souhaitez mettre à jour, dans mon exemple, ce serait "Alerte". Vous configurez ensuite votre extraction pour trouver le résultat que vous recherchez. Dans l'exemple, mon résultat a trouvé des alertes par date de création et type d'alerte.
Lire plus en détail comment interroger en utilisant un prédicat. Exemple de débordement de pile & Documentation Apple
Ensuite, je context.fetch(fetchRequest)
, je règle les résultats sur la valeur que je voulais mettre à jour et je traitais les erreurs dans un catch try. Enfin je 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)")
}
Vous créez plusieurs nouveaux objets LoginData
, mais votre méthode loadLoginData
renvoie toujours le même objet, le premier des résultats de la requête d'extraction.
Vous voulez continuer à mettre à jour le même objet, vous devez donc changer votre méthode saveLoginDetails
.
Au lieu de créer un nouvel objet (comme le fait insertNewObjectForEntityName
), utilisez la méthode loadLoginDetails
pour obtenir votre existant et modifiez la propriété à cet endroit.
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")}
bonne chance
Cela a fonctionné pour moi, vous devriez essayer ceci:
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
}
Cela a fonctionné pour moi, vous devriez essayer ceci:
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)
}
Cela a fonctionné pour moi. D'abord, je définis le filtre par l'attribut donné "taskName" avec fetchRequest.predicate. Ensuite, je récupère les données déjà enregistrées et définit la valeur pour "status" afin de mettre à jour cet objet.
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)")
}
}
Il existe une nouvelle fonctionnalité appelée Mises à jour par lots.
Je pense que cet article va vous aider:
http://www.bignerdranch.com/blog/new-in-core-data-and-ios-8-batch-updating/
En gros, vous utilisez le NSBatchUpdateRequest
au lieu de NSFetchRequest
, filtrez les résultats avec NSPredicate
, modifiez la valeur des résultats et enregistrez les données.
Un autre tutoriel à Swift:
http://code.tutsplus.com/tutorials/ios-8-core-data-and-batch-updates--cms-22164
Étape: 1 - créez un nouveau projet et sélectionnez "Utiliser les données de base", passez par: " https://medium.com/@ankurvekariya/core-data-crud-with-Swift-4-2-for-beginners-40efe4e7d1cc "
Étape: 2 - dans 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")
}
}
}
Étape: 3 - à l'intérieur de 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
}
}
Étape: 4 - À l'intérieur de 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)")
}
}
}