Enhancement: Monitors from unsafe transactions should get notified of changes #59

Closed
opened 2025-12-29 15:23:18 +01:00 by adam · 4 comments
Owner

Originally created by @tmspzz on GitHub (May 20, 2016).

Current State:

Monitors created via transaction.monitor... for transaction of type UnsafeDataTransaction do not get notified of changes until the transaction is committed.

However, they are notified if transaction.internalContext.save() is called

Proposal:

Have the option in a UnsafeDataTransaction to be notified upon context saves. Maybe in the fashion on transaction.flushesChangesImmediately = true

Originally created by @tmspzz on GitHub (May 20, 2016). Current State: Monitors created via `transaction.monitor...` for transaction of type `UnsafeDataTransaction` do not get notified of changes until the transaction is committed. However, they are notified if `transaction.internalContext.save()` is called Proposal: Have the option in a `UnsafeDataTransaction` to be notified upon context saves. Maybe in the fashion on `transaction.flushesChangesImmediately = true`
adam added the enhancement label 2025-12-29 15:23:18 +01:00
adam closed this issue 2025-12-29 15:23:18 +01:00
Author
Owner

@JohnEstropia commented on GitHub (May 20, 2016):

I can't think of a reasonable timing for an auto-flush without any trigger from some function call.
It will be too heavy if each property assignment triggers one flush.

The simplest I can think is to require a call to transaction.flush() when the changes are ready to be propagated to observers.

extension UnsafeDataTransaction {
    func flush() {
        self.internalContext.save()
    }
}

Another solution is to wrap all changes in closures:

extension UnsafeDataTransaction {
    func flush(@noescape closure: () -> Void) {
        closure()
        self.internalContext.save()
    }
}
// ...
transaction.flush {
    // ... make changes
}
@JohnEstropia commented on GitHub (May 20, 2016): I can't think of a reasonable timing for an auto-flush without any trigger from some function call. It will be too heavy if each property assignment triggers one flush. The simplest I can think is to require a call to `transaction.flush()` when the changes are ready to be propagated to observers. ``` swift extension UnsafeDataTransaction { func flush() { self.internalContext.save() } } ``` Another solution is to wrap all changes in closures: ``` swift extension UnsafeDataTransaction { func flush(@noescape closure: () -> Void) { closure() self.internalContext.save() } } // ... transaction.flush { // ... make changes } ```
Author
Owner

@tmspzz commented on GitHub (May 20, 2016):

I like the closure approach. However the scenario for that usage sometime looks like:

transaction.flushing {
 transaction.importObject...
}

I would give the option for both.

extension UnsafeDataTransaction {

    /**
     Cause the changes made in the transaction to be saved to the backing `NSMangedObjectContext`

     - Attention:
        Calling this method **will not commit the transaction**.
        Changes will not be propagated to the `DataStack`
     */

    func flush() throws {

        try self.internalContext.save()
    }

    /**
     Cause the changes made in the transaction to be saved to the backing `NSMangedObjectContext`

     - Attention:
        Calling this method **will not commit the transaction**.
        Changes will not be propagated to the `DataStack`
     */
    func flushing(@noescape closure: () throws -> Void) throws {

        try closure()
        try self.flush()
    }
}
@tmspzz commented on GitHub (May 20, 2016): I like the closure approach. However the scenario for that usage sometime looks like: ``` transaction.flushing { transaction.importObject... } ``` I would give the option for both. ``` extension UnsafeDataTransaction { /** Cause the changes made in the transaction to be saved to the backing `NSMangedObjectContext` - Attention: Calling this method **will not commit the transaction**. Changes will not be propagated to the `DataStack` */ func flush() throws { try self.internalContext.save() } /** Cause the changes made in the transaction to be saved to the backing `NSMangedObjectContext` - Attention: Calling this method **will not commit the transaction**. Changes will not be propagated to the `DataStack` */ func flushing(@noescape closure: () throws -> Void) throws { try closure() try self.flush() } } ```
Author
Owner

@tmspzz commented on GitHub (May 23, 2016):

Was thinking maybe the first case can be made prettier:

transaction.flushing { flush in
 flush.importObject...
}
func flushing(@noescape closure: (flush: UnsafeDataTransaction) throws -> Void) throws {
       try closure()
       try self.flush()
    }
@tmspzz commented on GitHub (May 23, 2016): Was thinking maybe the first case can be made prettier: ``` transaction.flushing { flush in flush.importObject... } ``` ``` func flushing(@noescape closure: (flush: UnsafeDataTransaction) throws -> Void) throws { try closure() try self.flush() } ```
Author
Owner

@JohnEstropia commented on GitHub (May 23, 2016):

In the end I stuck the name flush, I hope you won't mind:

    public func flush() throws
    public func flush(@noescape closure: () throws -> Void) throws

It matches CoreStore's SQL-ish naming (begin, commit, etc) and there's really no need to give separate names for the no-closure and the closure versions.

See: c15afcb381

@JohnEstropia commented on GitHub (May 23, 2016): In the end I stuck the name `flush`, I hope you won't mind: ``` public func flush() throws public func flush(@noescape closure: () throws -> Void) throws ``` It matches CoreStore's SQL-ish naming (begin, commit, etc) and there's really no need to give separate names for the no-closure and the closure versions. See: https://github.com/JohnEstropia/CoreStore/commit/c15afcb381cdb46d3d85c0cd0624df8e598e4a3b
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore#59