Originally created by @markkrenek on GitHub (Jan 6, 2016).
What's the suggested pattern for editing an NSManagedObject in a cancelable view controller? View controller A displays a list of model objects. The user selects one and then view controller B is displayed for editing the object. In pure Core Data, I pass the object to B, it creates its own child MOC, and performs edits on the object in that context. If the user cancels, the MOC is allowed to be released and no changes are saved. If the user presses Save, the child MOC is saved, and recursively saves until committed to the store.
(This is the pattern I've used in the past, where I directly edit an NSManagedObject in a temporary MOC as the user makes changes. The alternative is to maintain the edited values in local vars of the view controller and then push those changes onto the NSManagedObject only when the user presses Save. I find the former to be easier when edits might have ripple effects through relationships or computed values.)
Originally created by @markkrenek on GitHub (Jan 6, 2016).
What's the suggested pattern for editing an NSManagedObject in a cancelable view controller? View controller A displays a list of model objects. The user selects one and then view controller B is displayed for editing the object. In pure Core Data, I pass the object to B, it creates its own child MOC, and performs edits on the object in that context. If the user cancels, the MOC is allowed to be released and no changes are saved. If the user presses Save, the child MOC is saved, and recursively saves until committed to the store.
(This is the pattern I've used in the past, where I directly edit an NSManagedObject in a temporary MOC as the user makes changes. The alternative is to maintain the edited values in local vars of the view controller and then push those changes onto the NSManagedObject only when the user presses Save. I find the former to be easier when edits might have ripple effects through relationships or computed values.)
adam
added the question label 2025-12-29 15:22:34 +01:00
@markkrenek This is exactly the use-case that UnsafeDataTransactions were designed for:
lettransaction:UnsafeDataTransaction=CoreStore.beginUnsafe()self.transaction=transaction// keep a strong reference in your UIViewController// Later...self.temporaryObject=self.transaction.create(Into(YourEntity))// orself.temporaryObject=self.transaction.fetch(From(YourEntity),Where(/* ... */))// ... make updatesself.temporaryObject.yourProperty=// ... // When done ...self.transaction.commit{resultin// ...}
If you want to cancel changes, just don't call commit() on the transaction.
@JohnEstropia commented on GitHub (Jan 7, 2016):
@markkrenek This is exactly the use-case that `UnsafeDataTransaction`s were designed for:
``` swift
let transaction: UnsafeDataTransaction = CoreStore.beginUnsafe()
self.transaction = transaction // keep a strong reference in your UIViewController
// Later...
self.temporaryObject = self.transaction.create(Into(YourEntity))
// or
self.temporaryObject = self.transaction.fetch(From(YourEntity), Where( /* ... */ ))
// ... make updates
self.temporaryObject.yourProperty = // ...
// When done ...
self.transaction.commit { result in
// ...
}
```
If you want to cancel changes, just don't call `commit()` on the transaction.
Thanks. I'm still wrapping my head around some of the abstraction that CoreStore is providing. I had not thought to use UnsafeDataTransaction simply because of the "Unsafe" name. It sounds like as long as I make changes to the object only from the main thread, I'll be OK.
@markkrenek commented on GitHub (Jan 7, 2016):
Thanks. I'm still wrapping my head around some of the abstraction that CoreStore is providing. I had not thought to use UnsafeDataTransaction simply because of the "Unsafe" name. It sounds like as long as I make changes to the object only from the main thread, I'll be OK.
All transactions create their own temporary MOC and UnsafeDataTransaction lets you use it from any thread/queue. It's named "unsafe" because CoreStore cannot track changes made concurrently from other transactions. If your app does not update objects in the background then it should be fine.
Just make sure that you do not interact objects fetched/created from different contexts.
For example, don't do this:
letobject=CoreStore.fetchOne(From(SomeEntity),Where(...))// fetched from the main contextletanother=self.transaction.fetchOne(From(AnotherEntity),Where(...))// fetched from temporary contextanother.myRelationship=object// BAD!
@JohnEstropia commented on GitHub (Jan 7, 2016):
All transactions create their own temporary MOC and UnsafeDataTransaction lets you use it from any thread/queue. It's named "unsafe" because CoreStore cannot track changes made concurrently from other transactions. If your app does not update objects in the background then it should be fine.
Just make sure that you do not interact objects fetched/created from different contexts.
For example, don't do this:
``` swift
let object = CoreStore.fetchOne(From(SomeEntity), Where(...)) // fetched from the main context
let another = self.transaction.fetchOne(From(AnotherEntity), Where(...)) // fetched from temporary context
another.myRelationship = object // BAD!
```
You'll need to do this:
``` swift
another.myRelationship = self.transaction.fetchExisting(object) // OK!
```
Hey @markkrenek. I hope it's alright to piggyback off your previous question!
I've a similar pattern to you with regard to having a cancelable view controller.
Let's say I reuse a view controller which can both create & edit a 'customer' details.
I'd like to know how you handle logic for creating the Customer model object on creation & if updating a previous object?
Here's what I have currently, any input much appreciated! :
@IBActionfuncupdateCustomerAction(_sender:LoadingButton){if!self.customerDetailsPanel.isValid(isDeferred:false){// Early returnreturn}self.transaction=CoreStore.beginUnsafe()guardletcustomer:Customer={ifletexistingCustomer=self.customer{returnself.transaction?.edit(existingCustomer)}else{returnself.transaction?.create(Into<Customer>())}}()else{// Report errorreturn}customer.name=customerDetailsPanel.customerNameField.textcustomer.email=customerDetailsPanel.emailField.textcustomer.notes=notesPanel.notesTextView.textcustomer.phone=customerDetailsPanel.phoneNumberField.textcustomer.otherNumber=customerDetailsPanel.otherNumberField.textsender.showLoadingView()self.transaction?.commit{[weakself]resultinifleterror=result{// Report errorprint("Error - \(error)")}else{self?.navigationController?.popViewController(animated:true)}}}
@markst commented on GitHub (Oct 25, 2018):
Hey @markkrenek. I hope it's alright to piggyback off your previous question!
I've a similar pattern to you with regard to having a cancelable view controller.
Let's say I reuse a view controller which can both create & edit a 'customer' details.
I'd like to know how you handle logic for creating the Customer model object on creation & if updating a previous object?
Here's what I have currently, any input much appreciated! :
```swift
@IBAction func updateCustomerAction(_ sender: LoadingButton) {
if !self.customerDetailsPanel.isValid(isDeferred: false) {
// Early return
return
}
self.transaction = CoreStore.beginUnsafe()
guard let customer:Customer = {
if let existingCustomer = self.customer {
return self.transaction?.edit(existingCustomer)
} else {
return self.transaction?.create(Into<Customer>())
}
}() else {
// Report error
return
}
customer.name = customerDetailsPanel.customerNameField.text
customer.email = customerDetailsPanel.emailField.text
customer.notes = notesPanel.notesTextView.text
customer.phone = customerDetailsPanel.phoneNumberField.text
customer.otherNumber = customerDetailsPanel.otherNumberField.text
sender.showLoadingView()
self.transaction?.commit { [weak self] result in
if let error = result {
// Report error
print("Error - \(error)")
} else {
self?.navigationController?.popViewController(animated: true)
}
}
}
```
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Originally created by @markkrenek on GitHub (Jan 6, 2016).
What's the suggested pattern for editing an NSManagedObject in a cancelable view controller? View controller A displays a list of model objects. The user selects one and then view controller B is displayed for editing the object. In pure Core Data, I pass the object to B, it creates its own child MOC, and performs edits on the object in that context. If the user cancels, the MOC is allowed to be released and no changes are saved. If the user presses Save, the child MOC is saved, and recursively saves until committed to the store.
(This is the pattern I've used in the past, where I directly edit an NSManagedObject in a temporary MOC as the user makes changes. The alternative is to maintain the edited values in local vars of the view controller and then push those changes onto the NSManagedObject only when the user presses Save. I find the former to be easier when edits might have ripple effects through relationships or computed values.)
@JohnEstropia commented on GitHub (Jan 7, 2016):
@markkrenek This is exactly the use-case that
UnsafeDataTransactions were designed for:If you want to cancel changes, just don't call
commit()on the transaction.@markkrenek commented on GitHub (Jan 7, 2016):
Thanks. I'm still wrapping my head around some of the abstraction that CoreStore is providing. I had not thought to use UnsafeDataTransaction simply because of the "Unsafe" name. It sounds like as long as I make changes to the object only from the main thread, I'll be OK.
@JohnEstropia commented on GitHub (Jan 7, 2016):
All transactions create their own temporary MOC and UnsafeDataTransaction lets you use it from any thread/queue. It's named "unsafe" because CoreStore cannot track changes made concurrently from other transactions. If your app does not update objects in the background then it should be fine.
Just make sure that you do not interact objects fetched/created from different contexts.
For example, don't do this:
You'll need to do this:
@markst commented on GitHub (Oct 25, 2018):
Hey @markkrenek. I hope it's alright to piggyback off your previous question!
I've a similar pattern to you with regard to having a cancelable view controller.
Let's say I reuse a view controller which can both create & edit a 'customer' details.
I'd like to know how you handle logic for creating the Customer model object on creation & if updating a previous object?
Here's what I have currently, any input much appreciated! :