Feedback

iOSiOSCocoaSwiftPubNub iOS Swift SDK 4.5.15

CocoaPods is a dependency manager and this is by far the easiest and quickest way to get started with PubNub SDK! (If you don't have pods installed yet you can check CocoaPods installation section for installation guide).

Be sure you are running CocoaPods 1.0.0 or above! You can install the latest cocopods gem:

gem install cocoapods

If you’ve already installed you can upgrade to the latest CocoaPods gem using:

gem update cocoapods
To build the framework as a standalone bundle and integrate into project, perform the following:
  1. Clone the PubNub master repository
    git clone git@github.com:pubnub/objective-c.git
    
  2. Navigate to root of the cloned repository
  3. Run the CocoaPods pod install command to pull out all required dependencies
    pod install
    
  4. Open the PubNub.xcworkspace from the PubNub repository in Xcode.
  5. Select the Framework or Universal Framework target for target platform and hit Cmd+B to build the selected type of framework.
    Select Framework target

  6. Navigate to the Framework directory and find the Products directory.
    Navigate to Framework bundle
  7. Drag&Drop PubNub.framework bundle from the Products directory to your application.
    Drag & drop Framework bundle Swift
  8. Select the Copy items if needed checkbox and click Finish.
    Copy Framework bundle
  9. Open your project's General tab and scroll to Embedded Binaries.
    Open embedded binaries group Swift
  10. Click on + and select PubNub.framework file.
    Add Framework bundle to embedded binaries group
 
If the PubNub target has been used, then the framework will be generated only for the selected platform (device or simulator.) If you try to use the framework to compile for another platform, it will crash during run-time! Using the PubNub-Universal build target (which can be used on both device and simulator) will help mitigate any sort of crash scenarios during development.

Now that these steps are complete, let's learn more about how to use the framework in your app.

At this point, you should have the framework added to your application project, we'll need to make your project aware of the PubNub framework.

You need to import the PubNub module in files where it will be used.

import PubNub

To build the framework as a standalone bundle and integrate into project, perform the following:

  1. Install latest Carthage (if required).
  2. Create a Cartfile(any location can be used) or use existing file.
    		touch Cartfile		
  3. Add next line into a Cartfile which will allow to build framework bundles.
    		github "pubnub/objective-c" ~> 4.1		
  4. Update and rebuild the project's dependencies (update command ensure what latest PubNub client code will be used to build framework). build can be used if frameworks has been built before and it will be much faster because git clone will be skipped.
    		carthage update		

    Command above will build framework for all configured platforms, but if only one required it can be called like this

    		carthage update --platform ios		

    Instead of ios can be used: mac, tvos or watchos

  5. Navigate to the Carthage directory and find the Build directory.
  6. Navigate to directory which represent your target platform. For example: iOS

    For Carthage navigate to Framework bundle carthage
  7. Drag&Drop PubNub.framework bundle from the Products directory to your application.

    For Carthage drag & drop Framework bundle Swift
  8. Select the Copy items if needed checkbox and click Finish.

    For Carthage copy Framework bundle
  9. Open your project's General tab and scroll to Embedded Binaries.

    For Carthage open embedded binaries group Swift
  10. Click on + and select PubNub.framework file.

    For Carthage add Framework bundle to embedded binaries group

At this point, you should have the framework added to your application project, we'll need to make your project aware of the PubNub framework.

You need to import the PubNub module in files where it will be used.

import PubNub

Install the CocoaPods gem by following the procedure defined under How to Get It.
To add the PubNub SDK to your project with CocoaPods, there are four tasks to complete:
  1. Create new Xcode project.

    Xcode project

  2. Create a Podfile in your newly created Xcode project root folder
    touch Podfile
  3. The PubNub client can be added as module (only with a deployment target of iOS 8.0 and above) or as a static library (for deployment targets of iOS 7.0 and above).
    1. For a deployment target of iOS 8.0 and above use:
      source 'https://github.com/CocoaPods/Specs.git'
      
      # optionally complete and uncomment if compilation issues arise
      # project '<path to project relative to this Podfile>/<name of project without extension>'
      # workspace 'MyPubNubProject'
      
      use_frameworks!
      
      target 'application-target-name' do
          # Should only use this with projects 
          # that must have a minimum deployment 
          # target of iOS 8 
          platform :ios, '8.0' # (or '9.0' or '10.0')
          pod "PubNub", "~> 4"
      end
    2. For a deployment target of iOS 7.0 and above use:
      source 'https://github.com/CocoaPods/Specs.git'
      
      # optionally complete and uncomment if compilation issues arise
      # project '<path to project relative to this Podfile>/<name of project without extension>'
      # workspace 'MyPubNubProject'
       
      target 'application-target-name' do
          # Should only use this with projects 
          # that must have a minimum deployment 
          # target of iOS 7 
          platform :ios, '7.0' # (if you don't need to use iOS 7, then see other Podfile)
          pod "PubNub", "~> 4"
      end
      If you have any other pods you'd like to include, or if you have other targets you'd to add (like a test target) add those entries to this Podfile as well. See the CocoaPods documentation for more information on Podfile configuration.
  4. Install your pods by running pod install via the command line from the directory that contains your Podfile.

 
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!

By creating the Podfile and running pod install in the same directory as your Podfile, you should now have a Swift project with the PubNub SDK installed. To access the PubNub Objective-C SDK with the deployment target set to iOS 7.0 and below, you will need to create a bridging header.
The bridging header is a way to make the Swift code aware of the available Objective-C interface to the PubNub client. To create your bridging header:
  1. Create a new File (File → New → File) of type Source → Header File

    Create a new File

  2. Specify a location and name (along the lines of [MyProjectName]-Bridging-Header.h) and create the file

    Specify a location and name

  3. Make your project aware of this newly created bridging header by opening your project, selecting Build Settings, and using the search box to find Objective-C Bridging Header

    Objective-C Bridging Header

  4. Specify the path to the bridging header. The location is relative to the project / workspace files location.

    Specify the path to the bridging header

  5. Select your bridging file from project tree (replace if new, add if existing) with:
    #import <PubNub/PubNub.h>
    The convention for bridging headers in Swift is to use a single bridging header file per project -- if you have other Pods included in your project that are written in Objective-C, they would be imported here as well.
If the project’s deployment target is set to iOS 8.0 and above, you will need to import the module named AppDelegate.swift:
import UIKit
import PubNub // <- Here is our PubNub module import.
	
class AppDelegate: UIResponder, UIApplicationDelegate, PNObjectEventListener {

	// Stores reference on PubNub client to make sure what it won't be released.
	var client: PubNub!

	func application(_ application: UIApplication, 
					 didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
		...
	}
}
	
// Initialize and configure PubNub client instance
let configuration = PNConfiguration(publishKey: "demo", subscribeKey: "demo")
self.client = PubNub.clientWithConfiguration(configuration)
self.client.addListener(self)

// Subscribe to demo channel with presence observation
self.client.subscribeToChannels(["my_channel"], withPresence: true)


// Handle new message from one of channels on which client has been subscribed.
func client(_ client: PubNub, didReceiveMessage message: PNMessageResult) {
		
	// Handle new message stored in message.data.message
	if message.data.channel != 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.
	}
	
	print("Received message: \(message.data.message) on channel \(message.data.channel) " +
		  "at \(message.data.timetoken)")
}

