---
source_url: https://www.pubnub.com/docs/sdks/objective-c/api-reference/configuration
title: Configuration API for Objective-C SDK
updated_at: 2026-05-20T11:07:25.098Z
sdk_name: PubNub Objective-C SDK
sdk_version: 7.0.2
---

> 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


# Configuration API for Objective-C SDK

PubNub Objective-C SDK, use the latest version: 7.0.2

Install:

```bash
pod install PubNub@7.0.2
```

Complete API reference for building real-time applications on PubNub with the Objective-C Software Development Kit (SDK). This page covers configuration, initialization, and event handling with concise, working examples.

## Configuration

`PNConfiguration` stores settings that control the client's behavior. It includes credentials and options to tailor how the client connects, retries, and processes messages.

:::warning Privacy
[MAU billing](https://www.pubnub.com/docs/general/setup/account-setup#pricing-model) tracks users ([Device](https://www.pubnub.com/docs/general/basics/identify-users-and-devices) and MAU) for analytics and billing. PubNub does not track customers using transactions with random UUIDs/UserIDs.
:::

### Method(s)

Create a configuration instance with:

```objectivec
+ (instancetype)configurationWithPublishKey:(NSString *)publishKey 
                               subscribeKey:(NSString *)subscribeKey;
                                     userID:(NSString *)userID
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| publishKey | NSString | Yes |  | Publish key. Example: "demo". |
| subscribeKey | NSString | Yes |  | Subscribe key. Example: "demo". |
| userID | NSString | Yes |  | User ID. UTF‑8 string, up to 92 characters. Required. |
| heartbeatNotificationOptions | PNHeartbeatNotificationOptions | Optional |  | Heartbeat notifications. `Success`, `Failure` (default), `All`, or `None`. |
| stripMobilePayload | BOOL | Optional |  | If `YES`, remove push payload metadata (APNs/FCM) from received messages. |
| subscribeMaximumIdleTime | NSTimeInterval | Optional |  | Max seconds to wait for events. Default: `310`. |
| nonSubscribeRequestTimeout | NSTimeInterval | Optional |  | Timeout for non‑subscribe ops, in seconds. Default: `10`. |
| presenceHeartbeatValue | NSInteger | Optional |  | Presence timeout (seconds). Defaults to `300`. Triggers timeout if no heartbeat. |
| presenceHeartbeatInterval | NSInteger | Optional |  | Heartbeat interval (seconds). Typical: `(presenceHeartbeatValue / 2) - 1`. Min `3`. |
| keepTimeTokenOnListChange | BOOL | Optional |  | Keep previous timetoken on subscribe list change. Default: `YES`. |
| catchUpOnSubscriptionRestore | BOOL | Optional |  | Catch up on missed events after restore. Default: `YES`. |
| applicationExtensionSharedGroupIdentifier | NSString | Optional |  | Shared App Group ID for extensions (iOS 8.0+, macOS 10.10+). |
| requestMessageCountThreshold | NSUInteger | Optional |  | Max messages per response before `PNRequestMessageCountExceededCategory`. |
| maximumMessagesCacheSize | NSUInteger | Optional |  | De‑duplication cache size. Default: `100`. |
| completeRequestsBeforeSuspension | BOOL | Optional |  | Finish in‑flight API calls before suspension. Default: `YES`. |
| suppressLeaveEvents | BOOL | Optional |  | If `YES`, don’t send presence leave events on unsubscribe. |
| origin | NSString | Optional |  | Custom origin (domain). Example: "ps.pndsn.com". |
| requestRetry | PNRequestRetryConfiguration | Optional |  | Retry policy settings. See [requestRetry](#requestretry). |
| cryptoModule | [PNCryptoModule | Optional |  | Encrypt/decrypt module. Takes `cipherKey` and `useRandomInitializationVector`. See [cryptoModule](#cryptomodule). |
| logLevel | PNLogLevel | Optional |  | Minimum log level to capture. Values: `PNNoneLogLevel` (disabled), `PNTraceLogLevel`, `PNDebugLogLevel`, `PNInfoLogLevel`, `PNWarnLogLevel`, `PNErrorLogLevel`. Default: `PNNoneLogLevel`. See [Logging](https://www.pubnub.com/docs/sdks/objective-c/logging). |
| enableDefaultConsoleLogger | BOOL | Optional |  | Enable the built-in console logger. Default: `YES`. When `YES`, log entries print to the Xcode console. When `NO`, the SDK uses only custom loggers. See [Logging](https://www.pubnub.com/docs/sdks/objective-c/logging). |
| loggers | NSArray<id<PNLogger>> | Optional |  | Array of custom logger implementations conforming to the `PNLogger` protocol. Custom loggers receive log entries alongside the built-in console logger if the console logger is enabled. See [Custom Loggers](https://www.pubnub.com/docs/sdks/objective-c/logging#custom-loggers). |
| cipherKey | NSString | Optional |  | This way of setting this parameter is deprecated, pass it to `cryptoModule` instead. Key which is used to encrypt messages pushed to PubNub service and decrypt messages received from live feeds on which client subscribed at this moment. |
| useRandomInitializationVector | BOOL | Optional |  | This way of setting this parameter is deprecated, pass it to `cryptoModule` instead. When YES the initialization vector (IV) is random for all requests (not just for file upload). When NO the IV is hard-coded for all requests except for file upload. By default, using the random initialization vector is enabled. |

:::warning Disabling random initialization vector
Disable random initialization vector (IV) only for backward compatibility (<`4.16.0`) with existing applications. Never disable random IV on new applications.
:::

#### requestRetry

Use `PNRequestRetryConfiguration` to control retry behavior. For policy details, see [Reconnection Policy](https://www.pubnub.com/docs/general/setup/connection-management#reconnection-policy).

##### Create a default linear retry policy

```objectivec
+ (instancetype)configurationWithLinearDelay;
```

###### Example

```objectivec
configuration.requestRetry = [PNRequestRetryConfiguration configurationWithLinearDelay];
```

##### Create a linear retry policy with excluded endpoints

```objectivec
+ (instancetype)configurationWithLinearDelayExcludingEndpoints:(PNEndpoint)endpoints, ...;
```

| Parameter | Description |
| --- | --- |
| `endpoints`Type: `PNEndpoint` | The endpoints to exclude. For a list of endpoints, inspect `NS_ENUM(NSUInteger, PNEndpoint)` in the [PNStructures](https://github.com/pubnub/objective-c/blob/master/PubNub/Misc/PNStructures.h) file. |

###### Example

```objectivec
configuration.requestRetry = [PNRequestRetryConfiguration configurationWithLinearDelayExcludingEndpoints:PNMessageSendEndpoint, 0];
```

##### Create a linear retry policy with excluded endpoints and custom parameters

```objectivec
+ (instancetype)configurationWithLinearDelay:(NSTimeInterval)delay
                                maximumRetry:(NSUInteger)maximumRetry
                           excludedEndpoints:(PNEndpoint)endpoints, ...;
```

| Parameter | Description |
| --- | --- |
| `delay`Type: `NSTimeInterval` | Delay in seconds between failed requests. |
| `maximumRetry`Type: `NSUInteger` | How many times to retry before throwing an error. |
| `excludedEndpoints`Type: `PNEndpoint` | The endpoints to exclude. For a list of endpoints, inspect `NS_ENUM(NSUInteger, PNEndpoint)` in the [PNStructures](https://github.com/pubnub/objective-c/blob/master/PubNub/Misc/PNStructures.h) file. |

###### Example

```objectivec
/// example
configuration.requestRetry = [PNRequestRetryConfiguration configurationWithLinearDelay:3.f
                                                                          maximumRetry:3
                                                                     excludedEndpoints:PNMessageSendEndpoint, PNMessageStorageEndpoint, 0];
```

##### Create a default exponential retry policy

```objectivec
+ (instancetype)configurationWithExponentialDelay;
```

###### Example

```objectivec
configuration.requestRetry = [PNRequestRetryConfiguration configurationWithExponentialDelay];
```

##### Create an exponential retry policy with excluded endpoints

```objectivec
+ (instancetype)configurationWithExponentialDelayExcludingEndpoints:(PNEndpoint)endpoints, ...;
```

| Parameter | Description |
| --- | --- |
| `endpoints`Type: `PNEndpoint` | The endpoints to exclude. For a list of endpoints, inspect `NS_ENUM(NSUInteger, PNEndpoint)` in the [PNStructures](https://github.com/pubnub/objective-c/blob/master/PubNub/Misc/PNStructures.h) file. |

###### Example

```objectivec
configuration.requestRetry = [PNRequestRetryConfiguration configurationWithExponentialDelayExcludingEndpoints:PNMessageSendEndpoint, 0];
```

##### Create an exponential retry policy with excluded endpoints and custom parameters

```objectivec
+ (instancetype)configurationWithExponentialDelay:(NSTimeInterval)minimumDelay
                                     maximumDelay:(NSTimeInterval)maximumDelay
                                     maximumRetry:(NSUInteger)maximumRetry
                                excludedEndpoints:(PNEndpoint)endpoints, ...;
```

| Parameter | Description |
| --- | --- |
| `minimumDelay`Type: `NSTimeInterval` | Base delay in seconds used to calculate the next delay. |
| `maximumDelay`Type: `NSTimeInterval` | Maximum allowed computed delay in seconds between retry attempts. |
| `maximumRetry`Type: `NSUInteger` | How many times to retry before throwing an error. |
| `excludedEndpoints`Type: `PNEndpoint` | The endpoints to exclude. For a list of endpoints, inspect `NS_ENUM(NSUInteger, PNEndpoint)` in the [PNStructures](https://github.com/pubnub/objective-c/blob/master/PubNub/Misc/PNStructures.h) file. |

###### Example

```objectivec
configuration.requestRetry = [PNRequestRetryConfiguration configurationWithExponentialDelay:3.f
                                                                               maximumDelay:120.f
                                                                               maximumRetry:3
                                                                          excludedEndpoints:PNMessageSendEndpoint, PNMessageStorageEndpoint, 0];
```

#### cryptoModule

`cryptoModule` encrypts and decrypts messages and files. From 5.1.3, you can configure the algorithms it uses.

Each SDK includes two options: legacy 128‑bit encryption and recommended 256‑bit AES‑CBC. For background, see [Message Encryption](https://www.pubnub.com/docs/general/setup/data-security#message-encryption) and [File Encryption](https://www.pubnub.com/docs/general/setup/data-security#file-encryption).

If you don't set `cryptoModule` but set `cipherKey` and `useRandomInitializationVector` in config, the client uses legacy encryption.

For configuration details and examples, see [Encryption](https://www.pubnub.com/docs/sdks/objective-c/api-reference/encryption).

:::note Legacy encryption with 128-bit cipher key entropy
You don't have to change your encryption configuration if you want to keep using the legacy encryption. If you want to use the recommended 256-bit AES-CBC encryption, you must explicitly set that in PubNub config.
:::

### Sample code

:::note Required User ID
Always set the User ID (`userID`) to uniquely identify the user or device that connects to PubNub. Persist the value and keep it stable for the lifetime of the user or device. If you don't set the `userID`, the client cannot connect.
:::

```objectivec
// Basic configuration
PNConfiguration *config = [PNConfiguration configurationWithPublishKey:@"demo"
                                                          subscribeKey:@"demo"
                                                                userID:@"myUniqueUserID"];

// Create a PubNub client instance
PubNub *client = [PubNub clientWithConfiguration:config];

// Add listener for PubNub events
[client addListener:self];

// Subscribe to a test channel
PNSubscribeRequest *subscribeRequest = [PNSubscribeRequest requestWithChannels:@[@"test-channel"]
                                                                 channelGroups:nil];
subscribeRequest.observePresence = YES;

[client subscribeWithRequest:subscribeRequest];

// Publish a test message
PNPublishRequest *publishRequest = [PNPublishRequest requestWithChannel:@"test-channel"];
publishRequest.message = @{@"message": @"Hello PubNub!"};

[client publishWithRequest:publishRequest withCompletion:^(PNPublishStatus *status) {
    if (!status.isError) {
        NSLog(@"✅ Successfully published message! Connection is working.");
    } else {
        NSLog(@"❌ Failed to publish message. Error: %@", status.errorData.information);
    }
}];

// Required PNEventsListener methods
- (void)client:(PubNub *)client didReceiveStatus:(PNStatus *)status {
    // Checking connectivity only using subscribe operation.
    if (status.operation != PNSubscribeOperation) return;
    
    if (status.category == PNConnectedCategory) {
        NSLog(@"✅ Successfully connected to PubNub!");
    } else if (status.isError) {
        NSLog(@"❌ PubNub connection error: %@", status);
    } else {
        NSLog(@"Received status: %@", status);
    }
}

- (void)client:(PubNub *)client didReceiveMessage:(PNMessageResult *)message {
    NSLog(@"✅ Received message: %@ on channel: %@", message.data.message, message.data.channel);
}

- (void)client:(PubNub *)client didReceivePresenceEvent:(PNPresenceEventResult *)event {
    NSLog(@"Presence event: %@", event);
}
```

### Returns

Returns a configured client configuration instance.

### Other examples

#### Configure logging

Enable logging to monitor SDK (Software Development Kit) activity and troubleshoot issues.

##### Basic logging configuration

```objectivec
PNConfiguration *config = [PNConfiguration configurationWithPublishKey:@"demo" 
                                                          subscribeKey:@"demo"
                                                                userID:@"myUniqueUserID"];

// Set minimum log level
config.logLevel = PNDebugLogLevel;

PubNub *client = [PubNub clientWithConfiguration:config];
```

##### Change log level at runtime

```objectivec
// Adjust logging detail after initialization
[client setLogLevel:PNErrorLogLevel];
```

##### Disable console logger

```objectivec
PNConfiguration *config = [PNConfiguration configurationWithPublishKey:@"demo" 
                                                          subscribeKey:@"demo"
                                                                userID:@"myUniqueUserID"];
config.logLevel = PNDebugLogLevel;
config.enableDefaultConsoleLogger = NO;  // Disable default logger output to the Xcode console

PubNub *client = [PubNub clientWithConfiguration:config];
```

##### Add custom loggers

```objectivec
PNConfiguration *config = [PNConfiguration configurationWithPublishKey:@"demo" 
                                                          subscribeKey:@"demo"
                                                                userID:@"myUniqueUserID"];
config.logLevel = PNDebugLogLevel;
config.loggers = @[myCustomLogger];  // Add your PNLogger implementation

PubNub *client = [PubNub clientWithConfiguration:config];
```

For custom logger implementation examples and best practices, see [Logging](https://www.pubnub.com/docs/sdks/objective-c/logging).

#### Configure heartbeat notifications

##### PNConfiguration

```objectivec
PNConfiguration *config = [PNConfiguration configurationWithPublishKey:@"<pub key>" subscribeKey:@"<sub key>"];
/**
    This is where you need to adjust the PNConfiguration object for the types of heartbeat notifications you want.
    This is a bitmask of options located at https://github.com/pubnub/objective-c/blob/1f1c7a41a3bd8c32b644a6ad98fe179d45397c2b/PubNub/Misc/PNStructures.h#L24
    */
config.heartbeatNotificationOptions = PNHeartbeatNotifyAll;

self.client = [PubNub clientWithConfiguration:config];
[self.client addListener:self];
```

##### Listener

```objectivec
- (void)client:(PubNub *)client didReceiveStatus:(PNStatus *)status {

    if (status.operation == PNHeartbeatOperation) {

        /**
            Heartbeat operations can in fact have errors, so it is important to check first for an error.
            For more information on how to configure heartbeat notifications through the status
            PNObjectEventListener callback, consult http://www.pubnub.com/docs/sdks/objective-c/api-reference/configuration#configuration_basic_usage
            */

        if (!status.isError) { /* Heartbeat operation was successful. */ }
        else { /* There was an error with the heartbeat operation, handle here. */ }
    }
}
```

## Initialization

Install CocoaPods and follow the [Getting Started guide](https://www.pubnub.com/docs/sdks/objective-c). Then:

1. Create a new Xcode project.
2. Create a Podfile in a new Xcode project root folder 1pod init 1platform :ios, '9.0'2 3target 'application-target-name' do4 use_frameworks!5 6 pod "PubNub", "~> 4"7end

If you need more pods or targets (for example, a test target), add them to the same Podfile. See the CocoaPods [documentation](https://guides.cocoapods.org/syntax/podfile.html#target) for details.

* Install your pods by running `pod install` via the command line from the directory that contains your Podfile.

:::note
After installing your Pods, you should only be working within the workspace generated by CocoaPods or specified by you in Podfile. Always open the newly generated workspace file, not the original project file!
:::

Import the SDK headers where you use them:

```objectivec
#import <PubNub/PubNub.h>
```

#### Complete application delegate configuration

Add the `PNObjectEventListener` protocol to `AppDelegate` in the implementation file's anonymous category:

:::note Required User ID
Always set the User ID (`userID`) to uniquely identify the user or device that connects to PubNub. Persist the value and keep it stable for the lifetime of the user or device. If you don't set the `userID`, the client cannot connect.
:::

```objectivec
#import <PubNub/PubNub.h>

@interface AppDelegate () <PNObjectEventListener>

// Stores reference on PubNub client to make sure what it won't be released.
@property (nonatomic, strong) PubNub *client;

@end
```

### Description

Initialize the client API before calling any SDK methods. This sets account-level credentials such as `publishKey` and `subscribeKey`.

### Method(s)

Initialize PubNub with:

#### Initialize PubNub

```objectivec
+ (instancetype)clientWithConfiguration:(PNConfiguration *)configuration;
```

| Parameter | Description |
| --- | --- |
| `configuration` *Type: PNConfiguration | Reference on instance which store all user-provided information about how client should operate and handle events. |

#### Initialize with callback queue

```objectivec
+ (instancetype)clientWithConfiguration:(PNConfiguration *)configuration callbackQueue:(dispatch_queue_t)callbackQueue;
```

| Parameter | Description |
| --- | --- |
| `configuration` *Type: PNConfiguration | Reference on instance which store all user-provided information about how client should operate and handle events. |
| `callbackQueue`Type: dispatch_queue_t | Reference on queue which should be used by client for completion block and delegate calls. |

### Sample code

#### Initialize the PubNub client API

:::note Required User ID
Always set the User ID (`userID`) to uniquely identify the user or device that connects to PubNub. Persist the value and keep it stable for the lifetime of the user or device. If you don't set the `userID`, the client cannot connect.
:::

```objectivec
PNConfiguration *config = [PNConfiguration configurationWithPublishKey:@"demo"
                                                                                                      subscribeKey:@"demo"
                                                                                                                  userID:@"myUserID"];
config.TLSEnabled = YES;
self.client = [PubNub clientWithConfiguration:configuration];
```

:::warning Configuration instance
Ensure the same configuration instance (`config`) is passed to `clientWithConfiguration:` that you created above. The `TLSEnabled` property refers to Transport Layer Security (TLS).
:::

### Returns

Returns the client instance for invoking APIs such as `publish`, `subscribeToChannels`, `historyForChannel`, and `hereNowForChannel`.

### Other examples

#### Initialize the client

:::note Required User ID
Always set the User ID (`userID`) to uniquely identify the user or device that connects to PubNub. Persist the value and keep it stable for the lifetime of the user or device. If you don't set the `userID`, the client cannot connect.
:::

```objectivec
PNConfiguration *configuration = [PNConfiguration configurationWithPublishKey:@"demo"
                                                                    subscribeKey:@"demo"
                                                                          userID:@"myUserID"];

self.client = [PubNub clientWithConfiguration:configuration];
```

#### Initialization for a Read-Only client

In the case where a client will only read messages and never publish to a channel, you can simply omit the `publishKey` when initializing the client:

:::note Required User ID
Always set the User ID (`userID`) to uniquely identify the user or device that connects to PubNub. Persist the value and keep it stable for the lifetime of the user or device. If you don't set the `userID`, the client cannot connect.
:::

```objectivec
PNConfiguration *configuration = [PNConfiguration configurationWithPublishKey:@""
                                                                    subscribeKey:@"demo"
                                                                          userID:@"myUserID"];
self.client = [PubNub clientWithConfiguration:configuration];
```

## Event listeners

Use listeners to receive connectivity, message, presence, object, and file events. Add listeners before you subscribe or publish.

#### Add listeners

Your listener class must conform to the `PNEventsListener` protocol to receive callbacks.

```objectivec
// Adding listener.
[pubnub addListener:self];

// Callbacks listed below.

- (void)client:(PubNub *)pubnub didReceiveMessage:(PNMessageResult *)message {
    NSString *channel = message.data.channel; // Channel on which the message has been published
    NSString *subscription = message.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSNumber *timetoken = message.data.timetoken; // Publish timetoken
    id msg = message.data.message; // Message payload
    NSString *publisher = message.data.publisher; // Message publisher
}

- (void)client:(PubNub *)pubnub didReceiveSignal:(PNSignalResult *)signal {
    NSString *channel = message.data.channel; // Channel on which the signal has been published
    NSString *subscription = message.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSNumber *timetoken = message.data.timetoken; // Signal timetoken
    id msg = message.data.message; // Signal payload
    NSString *publisher = message.data.publisher; // Signal publisher
}

- (void)client:(PubNub *)pubnub didReceiveMessageAction:(PNMessageActionResult *)action {
    NSString *channel = action.data.channel; // Channel on which the message has been published
    NSString *subscription = action.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSString *event = action.data.event; // Can be: added or removed
    NSString *type = action.data.action.type; // Message action type
    NSString *value = action.data.action.value; // Message action value
    NSNumber *messageTimetoken = action.data.action.messageTimetoken; // Timetoken of the original message
    NSNumber *actionTimetoken = action.data.action.actionTimetoken; // Timetoken of the message action
    NSString *uuid = action.data.action.uuid; // UUID of user which added / removed message action
}

- (void)client:(PubNub *)pubnub didReceivePresenceEvent:(PNPresenceEventResult *)event {
    NSString *channel = message.data.channel; // Channel on which presence changes
    NSString *subscription = message.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSString *presenceEvent = event.data.presenceEvent; // Can be: join, leave, state-change, timeout or interval
    NSNumber *occupancy = event.data.presence.occupancy; // Number of users subscribed to the channel (not available for state-change event)
    NSNumber *timetoken = event.data.presence.timetoken; // Presence change timetoken
    NSString *uuid = event.data.presence.uuid; // UUID of user for which presence change happened

    // Only for 'state-change' event
    NSDictionary *state = event.data.presence.state; // User state (only for state-change event)

    // Only for 'interval' event
    NSArray<NSString *> *join = event.data.presence.join; // UUID of users which recently joined channel
    NSArray<NSString *> *leave = event.data.presence.leave; // UUID of users which recently leaved channel
    NSArray<NSString *> *timeout = event.data.presence.timeout; // UUID of users which recently timed out on channel
}

- (void)client:(PubNub *)pubnub didReceiveObjectEvent:(PNObjectEventResult *)event {
    NSString *channel = event.data.channel; // Channel to which the event belongs
    NSString *subscription = event.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSString *event = event.data.event; // Can be: set or delete
    NSString *type = event.data.type; // Entity type: channel, uuid or membership
    NSNumber *timestamp = event.data.timestamp; // Event timestamp

    PNChannelMetadata *channelMetadata = event.data.channelMetadata; // Updated channel metadata (only for channel entity type)
    PNUUIDMetadata *uuidMetadata = event.data.uuidMetadata; // Updated channel metadata (only for uuid entity type)
    PNMembership *membership = event.data.membership; // Updated channel metadata (only for membership entity type)
}

- (void)client:(PubNub *)pubnub didReceiveFileEvent:(PNFileEventResult *)event {
    NSString *channel = event.data.channel; // Channel to which file has been uploaded
    NSString *subscription = event.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    id message = event.data.message; // Message added for uploaded file
    NSString *publisher = event.data.publisher; // UUID of file uploader
    NSURL *fileDownloadURL = event.data.file.downloadURL; // URL which can be used to download file
    NSString *fileIdentifier = event.data.file.identifier; // Unique file identifier
    NSString *fileName = event.data.file.name; // Name with which file has been stored remotely
}

- (void)client:(PubNub *)pubnub didReceiveStatus:(PNStatus *)status {
    PNStatusCategory category = status.category; // One of PNStatusCategory fields to identify status of operation processing
    PNOperationType operation = status.operation; // One of PNOperationType fields to identify for which operation status received
    BOOL isError = status.isError; // Whether any kind of error happened.
    NSInteger statusCode = status.statusCode; // Related request processing status code
    BOOL isTLSEnabled = status.isTLSEnabled; // Whether secured connection enabled
    NSString *uuid = status.uuid; // UUID which configured for passed client
    NSString *authKey = status.authKey; // Auth key configured for passed client
    NSString *origin = status.origin; // Origin against which request has been sent
    NSURLRequest *clientRequest = status.clientRequest; // Request which has been used to send last request (may be nil)
    BOOL willAutomaticallyRetry = status.willAutomaticallyRetry; // Whether client will try to perform automatic retry

    // Following information available when operation == PNSubscribeOperation, because status is PNSubscribeStatus instance in this case
    PNSubscribeStatus *subscribeStatus = (PNSubscribeStatus *)status;
    NSNumber *currentTimetoken = subscribeStatus.currentTimetoken; // Timetoken which has been used for current subscribe request
    NSNumber *lastTimeToken = subscribeStatus.lastTimeToken; // Timetoken which has been used for previous subscribe request
    NSArray<NSString *> *subscribedChannels = subscribeStatus.subscribedChannels; // List of channels on which client currently subscribed
    NSArray<NSString *> *subscribedChannelGroups = subscribeStatus.subscribedChannelGroups; // List of channel groups on which client currently subscribed
    NSString *channel = subscribeStatus.data.channel; // Name of channel for which status has been received
    NSString *subscription = subscribeStatus.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSNumber *timetoken = subscribeStatus.data.timetoken; // Timetoken at which event arrived
    NSDictionary *userMetadata = subscribeStatus.data.userMetadata; // Metadata / envelope which has been passed along with event

    // Following information available when isError == YES, because status is PNErrorStatus instance in this case
    PNErrorStatus *errorStatus = (PNErrorStatus *)status;
    id associatedObject = errorStatus.associatedObject; // Data which may contain related information (not decrypted message for example)
    NSArray<NSString *> *erroredChannels = errorStatus.errorData.channels; // List of channels for which error reported (mostly because of Access Manager)
    NSArray<NSString *> *erroredChannelGroups = errorStatus.errorData.channelGroups; // List of channel groups for which error reported (mostly because of Access Manager)
    NSString *errorInformation = errorStatus.errorData.information; // Stringified information about error
    id errorData = errorStatus.errorData.data; // Additional error information from PubNub service
}
```

#### Remove listeners

```objectivec
[pubnub removeListener:self]
```

:::note Objective-C statements
Objective-C statements require a trailing semicolon in implementation files.
:::

#### Handling disconnects

The SDK automatically reconnects and reports status. You can stop automatic retries.

```objectivec
- (void)client:(PubNub *)pubnub didReceiveStatus:(PNStatus *)status {
  if (status.isError && status.willAutomaticallyRetry) {
    // Stop automatic retry attempts.
    [status cancelAutomaticRetry];
  }
}
```

#### Listener status events

| Category | Description |
| --- | --- |
| `PNAcknowledgmentCategory` | An API call was successful. This status has additional details based on the type of the successful operation. |
| `PNAccessDeniedCategory` | Access Manager permission failure. |
| `PNTimeoutCategory` | Server didn't respond in time for reported operation request. |
| `PNNetworkIssuesCategory` | No internet connection. |
| `PNRequestMessageCountExceededCategory` | Reported when received message count exceeds `requestMessageCountThreshold`. |
| `PNConnectedCategory` | The SDK subscribed to new channels / channel groups. |
| `PNReconnectedCategory` | The SDK was able to reconnect to PubNub. |
| `PNDisconnectedCategory` | The SDK unsubscribed from channels / channel groups. |
| `PNUnexpectedDisconnectCategory` | Unexpected loss of live updates from PubNub. |
| `PNRequestURITooLongCategory` | Request URI too long (too many channels or channel groups). |
| `PNMalformedFilterExpressionCategory` | Malformed filtering expression. |
| `PNMalformedResponseCategory` | Unexpected service response. |
| `PNDecryptionErrorCategory` | Decryption failed using the configured `cipherKey`. |
| `PNTLSConnectionFailedCategory` | Secure (TLS) connection failed. |
| `PNTLSUntrustedCertificateCategory` | Untrusted certificate chain. |

## UserID

Set the user ID at runtime.

### Method(s)

```objectivec
@property (nonatomic, copy, setter = setUserID:) NSString *userID;
```

### Sample code

:::note Required User ID
Always set the User ID (`userID`) to uniquely identify the user or device that connects to PubNub. Persist the value and keep it stable for the lifetime of the user or device. If you don't set the `userID`, the client cannot connect.
:::

```objectivec
// User authorized and we need to update used UUID
PNConfiguration *configuration = self.client.currentConfiguration;
configuration.userID = @"myUniqueUserID";

__weak __typeof(self) weakSelf = self;
[self.client copyWithConfiguration:configuration completion:^(PubNub *client) {

    weakSelf.client = client;
}];
```

### Other examples

#### Creating a function to subscribe a unique channel name

```objectivec
/**
    Subscription process results arrive to listener which should adopt to
    PNObjectEventListener protocol and registered using:
    */
[self.client addListener:self];
[self.client subscribeToChannels:@[[NSUUID UUID].UUIDString] withPresence:NO];

// Handle new message from one of channels on which client has been subscribed.
- (void)client:(PubNub *)client didReceiveMessage:(PNMessageResult *)message {

    // Handle new message stored in message.data.message
    if (![message.data.channel isEqualToString:message.data.subscription]) {

        // Message has been received on channel group stored in message.data.subscription.
    }
    else {

        // Message has been received on channel stored in message.data.channel.
    }

    NSLog(@"Received message: %@ on channel %@ at %@", message.data.message,
            message.data.channel, message.data.timetoken);
}

// Handle subscription status change.
- (void)client:(PubNub *)client didReceiveStatus:(PNStatus *)status {

    if (status.operation == PNSubscribeOperation) {

        // Check whether received information about successful subscription or restore.
        if (status.category == PNConnectedCategory || status.category == PNReconnectedCategory) {

            // Status object for those categories can be casted to `PNSubscribeStatus` for use below.
            PNSubscribeStatus *subscribeStatus = (PNSubscribeStatus *)status;
            if (subscribeStatus.category == PNConnectedCategory) {

                // This is expected for a subscribe, this means there is no error or issue whatsoever.
            }
            else {

                /**
                    This usually occurs if subscribe temporarily fails but reconnects. This means there was
                    an error but there is no longer any issue.
                    */
            }
        }
        else if (status.category == PNUnexpectedDisconnectCategory) {

            /**
                This is usually an issue with the internet connection, this is an error, handle
                appropriately retry will be called automatically.
                */
        }
        // Looks like some kind of issues happened while client tried to subscribe or disconnected from
        // network.
        else {

            PNErrorStatus *errorStatus = (PNErrorStatus *)status;
            if (errorStatus.category == PNAccessDeniedCategory) {

                /**
                    This means that Access Manager does allow this client to subscribe to this channel and channel group
                    configuration. This is another explicit error.
                    */
            }
            else {

                /**
                    More errors can be directly specified by creating explicit cases for other error categories
                    of `PNStatusCategory` such as: `PNDecryptionErrorCategory`,
                    `PNMalformedFilterExpressionCategory`, `PNMalformedResponseCategory`, `PNTimeoutCategory`
                    or `PNNetworkIssuesCategory`
                    */
            }
        }
    }
}
```

#### Creating a unique auth_key for Access Manager on initialization

```objectivec
PNConfiguration *configuration = self.client.currentConfiguration;
configuration.authKey = [NSUUID UUID].UUIDString.lowercaseString;

__weak __typeof(self) weakSelf = self;
[self.client copyWithConfiguration:configuration completion:^(PubNub *client) {

    // Store reference on new client with updated configuration.
    weakSelf.client = client;
}];
```

## Authentication key

Set and get the auth key.

### Method(s)

#### Authentication key

```objectivec
@property (nonatomic, nullable, copy) NSString *authKey;
```

#### UserID

```objectivec
@property (nonatomic, copy, setter = setUserID:) NSString *userID;
```

### Sample code

#### Set auth key

```objectivec
PNConfiguration *configuration = self.client.currentConfiguration;
configuration.authKey = @"my_new_authkey";

__weak __typeof(self) weakSelf = self;
[self.client copyWithConfiguration:configuration completion:^(PubNub *client) {

    // Store reference on new client with updated configuration.
    weakSelf.client = client;
}];
```

#### Get auth key

```objectivec
// Request current client configuration and pull out authorisation key from it.
NSString *authorizationKey = self.client.currentConfiguration.authKey;
```

### Returns

`Get Auth key` returns the `current authentication key`.

## Filter expression

:::note Requires Stream Controller add-on
This method requires that the *Stream Controller* add-on is enabled for your key in the [Admin Portal](https://admin.pubnub.com/). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

Stream filtering lets a subscriber receive only messages that match the filter. The filter runs on the server, so non‑matching messages never reach the client.

Use the following property to set or get the filter. For details, see [Publish Messages](https://www.pubnub.com/docs/general/messages/publish).

### Method(s)

```objectivec
@property (nonatomic, nullable, copy) NSString *filterExpression;
```

### Sample code

#### Set filter expression

:::note Required User ID
Always set the User ID (`userID`) to uniquely identify the user or device that connects to PubNub. Persist the value and keep it stable for the lifetime of the user or device. If you don't set the `userID`, the client cannot connect.
:::

```objectivec
PNConfiguration *configuration = [PNConfiguration configurationWithPublishKey:@"demo"
                                                                 subscribeKey:@"demo"
                                                                       userID:@"myUserID"];
self.client = [PubNub clientWithConfiguration:configuration];
self.client.filterExpression = @"(senderID=='PubNub')";
```

#### Get filter expression

```objectivec
NSLog(@"Filtering expression: %@", self.client.filterExpression);
```

### Returns

Returns the current filter expression.

:::warning
If filter expression is malformed, `PNObjectEventListener` won't receive any messages and presence events from service (only error status).
:::

## Terms in this document

* **Origin** - The subdomain used to establish a connection to the PubNub network that allows your application's traffic to appear like it's coming from your own domain.
* **PubNub** - PubNub is a real-time messaging platform that provides APIs and SDKs for building scalable applications. It handles the complex infrastructure of real-time communication, including: Message delivery and persistence, Presence detection, Access control, Push notifications, File sharing, Serverless processing with Functions and Events & Actions, Analytics and monitoring with BizOps Workspace, AI-powered insights with Illuminate.
* **Timetoken** - A unique identifier for each message that represents the number of 100-nanosecond intervals since January 1, 1970, for example, 16200000000000000.
* **User** - An individual or entity that interacts with a system, application, or service. In PubNub, a user typically refers to someone who sends or receives messages through the platform, identified by a unique user ID or username.
* **User ID** - UTF-8 encoded, unique string of up to 92 characters used to identify a single client (end user, device, or server) that connects to PubNub.