---
source_url: https://www.pubnub.com/docs/chat/community-supported/ios/data-components
title: Data components for PubNub Chat Components for iOS
updated_at: 2026-05-22T11:04:03.363Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Data components for PubNub Chat Components for iOS

Data components are responsible for managing data between the [UI Components](https://www.pubnub.com/docs/chat/community-supported/ios/ui-components) and the persistence layer. They also interact with the PubNub service by sending and receiving messages and signals.

Available components include:

* [Channel Data](#channel)
* [User Data](#user)
* [Member Data](#member)
* [Message Data](#message) (with [Message Reactions data](#message-reactions))

## Overview

PubNub Chat Components for iOS utilize several layers of configurable data to drive the functionality found in the UI Components. The goal of the data layer is to provide a simple and robust foundation that can be used across any chat implementation. The two main forms of data used by the components are [managed](#managed-data) and [network](#network-data) objects.

### Managed data

PubNub Chat Components for iOS rely on [Core Data](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/index.html) - an Apple framework to manage the model layer of the application - to provide a persistent, abstracted, and reliable local state to the UI Components.

This is achieved by defining data schemas and relationships inside a [Managed Object Model](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/KeyConcepts.html#//apple_ref/doc/uid/TP40001075-CH30-SW1). There is also a pre-configured set of managed entities provided by default to support rapid prototyping.

### Network data

A drawback of using Core Data managed objects is they can only be handled on the main queue of the application. To avoid any issues or errors while using concurrency, the managed objects are able to be converted to and from network object types. The objects attempt to mirror the default managed object schema, but can be further customized to match any schema that's needed by the application.

Network objects are most commonly used when interacting with PubNub APIs, but should be used whenever the applications might use multiple threads.

### Data flow

The typical data flow through the components revolves around storing incoming data into the Core Data instance and updating that data automatically in UI Components if the data matches the UI Components population query.

![Component Data Flow](https://www.pubnub.com/assets/images/ios-components-data-flow-828a069d474136e7838e10b4118da5d9.gif)

1. The PubNub APIs and Events return network data that can be stored directly in Core Data using the appropriate DataProvider methods found inside ChatProvider.
2. The UI Components use NSFetchedResultsController to create NSPredicate against the stored (managed) data. This controller automatically updates the component's data source if the new matching data is added, updated, or removed.
3. The UI Components provide actions that can be configured to call PubNub APIs through DataProvider or update existing objects and store the result.

### Data payloads

PubNub Chat Components for iOS enforce you to use the unified JSON schemas (data models) for such common entity types as [users](#users), [channels](#channels), and [messages](#messages) when transferring data over the PubNub network. These common data payloads allow you to create cross-platform applications and ensure that such applications developed in different technologies (Swift, Kotlin, or JavaScript) communicate with one another properly, avoiding any unexpected errors.

:::tip Validate your payload
To avoid any parsing errors, validate the data payload you prepared for users, channels, and messages in an [online validator](https://www.jsonschemavalidator.net).
:::

#### Users

Follow this schema for the user data in your apps:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "User",
  "type": "object",
  "description": "User of a chat application",
  "properties": {
    "id": {
      "description": "Unique identifier for a user",
      "type": "string"
    },
    "name": {
      "description": "Name of the user that you can display in the UI",
      "type": "string"
    },
    "email": {
      "description": "User's email address",
      "type": "string"
    },
    "externalId": {
      "description": "Reference to user identifier from an external system",
      "type": "string"
    },
    "profileUrl": {
      "description": "URL to a user avatar that you can display in the UI",
      "type": "string"
    },
    "type": {
      "description": "Type of the user",
      "type": "string",
      "examples": ["default", "admin", "moderator"],
      "default": "default"
    },
    "status": {
      "description": "Status of the user",
      "type": "string",
      "examples": ["default", "deleted"]
    },
    "custom": {
      "description": "Any additional payload information",
      "type": "object",
      "properties": {
        "description": {
          "description": "Description, job title, or some other information that you can display in the UI",
          "type": "string"
        }
      }
    },
    "eTag": {
      "description": "Identifier used for cache invalidation",
      "type": "string"
    },
    "updated": {
      "description": "ISO8601 date string of when the user has been last updated",
      "type": "string"
    },
  },
  "required": ["id", "type"]
}
```

Example:

```json
{
  "id": "some-user-id",
  "name": "Jane Doe",
  "email": "jane.doe@example.com",
  "externalId": "some-external-user-id",
  "profileUrl": "https://randomuser.me/api/portraits/men/1.jpg",
  "type": "default",
  "status": "default",
  "custom": {
    "description": "Office Assistant",
  },
  "eTag": "AYGyoY3gre71eA",
  "updated": "2020-09-23T09:23:34.598494Z"
}
```

#### Channels

Follow this schema for the channel data in your apps:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Channel",
  "description": "Channel in the chat application",
  "type": "object",
  "properties": {
    "id": {
      "description": "Unique identifier for a channel",
      "type": "string"
    },
    "name": {
      "description": "Name of the channel that you can display in the UI",
      "type": "string"
    },
    "description": {
      "description": "Description of the channel that you can display in the UI",
      "type": "string"
    },
    "type": {
      "description": "Type of the channel",
      "type": "string",
      "examples": ["default", "group", "direct"],
      "default": "default"
    },
    "status": {
      "description": "Status of the channel",
      "type": "string",
      "examples": ["default", "deleted"]
    },
    "custom": {
      "description": "Any additional payload information",
      "type": "object",
      "properties": {
        "profileUrl": {
          "description": "URL to a channel avatar that you can display in the UI",
          "type": "string"
        }
      }
    },
    "eTag": {
      "description": "Identifier used for cache invalidation",
      "type": "string"
    },
    "updated": {
      "description": "ISO8601 date string of when the channel has been last updated",
      "type": "string"
    },
  },
  "required": ["id", "type"]
}
```

Example:

```json
{
  "id": "some-channel-id",
  "name": "Off-topic",
  "description": "Off-topic channel for random chatter and fun",
  "type": "default",
  "status": "default",
  "custom": {
    "profileUrl": "https://www.gravatar.com/avatar/149e60f311749f2a7c6515f7b34?s=256&d=identicon"
  },
  "eTag": "AbOx6N+6vu3zoAE",
  "updated": "2020-09-23T09:23:37.175764Z"
}
```

#### Messages

Follow this schema for the message data in your apps:

:::note Supported message types
PubNub Chat Components for iOS support only text message data types.
:::

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Message Content",
  "description": "Message content in the chat application",
  "type": "object",
  "properties": {
    "id": {
      "description": "Unique identifier for a message. Use the UUID v4 algorithm.",
      "type": "string"
    },
    "text": {
      "description": "Text of the message that you can display in the UI",
      "type": "string"
    },
    "contentType": {
      "description": "If a message contains any extra content, this field describes its type. Currently, PubNub Chat Components support only text messages.",
      "type": "string",
      "examples": ["externalUrl", "imageUrl"]
    },
    "content": {
      "description": "Extra content for the message. It can contain any feature-specific data like URLs to external images.",
      "type": "object"
    },
    "createdAt": {
      "description": "ISO8601 date string of when the message was created",
      "type": "string"
    },
    "custom": {
      "description": "Any additional payload information",
      "type": "object"
    }
  },
  "required": ["id", "text", "createdAt"]
}
```

Example:

```json
{
  "id": "6da72b98-e211-4724-aad4-e0fb9f08999f",
  "text": "Let's sync on the topic in this thread.",
  "contentType": "none",
  "content": {},
  "custom": {},
  "createdAt": "2022-05-10T14:48:00.000Z"
}
```

## Channel

A [channel](https://www.pubnub.com/docs/chat/sdks/channels/channel-types-names) is commonly viewed as a collection of associated users with a specific purpose or goal. A channel could be created for direct communication between two or more users, a group of users, or other use case-specific scenarios.

### Managed data

The default Managed Object Model inside the Chat Components defines a Core Data `NSManagedObject` named `PubNubManagedChannel`.

If a custom Managed Object Model is used, an `NSManagedObject` entity must implement the `ManagedChatChannel` protocol before it can be used by the Chat Components framework.

#### Managed channel

The `PubNubManagedChannel` entity is a CoreData managed `Channel` class used whenever a `ChatChannel` needs to be stored locally. It is defined with the following attributes:

| Name | Type | Description |
| --- | --- | --- |
| `id` | `String` | Unique identifier for the object. |
| `name` | `String?` | Name of the channel. |
| `type` | `String` | Functional type of the channel. The default value is set to `"default"`. |
| `status` | `String?` | Status of the channel. |
| `details` | `String?` | Channel details you can display alongside the name. |
| `avatarURL` | `URL?` | URL to a channel avatar that you can display in the UI. |
| `custom` | `Data` | Custom key value pairs that can be stored with the channel. |
| `lastUpdated` | `Date?` | Last time the remote object was changed. This field references the `updated` field from `ChatChannel`. |
| `eTag` | `String?` | Caching value that changes whenever the remote object changes. |
| `memberCount` | `Int` | Total number of members that are currently active on the channel. |

#### Relationships

The `PubNubManagedChannel` entity has relationships with the following entities:

| Name | Type | Description |
| --- | --- | --- |
| `members` | `Set<PubNubManagedMember>` | Entity that connects to the users of a channel. |
| `messages` | `Set<PubNubManagedMessage>` | Entity that connects to the messages of a channel. |

#### Managed channel protocol

To allow for a custom Managed Object Model, the `ManagedChatChannel` protocol is used when referring to the managed object.

The protocol requires the following properties and methods:

* pubnubChannelID Identifier used when interacting with PubNub APIs. It can be different from the primary key ID used by the managed object. 1var pubnubChannelID: String { get }
* convert() Converts the managed object to a network object with the appropriately typed custom channel data. 1func convert<Custom: ChannelCustomData>() -> ChatChannel<Custom>

##### Returns

The base network object transformed to use the specified `ChannelCustomData`.

* insertOrUpdate(channel:into:) Inserts or updates the managed object from a network object. 1@discardableResult2static func insertOrUpdate<Custom: ChannelCustomData>(3 channel: ChatChannel<Custom>,4 into context: NSManagedObjectContext5) throws -> Self

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `channel` | `ChatChannel<ChannelCustomData>` | `ChatChannel` to be updated or inserted. |
| `into` | `NSManagedObjectContext` | Core Data context where the object is inserted or updated. |

##### Returns

The managed object that was inserted or updated.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a new managed object was created or an existing object was updated.

* `patch(usingPatch:into:)`

```swift
@discardableResult
static func patch<Custom: ChannelCustomData>(
  usingPatch patcher: ChatChannel<Custom>.Patcher,
  into context: NSManagedObjectContext
) throws -> Self
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `usingPatch` | `ChatChannel<ChannelCustomData>.Patcher` | `ChatChannel.Patcher` changeset that is applied to an existing channel if one exists. |
| `into` | `NSManagedObjectContext` | Core Data context where the object is inserted or updated. |

##### Returns

The managed object that was updated.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether an existing object was updated.

* remove(channelId:from:) Removes a managed object matching the channelId parameter. 1@discardableResult2static func remove(3 channelId: String,4 from context: NSManagedObjectContext5) -> Self?

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `channelId` | `String` | Unique identifier for the channel. |
| `from` | `NSManagedObjectContext` | Core Data context where the object is removed. |

##### Returns

The managed object that was removed.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a managed object was removed.

* channelBy(channelID:) Creates NSFetchRequest that gets a channel matching the channelId parameter. 1static func channelBy(channelID: String) -> NSFetchRequest<Self>

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `channelID` | `String` | Unique identifier for the channel. |

##### Returns

`NSFetchRequest` whose predicate is set to get the channel that matches the `channelID` parameter.

### Network data

The generic `ChatChannel` class contains the [channel payload](#channels) fields and is used whenever a Swift PubNub API requires a `Space` object.

| Name | Type | Description |
| --- | --- | --- |
| `id` | `String` | Unique identifier for the object. |
| `name` | `String?` | Name of the channel. |
| `type` | `String` | Functional type of the channel. The default value is set to `"default"`. |
| `status` | `String?` | Status of the channel. |
| `details` | `String?` | Channel details you can display alongside the name. |
| `avatarURL` | `URL?` | URL to a channel avatar that you can display in the UI. This field references the `profileUrl` field from the [channel payload](#channels) specification. |
| `updated` | `Date?` | Last time the remote object was changed. |
| `eTag` | `String?` | Caching value that changes whenever the remote object changes. |
| `custom` | `ChannelCustomData` | Custom key value pairs that can be stored with the channel. |

#### Custom channel data

Implement the `ChannelCustomData` protocol to provide custom data to the generic `ChatChannel` class.

By default, all custom data is implemented as an empty object `VoidCustomData`.

The default implementation of `ChatChannel` is a typealias of the following:

```swift
public typealias PubNubChatChannel = ChatChannel<VoidCustomData>
```

#### APIs

* `patch(:)`

Patches the properties of an existing `ChatUser` from a real-time changeset.

```swift
  public func patch(
    _ patcher: ChatChannel<Custom>.Patcher
  ) -> ChatChannel<Custom>
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `user` | `ChatChannel<Custom>.Patcher` | Channel changeset that will be applied to an existing `ChatChannel`. |

##### Returns

An updated `ChatChannel` if the `Patcher` was able to perform the update, otherwise the duplicate `ChatChannel`.

### Data provider actions

`DataProvider` contains several convenience methods that streamline the ability to fetch and manage channel data. You can access `DataProvider` through `ChatProvider`.

* load() Inserts or updates a list of channels in the Core Data store batching based on the supplied batchSize. 1public func load(2 channels: [ChatChannel<ModelData.Channel>],3 batchSize: Int = 256,4 batchHandler: (([ChatChannel<ModelData.Channel>], Error?) -> Void)? = nil,5 completion: (() -> Void)? = nil6)

#### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `channels` | `[ChatChannel<ModelData.Channel>]` | Channels to store. |
| `batchSize` | `Int` | Size of each chunk of channels to store. |
| `batchHandler` | `(([ChatChannel<ModelData.Channel>], Error?) -> Void)?` | Closure called after storing each batch. |
| `completion` | `(() -> Void)?` | Closure called after storing all channels. |

* removeStoredChannel() Removes a managed channel matching the supplied channelId. 1public func removeStoredChannel(2 channelId: String,3 completion: ((Error?) -> Void)? = nil4)

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `channelId` | `String` | Unique identifier for the channel. |
| `completion` | `((Error?) -> Void)?` | Closure called after removing the channel. |

* syncRemoteChannel() Calls the fetch(channel:) PubNub endpoint and stores the response inside the Core Data store. 1public func syncRemoteChannel(2 _ request: ChatChannelRequest<ModelData.Channel>,3 completion: ((Result<ChatChannel<ModelData.Channel>, Error>) -> Void)? = nil4)

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChatChannelRequest<ModelData.Channel>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<ChatChannel<ModelData.Channel>, Error>) -> Void)?` | `Result` of either the fetched and stored channel or an `Error`. |

* `syncRemoteChannelsPaginated()`

Calls the `fetchPagesPublisher(channels:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func syncRemoteChannelsPaginated(
  _ request: ChannelsFetchRequest,
  pageHandler: (([ChatChannel<ModelData.Channel>], ChannelsFetchRequest?, Error?) -> Void)? = nil,
  completion: ((PaginationError<ChannelsFetchRequest>?) -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChannelsFetchRequest` | Request object that sets the PubNub API method parameters. |
| `pageHandler` | `(([ChatChannel<ModelData.Channel>], ChannelsFetchRequest?, Error?) -> Void)?` | The latest batch of `ChatChannel` that was fetched and stored. |
| `completion` | `((PaginationError<ChannelsFetchRequest>?) -> Void)?` | `Result` of either the fetched and stored channels (with the next request for pagination) or an `Error`. |

* `createRemoteChannel()`

Calls the `create(channel:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func createRemoteChannel(
  _ request: ChatChannelRequest<ModelData.Channel>,
  completion: ((Result<ChatChannel<ModelData.Channel>, Error>) -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChatChannelRequest<ModelData.Channel>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<ChatChannel<ModelData.Channel>, Error>) -> Void)?` | `Result` of either the fetched and stored channels (with the next request for pagination) or an `Error`. |

* `updateRemoteChannel()`

Calls the `update(channel:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func updateRemoteChannel(
  _ request: ChatChannelRequest<ModelData.Channel>,
  completion: ((Result<ChatChannel<ModelData.Channel>, Error>) -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChatChannelRequest<ModelData.Channel>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<ChatChannel<ModelData.Channel>, Error>) -> Void)?` | `Result` of either the fetched and stored channel or an `Error`. |

* `removeRemoteChannel()`

Calls the `remove(channel:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func removeRemoteChannel(
  _ request: ChatChannelRequest<ModelData.Channel>,
  completion: ((Result<Void, Error>) -> Void)?
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChatChannelRequest<ModelData.Channel>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<Void, Error>) -> Void)?` | `Result` of either the fetched and stored channel or an `Error`. |

## User

A [user](https://www.pubnub.com/docs/general/metadata/users-metadata) is an individual that's using the chat application and can be associated with both channels (through members) and messages.

### Managed data

The default Managed Object Model inside the Chat Components defines a Core Data `NSManagedObject` named `PubNubManagedUser`.

If a custom Managed Object Model is used, then an `NSManagedObject` entity must implement the `ManagedChatUser` protocol before it can be used by the Chat Components framework.

#### Managed user

The `PubNubManagedUser` entity is a CoreData managed `User` class used whenever a `ChatUser` needs to be stored locally. It is defined with the following attributes:

| Name | Type | Description |
| --- | --- | --- |
| `id` | `String` | Unique identifier for the object. |
| `name` | `String?` | Name of the channel. |
| `type` | `String` | Functional type of the user. The default value is set to `"default"`. |
| `status` | `String?` | Status of the user. |
| `externalId` | `String?` | External identifier for the object. |
| `avatarURL` | `URL?` | URL to a user avatar that you can display in the UI. |
| `email` | `String?` | Email address for the user. |
| `custom` | `Data` | Custom key value pairs that can be stored with the user. |
| `lastUpdated` | `Date?` | Last time the remote object was changed. This field references the `updated` field from `ChatUser`. |
| `eTag` | `String?` | Caching value that changes whenever the remote object changes. |

#### Relationships

The `PubNubManagedUser` entity has relationships with the following entities:

| Name | Type | Description |
| --- | --- | --- |
| `memberships` | `Set<PubNubManagedMember>` | Entity that connects to the users of a channel. |
| `messages` | `Set<PubNubManagedMessage>` | Entity that connects to the messages of a channel. |

#### Managed user protocol

To allow for a custom Managed Object Model, the `ManagedChatUser` protocol is used when referring to the managed object.

The protocol requires the following properties and methods:

* pubnubUserID Identifier used when interacting with PubNub APIs. It can be different from the primary key ID used by the managed object. 1var pubnubUserID: String { get }
* convert() Converts the managed object to a network object with the appropriately typed custom user data. 1func convert<Custom: UserCustomData>() -> ChatUser<Custom>

##### Returns

The base network object transformed to use the specified `UserCustomData`.

* insertOrUpdate(user:into:) Inserts or updates the managed object from a network object. 1@discardableResult2static func insertOrUpdate<Custom: UserCustomData>(3 user: ChatUser<Custom>,4 into context: NSManagedObjectContext5) throws -> Self

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `user` | `ChatUser<UserCustomData>` | `ChatUser` to be updated or inserted. |
| `into` | `NSManagedObjectContext` | Core Data context where the object is inserted or updated. |

##### Returns

The managed object that was inserted or updated.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a new managed object was created or an existing object was updated.

* `patch(usingPatch:into:)`

```swift
@discardableResult
static func patch<Custom: UserCustomData>(
  usingPatch patcher: ChatUser<Custom>.Patcher,
  into context: NSManagedObjectContext
) throws -> Self
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `usingPatch` | `ChatUser<UserCustomData>.Patcher` | `ChatUser.Patcher` changeset that is applied to an existing user if one exists. |
| `into` | `NSManagedObjectContext` | Core Data context where the object is inserted or updated. |

##### Returns

The managed object that was updated.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether an existing object was updated.

* remove(userId:from:) Removes a managed object matching the userId parameter. 1@discardableResult2static func remove(3 userId: String,4 from context: NSManagedObjectContext5) -> Self?

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `userId` | `String` | Unique identifier for the user. |
| `from` | `NSManagedObjectContext` | Core Data context where the object is removed. |

##### Returns

The managed object that was removed.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a managed object was removed.

* userBy(userId:) Creates NSFetchRequest that gets ManagedChatUser matching the userId parameter. 1static func userBy(userId: String) -> NSFetchRequest<Self>

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `userId` | `String` | Unique identifier for `ManagedChatUser`. |

##### Returns

`NSFetchRequest` whose predicate is set to get `ManagedChatUser` that matches the `userId` parameter.

### Network data

The generic `ChatUser` class contains the [user payload](#users) fields and is used whenever a Swift PubNub API requires a `User` object.

| Name | Type | Description |
| --- | --- | --- |
| `id` | `String` | Unique identifier for the object. |
| `name` | `String?` | Name of the channel. |
| `type` | `String` | Functional type of the user. The default value is set to `"default"`. |
| `status` | `String?` | Status of the user. |
| `externalId` | `String?` | External identifier for the object. |
| `avatarURL` | `URL?` | URL to a user avatar that you can display in the UI. This field references the `profileUrl` field from the [user payload](#users) specification. |
| `email` | `String?` | Email address for the user. |
| `updated` | `Date?` | Last time the remote object was changed. |
| `eTag` | `String?` | Caching value that changes whenever the remote object changes. |
| `custom` | `UserCustomData` | Custom key value pairs that can be stored with the user. |

#### Custom user data

Implement the `UserCustomData` protocol to provide custom data to the generic `ChatUser` class.

By default, all custom data is implemented as an empty object `VoidCustomData`.

The default implementation of `ChatUser` is a typealias of the following:

```swift
public typealias PubNubChatUser = ChatUser<VoidCustomData>
```

#### APIs

* `patch(:)`

Patches the properties of an existing ChatUser from a real-time changeset.

```swift
  public func patch(
    _ patcher: ChatUser<Customr>.Patcher
  ) -> ChatUser<Custom>
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `user` | `ChatUser<Custom>.Patcher` | User changeset that will be applied to an existing `ChatUser`. |

##### Returns

An updated `ChatUser` if the `Patcher` was able to perform the update, otherwise the duplicate `ChatUser`.

### Data provider actions

`DataProvider` contains several convenience methods that streamline the ability to fetch and manage user data. You can `DataProvider` through `ChatProvider`,

* load() Insets or updates a list of users in the Core Data store batching based on the supplied batchSize. 1public func load(2 users: [ChatUser<ModelData.User>],3 batchSize: Int = 256,4 batchHandler: (([ChatUser<ModelData.User>], Error?) -> Void)? = nil,5 completion: (() -> Void)? = nil6)

#### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `users` | `[ChatUser<ModelData.User>]` | Users to store. |
| `batchSize` | `Int` | Size of each chunk of users to store. |
| `batchHandler` | `(([ChatUser<ModelData.User>], Error?) -> Void)?` | Closure called after storing each batch. |
| `completion` | `(() -> Void)?` | Closure called after storing all users. |

* removeStoredUser() Removes a managed user matching the supplied userId. 1public func removeStoredUser(2 userId: String,3 completion: ((Error?) -> Void)? = nil4)

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `userId` | `String` | Unique identifier for the user. |
| `completion` | `((Error?) -> Void)?` | Closure called after removing the user. |

* `syncRemoteUser()`

Calls the `fetch(user:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func syncRemoteUser(
  _ request: ChatUserRequest<ModelData.User>,
  completion: ((Result<ChatUser<ModelData.User>, Error>) -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChatUserRequest<ModelData.User>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<ChatUser<ModelData.User>, Error>) -> Void)?` | `Result` of either the fetched and stored user or an `Error`. |

* `syncRemoteUsers()`

Calls the `fetch(users:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func syncRemoteUsers(
  _ request: UsersFetchRequest,
  completion: ((Result<(channels: [ChatUser<ModelData.User>], next: UsersFetchRequest?), Error>) -> Void)?
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `UsersFetchRequest` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<(channels: [ChatUser<ModelData.User>], next: UsersFetchRequest?), Error>) -> Void)?` | `Result` of either the fetched and stored users (with the next request for pagination) or an `Error`. |

* `syncRemoteUsersPaginated()`

Calls the `fetchPagesPublisher(users:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func syncRemoteUsersPaginated(
  _ request: UsersFetchRequest,
  pageHandler: (([ChatUser<ModelData.User>], UsersFetchRequest?, Error?) -> Void)? = nil,
  completion: ((PaginationError<UsersFetchRequest>?) -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `UsersFetchRequest` | Request object that sets the PubNub API method parameters. |
| `pageHandler` | `(([ChatUser<ModelData.User>], UsersFetchRequest?, Error?) -> Void)?` | The latest batch of `ChatUser` that was fetched and stored. |
| `completion` | `((PaginationError<UsersFetchRequest>?) -> Void)?` | `Result` of either the fetched and stored users (with the next request for pagination) or an `Error`. |

* `createRemoteUser()`

Calls the `create(user:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func createRemoteUser(
  _ request: ChatUserRequest<ModelData.User>,
  completion: ((Result<ChatUser<ModelData.User>, Error>) -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChatUserRequest<ModelData.User>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<ChatUser<ModelData.User>, Error>) -> Void)?` | `Result` of either the fetched and stored user or an `Error`. |

* `updateRemoteUser()`

Calls the `update(user:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func updateRemoteUser(
  _ request: ChatUserRequest<ModelData.User>,
  completion: ((Result<ChatUser<ModelData.User>, Error>) -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChatUserRequest<ModelData.User>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<ChatUser<ModelData.User>, Error>) -> Void)?` | `Result` of either the fetched and stored user or an `Error`. |

* removeRemoteUser() Calls the remove(user:) PubNub endpoint and stores the response inside the Core Data store.

```swift
public func removeRemoteUser(
  _ request: ChatUserRequest<ModelData.User>,
  completion: ((Result<Void, Error>) -> Void)?
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChatUserRequest<ModelData.User>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<Void, Error>) -> Void)?` | `Result` of either the removed `userId` or an `Error`. |

## Member

The [users](https://www.pubnub.com/docs/general/metadata/users-metadata) that are associated with a channel are also known as its members. A user might have many channel memberships and a channel might have multiple members.

### Managed data

The default Managed Object Model inside the Chat Components defines a Core Data `NSManagedObject` named `PubNubManagedMember`.

If a custom Managed Object Model is used, an `NSManagedObject` entity must implement the `ManagedChatMember` protocol before it can be used by the Chat Components framework.

#### Managed member

The `PubNubManagedMember` entity is a CoreData managed `Member` class used whenever a `ChatMember` needs to be stored locally. It is defined with the following attributes:

| Name | Type | Description |
| --- | --- | --- |
| `id` | `String` | Unique identifier for the object. |
| `custom` | `Data` | Custom key value pairs that can be stored with the member. |
| `status` | `String?` | Membership status. |
| `lastUpdated` | `Date?` | Last time the remote object was changed. This field references the `updated` field from `ChatMember`. |
| `eTag` | `String?` | Caching value that changes whenever the remote object changes. |
| `isPresent` | `Bool` | Presence status of the user on the channel. |
| `presenceState` | `Data?` | [Presence](https://www.pubnub.com/docs/general/presence/overview) state of the user on the channel. |
| `channelId` | `String` | Denormalized channel identifier that's derived from the `channel` relationship entity. |
| `userId` | `String` | Denormalized user identifier that's derived from the `user` relationship entity. |

#### Relationships

The `PubNubManagedMember` entity has relationships with the following entities:

| Name | Type | Description |
| --- | --- | --- |
| `user` | `PubNubManagedUser` | Entity that connects to the user. |
| `channel` | `PubNubManagedChannel` | Entity that connects to the channel. |

#### Managed member protocol

To allow for a custom Managed Object Model, the `ManagedChatMember` protocol is used when referring to the managed object.

The protocol requires the following properties and methods:

* convert() Converts the managed object to a network object with the appropriately typed Custom Chat data. 1func convert<Custom: ChatCustomData>() -> ChatMember<Custom>

##### Returns

The base network object transformed to use the specified `ChatCustomData`.

* insertOrUpdate(member:into:) Inserts or updates the managed object from a network object.

```swift
@discardableResult
static func insertOrUpdate<Custom: ChatCustomData>(
  member: ChatMember<Custom>,
  forceWrite: Bool,
  into context: NSManagedObjectContext
) throws -> Self
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `member` | `ChatMember<ChatCustomData>` | `ChatMember` to be updated or inserted. |
| `forceWrite` | `Bool` | Flag that defines if you want to override properties from `PubNubManagedMember` to those in `ChatMember<ChatCustomData>`. Set it to `true` if you want to insert a new membership that hasn't been synced with the PubNub server yet or if you want to override the `channel` and `user` properties for the already stored membership. |
| `into` | `NSManagedObjectContext` | Core Data context where the object is inserted or updated. |

##### Returns

The managed object that was inserted or updated.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a new managed object was created or an existing object was updated.

* `patch(usingPatch:into:)`

```swift
@discardableResult
static func patch<Custom: ChatCustomData>(
  usingPatch patcher: ChatMember<Custom>.Patcher,
  into context: NSManagedObjectContext
) throws -> Self
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `usingPatch` | `ChatMember<ChatCustomData>.Patcher` | `ChatUser.Patcher` changeset that is applied to an existing member if one exists. |
| `into` | `NSManagedObjectContext` | Core Data context where the object is inserted or updated. |

##### Returns

The managed object that was updated.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether an existing object was updated.

* remove(channelId:userId:from:) Removes a managed object matching the channelId parameter. 1@discardableResult2static func remove(3 channelId: String,4 userId: String,5 from context: NSManagedObjectContext6) -> Self?

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `channelId` | `String` | Unique identifier for the channel. |
| `userId` | `String` | Unique identifier for the user. |
| `from` | `NSManagedObjectContext` | Core Data context where the object is removed. |

##### Returns

The managed object that was removed.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a managed object was removed.

* membershipsBy(userId:) Creates NSFetchRequest that gets ManagedChatMember whose connected ManagedChatUser has the userId passed as the parameter. 1static func membershipsBy(userId: String) -> NSFetchRequest<Self>

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `userId` | `String` | Unique identifier for `ManagedChatUser`. |

##### Returns

`NSFetchRequest` whose predicate is set to get `ManagedChatMember` that matches the `userId` of the connected `ManagedChatUser`.

* membersBy(channelID:excludingUserId:onlyPresent) Creates NSFetchRequest that gets a list of ManagedChatMember for a specific ManagedChatChannel. 1static func membersBy(channelID: String, excludingUserId: String?, onlyPresent: Bool) -> NSFetchRequest<Self>

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `channelID` | `String` | Unique identifier for `ManagedChatChannel`. |
| `excludingUserId` | `String?` | Optional user identifier to be excluded. You can use it to remove the current user from a predicate. |
| `onlyPresent` | `Bool` | Whether the predicate should return only these channel members that are online. |

##### Returns

`NSFetchRequest` whose predicate is set to a list of `ManagedChatMember` for a specific `ManagedChatChannel`.

* memberBy(pubnubChannelId:pubnubUserId:) Creates NSFetchRequest that gets ManagedChatMember for specific ManagedChatChannel and ManagedChatUser using their PubNub identifiers. 1static func memberBy(pubnubChannelId: String, pubnubUserId: String) -> NSFetchRequest<Self>

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `pubnubChannelId` | `String` | Unique PubNub identifier for `ManagedChatChannel`. |
| `pubnubUserId` | `String` | Unique PubNub identifier for `ManagedChatUser`. |

##### Returns

`NSFetchRequest` whose predicate is set to get `ManagedChatMember` for specific `ManagedChatChannel` and `ManagedChatUser` using their PubNub identifiers.

### Network data

The generic `ChatMember` class is used whenever a Swift PubNub API requires a `Membership` object.

| Name | Type | Description |
| --- | --- | --- |
| `chatChannel` | `ChatChannel<Custom.Channel>` | Generic `ChatChannel` object linked to the user. |
| `chatUser` | `ChatUser<Custom.User>` | Generic `ChatUser` object linked to the channel. |
| `status` | `String?` | Membership status. |
| `updated` | `Date?` | Last time the remote object was changed. |
| `eTag` | `String?` | Caching value that changes whenever the remote object changes. |
| `custom` | `Custom.Member` | Custom key value pairs that can be stored with the user. |
| `isPresent` | `Bool?` | Presence status of the user on the channel. |
| `presence` | `MembershipPresence?` | [Presence](https://www.pubnub.com/docs/general/presence/overview) state of the user on the channel. |

#### Custom chat data

Implement the `ChatCustomData` protocol to provide custom data to the generic `Custom` class. `ChatCustomData.Member` can have its own custom data set by using the `MemberCustomData` protocol. To allow for generic type adherence for both `ChatUser` and `ChatChannel` properties, the `ChatCustomData` protocol can specify `UserCustomData` and `ChannelCustomData` implementations respectively.

By default, all custom data is implemented as an empty object `VoidCustomData`.

The default implementation of `ChatMember` is a typealias of the following:

```swift
public typealias PubNubChatMember = ChatMember<VoidCustomData>
```

### Data provider actions

`DataProvider` contains several convenience methods that streamline the ability to fetch and manage member data. `DataProvider`. You can access `DataProvider` through `ChatProvider`.

* load(members:batchSize:batchHandler:completion) Inserts or updates a list of members in the Core Data store batching based on the supplied batchSize. 1public func load(2 members: [ChatMember<ModelData>],3 batchSize: Int = 256,4 forceWrite: Bool = true,5 batchHandler: (([ChatMember<ModelData>], Error?) -> Void)? = nil,6 completion: (() -> Void)? = nil7)

#### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `members` | `[ChatMember<ModelData>]` | Members to store. |
| `batchSize` | `Int` | Size of each chunk of members to store. |
| `forceWrite` | `Bool` | Flag that defines if you want to override properties from `PubNubManagedMember` to those in `ChatMember<ChatCustomData>`. Set it to `true` if you want to insert a new membership that hasn't been synced with the PubNub server yet or if you want to override the `channel` and `user` properties for the already stored membership. |
| `batchHandler` | `(([ChatMember<ModelData>], Error?) -> Void)?` | Closure called after storing each batch. |
| `completion` | `(() -> Void)?` | Closure called after storing all members. |

* removeStoredMember(channelId:userId:completion:) Removes a managed member matching the supplied channelId and userId. 1public func removeStoredMember(2 channelId: String,3 userId: String,4 completion: ((Error?) -> Void)? = nil5)

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `channelId` | `String` | Unique identifier for the channel. |
| `userId` | `String` | Unique identifier for the user. |
| `completion` | `((Error?) -> Void)?` | Closure called after removing the member. |

* `removeStoredMembers(members:batchSize:batchHandler:completion:)`

Removes managed members matching the supplied `members`, `batchSize`, and `batchHandler`.

```swift
public func removeStoredMembers(
  members: [ChatMember<ModelData>],
  userId: Int,
  batchHandler: (([ChatMember<ModelData>], Error?) -> Void)? = nil,
  completion: (() -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `members` | `[ChatMember<ModelData>]` | Members to remove |
| `batchSize` | `Int` | Number of members to remove per batch. |
| `batchHandler` | `(([ChatMember<ModelData>], Error?) -> Void)?` | Closure called after storing each batch. |
| `completion` | `(() -> Void)? = nil` | Closure called after removing the members. |

* `syncRemoteUserMembers`

Calls the `fetch(userMembers:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func syncRemoteUserMembers(
  _ request: UserMemberFetchRequest,
  completion: ((Result<([ChatMember<ModelData>], next: UserMemberFetchRequest?), Error>) -> Void)?
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `UserMemberFetchRequest` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<([ChatMember<ModelData>], next: UserMemberFetchRequest?), Error>) -> Void)?` | `Result` of either the existing members that are stored locally ( with the next page of members) or an `Error`. |

* `syncRemoteChannelMembers`

Calls the `fetch(channelMembers:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func syncRemoteChannelMembers(
  _ request: ChannelMemberFetchRequest,
  completion: ((Result<([ChatMember<ModelData>], next: ChannelMemberFetchRequest?), Error>) -> Void)?
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChannelMemberFetchRequest` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<([ChatMember<ModelData>], next: ChannelMemberFetchRequest?), Error>) -> Void)?` | `Result` of either the existing members that are stored locally (with the next page of members) or an `Error`. |

* `syncRemoteUserMembersPagination`

Calls the `fetchPagesPublisher(userMembers:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func syncRemoteUserMembersPagination(
  _ request: UserMemberFetchRequest,
  pageHandler: (([ChatMember<ModelData>], UserMemberFetchRequest?, Error?) -> Void)? = nil,
  completion: ((PaginationError<UserMemberFetchRequest>?) -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `UserMemberFetchRequest` | Request object that sets the PubNub API method parameters. |
| `pageHandler` | `(([ChatMember<ModelData>], UserMemberFetchRequest?, Error?) -> Void)?` | The latest batch of `ChatMember` that was fetched and stored. |
| `completion` | `((PaginationError<UserMemberFetchRequest>?) -> Void)?` | `Result` of either the existing members that are stored locally (with the next page of members) or an `Error`. |

* `syncRemoteChannelMembersPagination`

Calls the `fetchPagesPublisher(channelMembers:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func syncRemoteChannelMembersPagination(
  _ request: ChannelMemberFetchRequest,
  pageHandler: (([ChatMember<ModelData>], ChannelMemberFetchRequest?, Error?) -> Void)? = nil,
  completion: ((PaginationError<ChannelMemberFetchRequest>?) -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `ChannelMemberFetchRequest` | Request object that sets the PubNub API method parameters. |
| `pageHandler` | `(([ChatMember<ModelData>], ChannelMemberFetchRequest?, Error?) -> Void)?` |  |
| `completion` | `((PaginationError<ChannelMemberFetchRequest>?) -> Void)?` | `Result` of either the existing members that are stored locally (with the next page of members) or an `Error`. |

* `createRemoteMembers`

Calls the `create(members:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func createRemoteMembers(
  _ request: MembersModifyRequest<ModelData>,
  completion: ((Result<Void, Error>) -> Void)?
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `MembersModifyRequest<ModelData>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<Void, Error>) -> Void)?` | `Result` of either the existing members that are stored locally (with the next page of members) or an `Error`. |

* `updateRemoteMemberships`

Calls the `update(members:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func updateRemoteMemberships(
  _ request: MembersModifyRequest<ModelData>,
  completion: ((Result<Void, Error>) -> Void)?
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `MembersModifyRequest<ModelData>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<Void, Error>) -> Void)?` | `Result` of either the existing members that are stored locally (with the next page of members) or an `Error`. |

* `removeRemoteMemberships`

Calls the `remove(members:)` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func removeRemoteMemberships(
  _ request: MembersModifyRequest<ModelData>,
  completion: ((Result<Void, Error>) -> Void)?
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `MembersModifyRequest<ModelData>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<Void, Error>) -> Void)?` | `Result` of either the existing members that are stored locally (with the next page of members) or an `Error`. |

## Message

A [message](https://www.pubnub.com/docs/general/messages/publish) is the dynamic content that a user sends to other users inside a channel.

### Managed data

The default Managed Object Model inside the Chat Components defines a Core Data `NSManagedObject` named `PubNubManagedMessage`.

If a custom Managed Object Model is used, an `NSManagedObject` entity must implement the `ManagedChatMessage` protocol before it can be used by the Chat Components framework.

#### Managed message

The `PubNubManagedMessage` entity is a CoreData managed `Message` class used whenever a `ChatMessage` needs to be stored locally. It is defined with the following attributes:

| Name | Type | Description |
| --- | --- | --- |
| `id` | `String` | Unique identifier for the object. |
| `timetoken` | `Timetoken` | Int64 timestamp for the message. |
| `dateCreated` | `Date` | ISO8601 date string of when the message was created. This attribute references the `createdAt` field from the [message payload](#messages) specification. |
| `text` | `String` | Text of the message. |
| `contentType` | `String` | Type identifier of the message payload. Currently, PubNub Chat Components support only text messages. |
| `content` | `Data` | Extra content for the message. Can contain any feature-specific data, like URLs to external images. |
| `custom` | `Data` | Custom key value pairs that can be stored with the message. |
| `pubnubUserId` | `String` | Denormalized user identifier that's derived from the `user` relationship entity. |
| `pubnubChannelId` | `String` | Denormalized channel identifier that's derived from the `channel` relationship entity. |

#### Relationships

The `PubNubManagedMessage` entity has relationships with the following entities:

| Name | Type | Description |
| --- | --- | --- |
| `author` | `PubNubManagedUser` | Entity that connects to the user. |
| `channel` | `PubNubManagedChannel` | Entity that connects to the channel. |

#### Managed message protocol

To allow for a custom Managed Object Model, the `ManagedChatMessage` protocol is used when referring to the managed object.

The protocol requires the following properties and methods:

* pubnubMessageID Identifier used when interacting with PubNub APIs. 1var pubnubMessageID: Timetoken { get }
* convert() Converts the managed object to a network object with the appropriately typed custom chat data. 1 func convert<Custom: ChatCustomData>() throws -> ChatMessage<Custom>

##### Returns

The base network object transformed to use the specified `ChatCustomData`.

* insertOrUpdate(message:into:) Inserts or updates the managed object from a network object. 1@discardableResult2static func insertOrUpdate<Custom: ChatCustomData>(3 message: ChatMessage<Custom>,4 processMessageActions: Bool,5 into context: NSManagedObjectContext6) throws -> Self

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `message` | `ChatMessage<ChatCustomData>` | `ChatMessage` to be updated or inserted. |
| `processMessageActions` | `Bool` | Flag that defines if you want to insert or update message actions that belong to the given `message`. |
| `into` | `NSManagedObjectContext` | Core Data context where the object is inserted or updated. |

##### Returns

The managed object that was inserted or updated.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a new managed object was created or an existing object was updated.

* remove(messageId:from:) Removes a managed object matching the messageId parameter. 1@discardableResult2static func remove(3 messageId: String,4 from context: NSManagedObjectContext5) ->

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `messageId` | `String` | Unique identifier for the message. |
| `from` | `NSManagedObjectContext` | Core Data context where the object is removed. |

##### Returns

The managed object that was removed.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a managed object was removed.

* messagesBy(pubnubUserId:) NSFetchRequest whose predicate is set to a list of ManagedChatMessage for a specific ManagedChatUser. 1static func messagesBy(pubnubUserId: String) -> NSFetchRequest<Self>

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `pubnubUserId` | `String` | Unique identifier for `ManagedChatUser`. |

##### Returns

`NSFetchRequest` whose predicate is set to get a list of `ManagedChatMessage` for a specific `ManagedChatUser`.

* messagesBy(pubnubChannelId:) NSFetchRequest whose predicate is set to a list of ManagedChatMessage for a specific ManagedChatChannel. 1static func messagesBy(pubnubChannelId: String) -> NSFetchRequest<Self>

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `pubnubChannelId` | `String` | Unique identifier for `ManagedChatChannel`. |

##### Returns

`NSFetchRequest` whose predicate is set to get a list of `ManagedChatMessage` for a specific `ManagedChatChannel`.

* messageBy(messageId:) Creates NSFetchRequest that gets ManagedChatMessage matching the messageId parameter.

```swift
static func messageBy(messageId: String) -> NSFetchRequest<Self>
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `messageId` | `String` | Unique identifier for `ManagedChatMessage`. |

##### Returns

`NSFetchRequest` whose predicate is set to get `ManagedChatMessage` matching the `messageId` parameter.

### Network data

The generic `ChatMessage` class implements the `PubNubMessage` protocol so it can be used whenever a Swift PubNub API requires or supplies a `PubNubMessage` object. The `ChatMessage` class contains the [message payload](#messages) fields and is defined with the following attributes:

| Name | Type | Description |
| --- | --- | --- |
| `id` | `String` | Unique identifier for the object. |
| `text` | `String` | Text of the message. |
| `contentType` | `String?` | Type identifier of the message payload. Currently, PubNub Chat Components support only text messages. |
| `content` | `JSONCodable?` | Extra content for the message. Can contain any feature-specific data, like URLs to external images. |
| `custom` | `Custom.Message` | Custom key value pairs that can be stored with the message. |
| `createdAt` | `Date` | ISO8601 date string of when the message was created. |
| `timetoken` | `Timetoken` | Int64 timestamp for the message. |
| `content` | `MessagePayload` | Payload of the message. |
| `pubnubUserId` | `String` | Denormalized message sender identifier that's derived from the `user` relationship entity. |
| `userModel` | `ChatUser<Custom.User>?` | Optional `ChatUser` object that should match `pubnubUserId`. |
| `pubnubChannelId` | `String` | Denormalized channel identifier of the message sender that's derived from the `channel` relationship entity. |
| `channelModel` | `ChatChannel<Custom.Channel>?` | Optional `ChatChannel` object that should match `pubnubChannelId`. |

#### Custom chat data

Implement the `ChatCustomData` protocol to provide custom data to the generic `Custom` class. `ChatCustomData.Message` can have its own custom data set by using the `MessageCustomData` protocol. To allow for generic type adherence for both `ChatUser` and `ChatChannel` properties, the `ChatCustomData` protocol can specify `UserCustomData` and `ChannelCustomData` implementations respectively.

By default, all custom data is implemented as an empty object `VoidCustomData`.

The default implementation of `ChatMember` is a typealias of the following:

```swift
public typealias PubNubChatMessage = ChatMessage<VoidCustomData>
```

### Data provider actions

`DataProvider` contains several convenience methods that streamline the ability to fetch and manage message data. You can access `DataProvider` through `ChatProvider`.

* load(messages:processMessageActions:batchSize:batchHandler:completion) Inserts or updates a list of messages in the Core Data store batching based on the supplied batchSize. 1public func load(2 messages: [ChatMessage<ModelData>],3 processMessageActions: Bool,4 batchSize: Int = 256,5 batchHandler: (([ChatMessage<ModelData>], Error?) -> Void)? = nil,6 completion: (() -> Void)? = nil7)

#### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `messages` | `[ChatMessage<ModelData>]` | Messages to store. |
| `processMessageActions` | `Bool` | Message reactions to store. |
| `batchSize` | `Int` | Size of each chunk of messages to store. |
| `batchHandler` | `(([ChatUser<ModelData>], Error?) -> Void)?` | Closure called after storing each batch. |
| `completion` | `(() -> Void)?` | Closure called after storing all messages. |

* removeStoredMessage(messageId:completion:) Removes a managed message matching the supplied messageId. 1public func removeStoredMessage(2 messageId: String,3 completion: ((Error?) -> Void)? = nil4)

#### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `messageId` | `String` | Unique identifier for the message. |
| `completion` | `((Error?) -> Void)?` | Closure called after removing the message. |

* `sendRemoteMessage`

Calls the `sendMessage()` PubNub endpoint and stores the response inside the Core Data store.

```swift
public func sendRemoteMessage(
  _ request: SendMessageRequest<ModelData>,
  completion: ((Result<ChatMessage<ModelData>, Error>) -> Void)?
)
```

#### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `SendMessageRequest<ModelData>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<ChatMessage<ModelData>, Error>) -> Void)?` | `Result` of either the published and stored message or an `Error`. |

* syncRemoteMessages Calls the fetchMessageHistory() PubNub endpoint and stores the response inside the Core Data store. 1public func syncRemoteMessages(2 _ request: MessageHistoryRequest,3 completion: ((Result<(messageByChannelId: [String: [ChatMessage<ModelData>]], next: MessageHistoryRequest?), PaginationError<MessageHistoryRequest>>) -> Void)?4)

#### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `MessageHistoryRequest` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<(messageByChannelId: [String: [ChatMessage<ModelData>]], next: MessageHistoryRequest?), PaginationError<MessageHistoryRequest>>) -> Void)?` | `Result` of either the existing messages that are stored locally (with the next page of messages) or `PaginationError` that contains `MessageHistoryRequest` that failed. |

### Message Reactions

A [message reaction](https://www.pubnub.com/docs/chat/community-supported/ios/message-reactions) is an emoji that a user adds to a message to react to it.

#### Managed data

The default Managed Object Model inside the Chat Components defines a Core Data `NSManagedObject` named `PubNubManagedMessageAction`.

If a custom Managed Object Model is used, an `NSManagedObject` entity must implement the `ManagedChatMessageAction` protocol before it can be used by the Chat Components framework.

##### Managed message reaction

The `PubNubManagedMessageAction` entity is defined with the following attributes:

| Name | Type | Description |
| --- | --- | --- |
| `id` | `String` | Unique identifier for the object. |
| `published` | `Timetoken` | Publish timetoken of the message action. |
| `sourceType` | `String` | Message action's type. |
| `value` | `String` | Message action's value. |
| `pubnubParentTimetoken` | `Timetoken` | Timetoken of the message that this action belongs to. |
| `pubnubParentId` | `String` | ID of the message that this action belongs to. |
| `pubnubUserId` | `String` | Publisher of the message action. |

##### Relationships

The `PubNubManagedMessageAction` entity has relationships with the following entities:

| Name | Type | Description |
| --- | --- | --- |
| `author` | `PubNubManagedUser` | Entity that connects to the user. |
| `parent` | `PubNubManagedMessage` | Entity that connects to the message. |

##### Managed message reaction protocol

To allow for a custom Managed Object Model, the `ManagedChatMessageAction` protocol is used when referring to the managed object.

The protocol requires the following properties and methods:

* pubnubActionTimetoken Identifier used when interacting with PubNub APIs. 1var pubnubActionTimetoken: Timetoken { get }
* convert() Converts the managed object to a network object with the appropriately typed custom chat data. 1public func convert<Custom: ChatCustomData>() throws -> ChatMessageAction<Custom>

###### Returns

The base network object transformed to use the specified `ChatCustomData`.

* insertOrUpdate(messageAction:into:) Inserts or updates the managed object from a network object. 1public static func insertOrUpdate<Custom: ChatCustomData>(2 messageAction: ChatMessageAction<Custom>,3 into context: NSManagedObjectContext4)

###### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `messageAction` | `ChatMessageAction<Custom>` | `ChatMessageAction` to be updated or inserted. |
| `into` | `NSManagedObjectContext` | Core Data context where the object is inserted or updated. |

###### Returns

The managed object that was inserted or updated.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a new managed object was created or an existing object was updated.

* insertOrUpdate(messageAction:into:) Inserts the managed object from a network object. 1public static func insert<Custom: ChatCustomData>(2 messageAction: ChatMessageAction<Custom>,3 into context: NSManagedObjectContext4)

###### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `messageAction` | `ChatMessageAction<Custom>` | `ChatMessageAction` to be inserted. |
| `into` | `NSManagedObjectContext` | Core Data context where the object is insertedd. |

###### Returns

The managed object that was inserted.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a new managed object was created or an existing object was updated.

* remove(messageActionId:from:) Removes the managed object from a network object. 1@discardableResult2public static func remove(3 messageActionId: String,4 from context: NSManagedObjectContext5) -> Self

###### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `messageActionId` | `String` | `messageActionId` to be removed. |
| `into` | `NSManagedObjectContext` | Core Data context where the object is removed. |

###### Returns

The managed object that was removed.

Observing the [NSManagedObjectContextDidSave](https://developer.apple.com/documentation/foundation/nsnotification/name/1506380-nsmanagedobjectcontextdidsave) notification will indicate whether a new managed object was removed.

#### Network data

The generic `ChatMessageAction` class implements the `PubNubChatMessageAction` protocol so it can be used whenever a Swift PubNub API requires or supplies a `PubNubChatMessageAction` object.

| Name | Type | Description |
| --- | --- | --- |
| `actionTimetoken` | `Timetoken` | Publish timetoken of the message action. |
| `parentTimetoken` | `Timetoken` | Timetoken of the message that this action belongs to. |
| `sourceType` | `String` | Message action's type. |
| `value` | `String` | Message action's value. |
| `pubnubUserId` | `String` | Publisher of the message action. |
| `userModel` | `ChatUser<CustomData.User>?` | Optional `ChatUser` object that should match `pubnubUserId`. |
| `pubnubChannelId` | `String` | ID of the channel that the message and its message action belongs to. |
| `messageModel` | `ChatMessage<CustomData>?` | Optional `ChatMessage` object that should match `parentTimetoken`. |

#### Data provider actions

`DataProvider` contains several convenience methods that streamline the ability to fetch and manage message data. You can access `DataProvider` through `ChatProvider`.

* sendRemoteMessageAction(_:completion:) Calls the addMessageAction() PubNub endpoint and stores the response inside the Core Data store. 1public func sendRemoteMessageAction(2 _ request: MessageActionSendRequest<ModelData>,3 completion: ((Result<ChatMessageAction<ModelData>, Error>) -> Void)?4)

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `MessageActionSendRequest<ModelData>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<ChatMessageAction<ModelData>, Error>) -> Void)?` | Result of either the published and stored message reaction or an `Error`. |

* removeRemoteMessageAction(_:completion:) Calls the removeMessageActions() PubNub endpoint and stores the response inside the Core Data store. 1public func removeRemoteMessageAction(2 _ request: MessageActionRequest<ModelData>,3 completion: ((Result<Void, Error>) -> Void)?4)

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `MessageActionRequest<ModelData>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<Void, Error>) -> Void)?` | Closure called after removing the message reaction. |

* syncRemoteMessageActions(_:completion:) Calls the fetchMessageActions() PubNub endpoint and stores the response inside the Core Data store. 1public func removeRemoteMessageAction(2 _ request: MessageActionFetchRequest,3 completion: ((Result<(actions: [ChatMessageAction<ModelData>], next: MessageActionFetchRequest?), PaginationError<MessageActionFetchRequest>>) -> Void)?4)

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `MessageActionRequest<ModelData>` | Request object that sets the PubNub API method parameters. |
| `completion` | `((Result<(actions: [ChatMessageAction<ModelData>], next: MessageActionFetchRequest?), PaginationError<MessageActionFetchRequest>>) -> Void)?` | `Result` of either the existing message reactions that are stored locally (with the next page of message reactions) or `PaginationError` that contains `MessageActionFetchRequest` that failed. |

* syncAllRemoteMessageActions(pageHandler:completion:) Calls the fetchMessageActions() PubNub endpoint and stores the response inside the Core Data store. 1public func syncAllRemoteMessageActions(2 _ request: MessageActionFetchRequest,3 pageHandler: (([ChatMessageAction<ModelData>], MessageActionFetchRequest?, Error?) -> Void)? = nil,4 completion: ((PaginationError<MessageActionFetchRequest>?) -> Void)? = nil5)

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `_ request` | `MessageActionFetchRequest` | Request object that sets the PubNub API method parameters. |
| `pageHandler` | `(([ChatMessageAction<ModelData>], MessageActionFetchRequest?, Error?) -> Void)?` | Closure called after storing each page. |
| `completion` | `((PaginationError<MessageActionFetchRequest>?) -> Void)?` | Closure called after storing all message reactions. |

* load(messages:processMessageActions:batchSize:batchHandler:completion) Inserts or updates a list of messages with reactions in the Core Data store batching based on the supplied batchSize. 1public func load(2 messages: [ChatMessage<ModelData>],3 processMessageActions: Bool,4 batchSize: Int = 256,5 batchHandler: (([ChatMessage<ModelData>], Error?) -> Void)? = nil,6 completion: (() -> Void)? = nil7)

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `messages` | `[ChatMessage<ModelData>]` | Messages to store. |
| `processMessageActions` | `Bool` | Flag that defines if you want to insert or update message actions that belong to the given `message`. |
| `batchSize` | `Int` | Size of each chunk of messages with reactions to store. |
| `batchHandler` | `(([ChatMessage<ModelData>], Error?) -> Void)?` | Closure called after storing each batch. |
| `completion` | `(() -> Void)?` | Closure called after storing all message reactions. |

* load(messageActions:batchSize:batchHandler:completion) Inserts or updates a list of message reactions in the Core Data store batching based on the supplied batchSize. 1public func load(2 messageActions: [ChatMessageAction<ModelData>],3 batchSize: Int = 256,4 batchHandler: (([ChatMessageAction<ModelData>], Error?) -> Void)? = nil,5 completion: (() -> Void)? = nil6)

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `messageActions` | `[ChatMessageAction<ModelData>]` | Message reactions ot store. |
| `batchSize` | `Int` | Size of each chunk of reactions to store. |
| `batchHandler` | `(([ChatMessageAction<ModelData>], Error?) -> Void)?` | Closure called after storing each batch. |
| `completion` | `(() -> Void)?` | Closure called after storing all message reactions. |

* `removeStoredMessageAction(messageActionId:completion)`

Removes a list of messages reactions from the Core Data store batching.

```swift
public func removeStoredMessageAction(
  messageActionId: String,
  completion: ((Error?) -> Void)? = nil
)
```

##### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `messageActionId` | `String` | Unique identifier for the message reaction. |
| `completion` | `((Error?) -> Void)?` | Closure called after removing all message reactions. |