// New presence event handling.
func client(_ client: PubNub, didReceivePresenceEvent event: PNPresenceEventResult) {
	
	// Handle presence event event.data.presenceEvent (one of: join, leave, timeout, state-change).
	if event.data.channel != event.data.subscription {
		
		// Presence event has been received on channel group stored in event.data.subscription.
	}
	else {
		
		// Presence event has been received on channel stored in event.data.channel.
	}
	
	if event.data.presenceEvent != "state-change" {
		
		print("\(event.data.presence.uuid) \"\(event.data.presenceEvent)'ed\"\n" +
			  "at: \(event.data.presence.timetoken) on \(event.data.channel) " +
			  "(Occupancy: \(event.data.presence.occupancy))");
	}
	else {
		
		print("\(event.data.presence.uuid) changed state at: " +
			  "\(event.data.presence.timetoken) on \(event.data.channel) to:\n" +
			  "\(event.data.presence.state)");
	}
}

// Handle subscription status change.
func client(_ client: PubNub, didReceive status: PNStatus) {
	
	if status.operation == .subscribeOperation {
		
		// Check whether received information about successful subscription or restore.
		if status.category == .PNConnectedCategory || status.category == .PNReconnectedCategory {
			
			let subscribeStatus: PNSubscribeStatus = status as! PNSubscribeStatus
			if subscribeStatus.category == .PNConnectedCategory {
				
				// This is expected for a subscribe, this means there is no error or issue whatsoever.
				
				// Select last object from list of channels and send message to it.
				let targetChannel = client.channels().last!
				client.publish("Hello from the PubNub Swift SDK", toChannel: targetChannel,
							   compressed: false, withCompletion: { (publishStatus) -> Void in
								
					if !publishStatus.isError {
						
						// Message successfully published to specified channel.
					}
					else {
						
						/**
						 Handle message publish error. Check 'category' property to find out 
						 possible reason because of which request did fail.
						 Review 'errorData' property (which has PNErrorData data type) of status
						 object to get additional information about issue.
						 
						 Request can be resent using: publishStatus.retry()
						 */
					}
				})
			}
			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 {
			
			let errorStatus: PNErrorStatus = status as! PNErrorStatus
			if errorStatus.category == .PNAccessDeniedCategory {
				
				/**
				 This means that PAM 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`
				 */
			}
		}
	}
}
In addition to the Hello World sample code, we also provide some copy and paste snippets of common API functions:
Instantiate a new Pubnub instance. Only the subscribeKey is mandatory. Also include publishKey if you intend to publish from this instance, and the secret_key if you wish to perform PAM administrative operations from this Swift instance.
 
It is not a best practice to include the secret key in client-side code for security reasons.
let configuration = PNConfiguration(publishKey: "demo", subscribeKey: "demo")
self.client = PubNub.clientWithConfiguration(configuration)
 
The PubNub instance should be placed as a variable in a long-life object (otherwise the PubNub instance will be automatically removed as an autoreleased object.)

var client: PubNub!
Call timeWithCompletion() to verify the client connectivity to the origin:
self.client.timeWithCompletion({ (result, status) in

	if status == nil {

		// Handle downloaded server time token using: result.data.timetoken
	}
	else {

		/**
		 Handle time token download error. Check 'category' property to find 
		 out possible reason because of which request did fail.
		 Review 'errorData' property (which has PNErrorData data type) of status
		 object to get additional information about issue.
		
		 Request can be resent using: status.retry()
		 */
	}
})
Subscribe (listen on) a channel (it's async!):
/**
 Subscription process results arrive to listener which should adopt to PNObjectEventListener protocol
 and registered using:
 */
self.client.addListener(self)
self.client.subscribeToChannels(["my_channel1","my_channel2"], withPresence: false)


// Handle new message from one of channels on which client has been subscribed.
func client(_ client: PubNub, didReceiveMessage message: PNMessageResult) {
		
	// Handle new message stored in message.data.message
	if message.data.channel != 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.
	}
	
	print("Received message: \(message.data.message) on channel \(message.data.channel) " +
		  "at \(message.data.timetoken)")
}

// Handle subscription status change.
func client(_ client: PubNub, didReceive status: PNStatus) {
		
	if status.operation == .subscribeOperation {
		
		// Check whether received information about successful subscription or restore.
		if status.category == .PNConnectedCategory || status.category == .PNReconnectedCategory {
			
			let subscribeStatus: PNSubscribeStatus = status as! PNSubscribeStatus
			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 {
			
			let errorStatus: PNErrorStatus = status as! PNErrorStatus
			if errorStatus.category == .PNAccessDeniedCategory {
				
				/**
				 This means that PAM 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`
				 */
			}
		}
	}
	else if status.operation == .unsubscribeOperation {
		
		if status.category == .PNDisconnectedCategory {
			
			/**
			 This is the expected category for an unsubscribe. This means there was no error in 
			 unsubscribing from everything.
			 */
		}
	}
	else if status.operation == .heartbeatOperation {
		
		/**
		 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/ios-objective-c/api-reference#configuration_basic_usage
		 */
		
		if !status.isError { /* Heartbeat operation was successful. */ }
		else { /* There was an error with the heartbeat operation, handle here. */ }
	}
}
Publish a message to a channel:
self.client.publish("Hello from the PubNub Swift SDK", toChannel: "my_channel",
					compressed: false, withCompletion: { (status) in
						
	if !status.isError {
		
		// Message successfully published to specified channel.
	}
	else{
		
		/**
		 Handle message publish error. Check 'category' property to find 
		 out possible reason because of which request did fail.
		 Review 'errorData' property (which has PNErrorData data type) of status
		 object to get additional information about issue.
		 
		 Request can be resent using: status.retry()
		 */
	}
})
Get occupancy of who's here now on the channel by UUID:
Requires that the Presence add-on is enabled for your key. How do I enable add-on features for my keys? - see http://www.pubnub.com/knowledge-base/discussion/644/how-do-i-enable-add-on-features-for-my-keys
// With .UUID client will pull out list of unique identifiers and occupancy information.
self.client.hereNowForChannel("my_channel", withVerbosity: .UUID,
							  completion: { (result, status) in
										
	if status == nil {
		
		/**
		 Handle downloaded presence information using:
			result.data.uuids - list of uuids.
			result.data.occupancy - total number of active subscribers.
		 */
	}
	else {
		
		/**
		 Handle presence audit error. Check 'category' property to find
		 out possible reason because of which request did fail.
		 Review 'errorData' property (which has PNErrorData data type) of status
		 object to get additional information about issue.
		 
		 Request can be resent using: status.retry()
		 */
	}
})
Subscribe to realtime Presence events, such as join, leave, and timeout, by UUID. Setting the presence attribute to a callback will subscribe to presents events on my_channel:
Requires that the Presence add-on is enabled for your key. How do I enable add-on features for my keys? - see http://www.pubnub.com/knowledge-base/discussion/644/how-do-i-enable-add-on-features-for-my-keys
/**
 Subscription process results arrive to listener which should adopt to
 PNObjectEventListener protocol and registered using:
 */
self.client.addListener(self)
self.client.subscribeToPresenceChannels(["my_channel"])


// New presence event handling.
func client(_ client: PubNub, didReceivePresenceEvent event: PNPresenceEventResult) {
	
	// Handle presence event event.data.presenceEvent (one of: join, leave, timeout, state-change).
	if event.data.channel != event.data.subscription {
		
		// Presence event has been received on channel group stored in event.data.subscription.
	}
	else {
		
		// Presence event has been received on channel stored in event.data.channel.
	}
	
	if event.data.presenceEvent != "state-change" {
		
		print("\(event.data.presence.uuid) \"\(event.data.presenceEvent)'ed\"\n" +
			  "at: \(event.data.presence.timetoken) on \(event.data.channel) " +
			  "(Occupancy: \(event.data.presence.occupancy))");
	}
	else {
		
		print("\(event.data.presence.uuid) changed state at: " +
			  "\(event.data.presence.timetoken) on \(event.data.channel) to:\n" +
			  "\(event.data.presence.state)");
	}
}
Retrieve published messages from archival storage:
Requires that the Storage and Playback add-on is enabled for your key. How do I enable add-on features for my keys? - see http://www.pubnub.com/knowledge-base/discussion/644/how-do-i-enable-add-on-features-for-my-keys
self.client.historyForChannel("history_channel", withCompletion: { (result, status) in

	if status == nil {

		/**
		 Handle downloaded history using:
			result.data.start - oldest message time stamp in response
			result.data.end - newest message time stamp in response
			result.data.messages - list of messages
		 */
	}
	else {

		/**
		 Handle message history download error. Check 'category' property
		 to find out possible reason because of which request did fail.
		 Review 'errorData' property (which has PNErrorData data type) of status
		 object to get additional information about issue.

		 Request can be resent using: status.retry()
		 */
	}
})
Stop subscribing (listening) to a channel.
/**
 Subscription process results arrive to listener which should adopt to
 PNObjectEventListener protocol and registered using:
 */
self.client.addListener(self)
self.client.unsubscribeFromChannels(["my_channel1", "my_channel2"], withPresence: false)


// Handle subscription status change.
func client(_ client: PubNub, didReceive status: PNStatus) {

	if status.operation == .unsubscribeOperation && status.category == .PNDisconnectedCategory {
            
		/**
		 This is the expected category for an unsubscribe. This means there was no error in 
		 unsubscribing from everything.
		 */
	}
}
Check out PubNub's other Swift-based SDKs, such as Swift, Cocoa Swift.