<!--
{
  "availability" : [
    "iOS: 17.0.0 -",
    "iPadOS: 17.0.0 -",
    "macCatalyst: 17.0.0 -",
    "macOS: 14.0.0 -",
    "tvOS: 17.0.0 -",
    "visionOS: -",
    "watchOS: 10.0.0 -"
  ],
  "documentType" : "symbol",
  "framework" : "CloudKit",
  "identifier" : "/documentation/CloudKit/CKSyncEngineDelegate-1q7g8/nextRecordZoneChangeBatch(_:syncEngine:)",
  "metadataVersion" : "0.1.0",
  "role" : "Instance Method",
  "symbol" : {
    "kind" : "Instance Method",
    "modules" : [
      "CloudKit"
    ],
    "preciseIdentifier" : "s:8CloudKit20CKSyncEngineDelegateP25nextRecordZoneChangeBatch_04syncD0AA0cD0C0ghiJ0VSgAG18SendChangesContextV_AGtYaF"
  },
  "title" : "nextRecordZoneChangeBatch(_:syncEngine:)"
}
-->

# nextRecordZoneChangeBatch(_:syncEngine:)

Asks the delegate to provide the next set of record changes to send to the server.

```
func nextRecordZoneChangeBatch(_ context: CKSyncEngine.SendChangesContext, syncEngine: CKSyncEngine) async -> CKSyncEngine.RecordZoneChangeBatch?
```

## Parameters

`context`

The reason for the sync engine’s request, and any additional options that request is using.

`syncEngine`

The sync engine asking about pending changes.

## Return Value

If there are pending record changes, a batch of those changes for the sync engine to process; otherwise, `nil` to indicate there are no changes to send.

## Discussion

In your implementation, ask the sync engine’s state for any pending record zone changes and then return a change batch containing a [`CKRecord`](/documentation/CloudKit/CKRecord) instance for each record identifier the state provides, as the following example shows:

```swift
func nextRecordZoneChangeBatch(
    _ context: CKSyncEngine.SendChangesContext,
    syncEngine: CKSyncEngine
) async -> CKSyncEngine.RecordZoneChangeBatch? {

    // Get the pending record changes and filter by the context's scope.
    let pendingChanges = syncEngine.state.pendingRecordZoneChanges
        .filter { context.options.zoneIDs.contains($0) }

    // Return a change batch that contains the corresponding materialized records.
    return await CKSyncEngine.RecordZoneChangeBatch(
        pendingChanges: pendingChanges) { self.recordFor(id: $0) }
}
```

When syncing, you must make sure to only return a batch for the scope specified in the callback.
You can do this by checking the [`scope`](/documentation/CloudKit/CKSyncEngine-5sie5/SendChangesOptions/scope-swift.property) property in [`options`](/documentation/CloudKit/CKSyncEngine-5sie5/SendChangesContext/options).
If you do not do this, you may encounter a [`invalidArguments`](/documentation/CloudKit/CKError/invalidArguments) error.

For both scheduled and manual send operations, the sync engine calls this method repeatedly until your app has no more changes and returns `nil`.

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)