Create message drafts

A MessageDraft object is an abstraction for composing a message that has not yet been published. You can use it to:

You can display user mentions, channel references, and links (collectively called "message elements") to the user on the front end of your application by adding a message draft change listener.

Message drafts consist of MessageElement objects, which can be either instances of plainText or link.

plainText are simple strings, while link elements are used for user mentions, channel references, and URLs. They contain a text and a reference to the linked element regardless if it's a user, a channel, or a URL.

Each link implements a MentionTarget interface, which defines the type of mention. Available targets include:

  • MentionTarget.user(userId: String)
  • MentionTarget.channel(channelId: String)
  • MentionTarget.url(url: String)
Store draft messages locally

Swift Chat SDK does not provide a method for storing the drafted message on the client, so whenever a user drafts a message in a chat app, changes a channel, and goes back to that channel, the drafted message gets lost.

To save drafted messages before they are published on channels, implement your own local storage mechanism suitable for the platform you use.

Create a draft message

createMessageDraft() creates a message draft (MessageDraft object) that can consist of:

Method signature

This method has the following signature:

channel.createMessageDraft(
userSuggestionSource: UserSuggestionSource = .channel,
isTypingIndicatorTriggered: Bool = true,
userLimit: Int = 10,
channelLimit: Int = 10
) -> MessageDraftImpl

Input

ParameterTypeRequiredDefaultDescription
userSuggestionSourceUserSuggestionSource = .channel or UserSuggestionSource = .globalNoUserSuggestionSource = .channelThis parameter refers to the Mentions feature. Data source from which you want to retrieve users. You can choose either the list of channel members (.channel) or users on the app's Admin Portal keyset (.global).
isTypingIndicatorTriggeredBoolNotrueThis parameter refers to the Typing Indicator feature. Defines if the typing indicator should be enabled when writing the message.
userLimitIntNo10This parameter refers to the Mentions feature. Maximum number of usernames (name field from the User object) you can mention in one message (the default value is 10 and max is 100).
channelLimitIntNo10This parameter refers to the References feature. Maximum number of channel names (name field from the Channel object) you can reference in one message (the default value is 10 and max is 100).

Output

TypeDescription
MessageDraftTypeInstance of MessageDraftType, which represents a draft version of a message with the content, all links, referenced channels, mentioned users and their names.

Basic usage

Create a draft message containing just plain text.

let messageDraft = channel.createMessageDraft(isTypingIndicatorTriggered: channel.type != .public)

Add message draft change listener

Add a MessageDraftChangeListener to listen for changes to the contents of a message draft, as well as to retrieve the current message elements suggestions for user mentions, channel reference, and links. For example, when the message draft contains ... @name ... or ... #chann ....

Method signature

This method has the following signature:

messageDraft.addChangeListener(_ listener: MessageDraftChangeListener)

public protocol MessageDraftChangeListener: AnyObject {

/// Called when there is a change in the message elements or suggested mentions.
func onChange(messageElements: [MessageElement], suggestedMentions: any FutureObject<[SuggestedMention]>)
}

Input

ParameterTypeDescription
_ listenerMessageDraftChangeListenerThe listener that receives the most current message elements and suggestions list.
MessageDraftChangeListener
ParameterTypeDescription
onChange(messageElements: [MessageElement], suggestedMentions: any FutureObject<[SuggestedMention]>)function
  • messageElements: [MessageElement] - this parameter is a list of MessageElement objects, representing the current state of the message draft. This could contain a mix of plain text and links, channel references, or user mentions.
  • suggestedMentions: any FutureObject<[SuggestedMention]> - this parameter is a FutureObject containing a list of SuggestedMention objects. These are potential suggestions for message elements based on the current text in the draft.
SuggestedMention

A SuggestedMention represents a potential mention suggestion received from MessageDraftChangeListener.

ParameterTypeDescription
offsetIntThe position from the start of the message draft where the message elements starts. It's counted from the beginning of the message (including spaces), with 0 as the first character.
replaceFromStringThe original text at the given offset in the message draft text.
replaceWithStringThe suggested replacement for the replaceFrom text.
targetMentionTargetThe message element type. Available types include:

  • MentionTarget.user(userId: String)
  • MentionTarget.channel(channelId: String)
  • MentionTarget.url(url: String)

Output

This method doesn't return any data.

Basic usage

Add the listener to your message draft.

// Create a message draft
let messageDraft = channel?.createMessageDraft(isTypingIndicatorTriggered: channel?.type != .public)
// Add the listener
let listener = ClosureMessageDraftChangeListener() { elements, suggestedMentions in
updateUI(with: elements) // updateUI is your own function for updating UI

suggestedMentions.async { result in
switch result {
case .success(let mentions):
updateSuggestions(with: mentions) // updateSuggestions is your own function for displaying suggestions
case .failure(let error):
print("Error retrieving suggestions: \(error)")
}
}
}
show all 17 lines

Remove message draft change listener

Remove a previously added MessageDraftChangeListener.

Method signature

This method has the following signature:

messageDraft.removeChangeListener(_ listener: MessageDraftChangeListener)

Input

ParameterTypeDescription
_ listenerMessageDraftChangeListenerThe listener to remove.

Output

This method doesn't return any data.

Basic usage

Remove a listener from your message draft.

// Create a message draft
let messageDraft = channel?.createMessageDraft(isTypingIndicatorTriggered: channel?.type != .public)
// Define the listener as a closure
let listener = ClosureMessageDraftChangeListener() { elements, suggestedMentions in
updateUI(with: elements) // updateUI is your own function for updating UI

suggestedMentions.async { result in
switch result {
case .success(let mentions):
updateSuggestions(with: mentions) // updateSuggestions is your own function for displaying suggestions
case .failure(let error):
print("Error retrieving suggestions: \(error)")
}
}
}
show all 19 lines

Add message element

addMention() adds a user mention, channel reference or a link specified by a mention target at a given offset.

Method signature

This method has the following signature:

messageDraft.addMention(
offset: Int,
length: Int,
target: MentionTarget
)

Input

ParameterTypeRequiredDefaultDescription
offsetIntYesn/aPosition of a character in a message where the message element you want to insert starts. It's counted from the beginning of the message (including spaces), with 0 as the first character.
lengthIntYesn/aNumber of characters the message element should occupy in the draft message's text.
targetMentionTargetYesn/aMessage element type. Available types include:

  • MentionTarget.user(userId: String)
  • MentionTarget.channel(channelId: String)
  • MentionTarget.url(url: String)

Output

This method returns no output data.

Basic usage

Create the Hello Alex! I have sent you this link on the #offtopic channel. message where Alex is a user mention, link is a URL, and #offtopic is a channel reference.

// Create an empty message draft
if let messageDraft = channel?.createMessageDraft(isTypingIndicatorTriggered: channel?.type != .public) {

// Add initial text
messageDraft.update(text: "Hello Alex!")

// Add a user mention to the string "Alex"
messageDraft.addMention(offset: 6, length: 4, target: .user(userId: "alex_d"))

// Change the text
messageDraft.update(text: "Hello Alex! I have sent you this link on the #offtopic channel.")

// Add a URL mention to the string "link"
messageDraft.addMention(offset: 33, length: 4, target: .url(url: "www.pubnub.com"))

show all 18 lines

Remove message element

removeMention() removes a user mention, channel reference, or a link at a given offset.

Method signature

This method has the following signature:

messageDraft.removeMention(offset: Int)

Input

ParameterTypeRequiredDefaultDescription
offsetIntYesn/aPosition of the first character of the message element you want to remove.
Offset value

If you don't provide the position of the first character of the message element to remove, it isn't removed.

Output

This method returns no output data.

Basic usage

Remove the URL element from the word link in the Hello Alex! I have sent you this link on the #offtopic channel. message.

// assume the message reads
// Hello Alex! I have sent you this link on the #offtopic channel.

// remove the link mention
messageDraft?.removeMention(offset: 33)

Update message text

update() lets you replace the text of a draft message with new content.

Removing message elements

As a best effort, the optimal set of insertions and removals that converts the current text to the provided text is calculated to preserve any message elements.

If any message element text is found to be modified in the updated text, the message element is removed.

Method signature

This method has the following signature:

messageDraft.update(text: String)

Input

ParameterTypeRequiredDefaultDescription
textstringYesn/aText of the message that you want to update.

Output

This method returns no output data.

Basic usage

Change the message I sent Alex this picture. to I did not send Alex this picture. where Alex is a user mention.

// the message reads:
// I sent [Alex] this picture.
// where [Alex] is a user mention
messageDraft?.update(text: "I did not send Alex this picture.")
// the message now reads:
// I did not send [Alex] this picture.
// the mention is preserved because its text wasn't changed
Mention text changes

If you decided to change the name Alex to some other name, the mention would be removed because your updated text's index coincided with an existing mention.

For more manual control over inserting and removing parts of a message, refer to Insert message text and Remove message text.

Insert suggested message element

Inserts a message element returned by the MessageDraftChangeListener into the MessageDraft.

Text must match

The SuggestedMention must be up to date with the message text, that is, SuggestedMention.replaceFrom must match the message draft at position SuggestedMention.replaceFrom, otherwise an exception is thrown.

Method signature

This method has the following signature:

messageDraft.insertSuggestedMention(
mention: SuggestedMention,
text: String
)

Input

ParameterTypeRequiredDefaultDescription
mentionSuggestedMentionYesn/aA user, channel, or URL suggestion obtained from MessageDraftChangeListener.
textstringYesn/aThe text you want the message element to display.

Output

This method returns no output data.

Basic usage

Register a listener and insert a suggested element.

Suggested change
// Create a message draft
let messageDraft = channel?.createMessageDraft(isTypingIndicatorTriggered: channel?.type != .public)
// Add the listener
let listener: ([MessageElement], FutureObject<[SuggestedMention]>) -> Void = { elements, suggestedMentions in
updateUI(elements) // updateUI is your own function for updating the UI
suggestedMentions.async { result in
switch result {
case .success(let mentions):
updateSuggestions(mentions) // updateSuggestions is your own function for displaying suggestions
case .failure(let error):
print("Error retrieving suggestions: \(error)")
}
}
}
show all 40 lines

Insert message text

insertText() lets you insert plain text in the draft message at a given offset from the beginning of the message.

Removing message elements

If the position of the text you want to insert corresponds to an existing message element, this element is removed.

Method signature

This method has the following signature:

messageDraft.insertText(
offset: Int,
text: String
)

Input

ParameterTypeRequiredDefaultDescription
offsetIntYesn/aPosition of a character in a message where the text you want to insert starts. It's counted from the beginning of the message (including spaces), with 0 as the first character.
textstringYesn/aText that you want to insert.

Output

This method returns no output data.

Basic usage

In the message Check this support article https://www.support-article.com/., add the word out between the words Check and this.

// The message reads:
// Check this support article https://www.support-article.com/.
messageDraft?.insertText(offset: 6, text: "out ")
// The message now reads:
// Check out this support article https://www.support-article.com/.

Remove message text

removeText() lets you remove plain text from the draft message at a given offset from the beginning of the message.

Removing message elements

If the position of the text you want to remove corresponds to an existing message element, this element is removed.

Method signature

This method has the following signature:

messageDraft.removeText(
offset: Int,
length: Int
)

Input

ParameterTypeRequiredDefaultDescription
offsetIntYesn/aPosition of a character in a message where the text you want to insert starts. It's counted from the beginning of the message (including spaces), with 0 as the first character.
lengthIntYesn/aHow many characters to remove, starting at the given offset.

Output

This method returns no output data.

Basic usage

In the message Check out this support article https://www.support-article.com/., remove the word out.

// The message reads:
// Check out this support article https://www.support-article.com/.
messageDraft?.removeText(offset: 5, length: 4)
// The message now reads:
// Check this support article https://www.support-article.com/.

Send a draft message

send() publishes the draft text message with all mentioned users, links, and referenced channels.

Whenever you mention any users, send() also emits events of type mention.

Method signature

This method has the following signature:

messageDraft.send(
meta: [String: JSONCodable]? = null,
shouldStore: Bool = true,
usePost: Bool = false,
ttl: Int? = null,
completion: ((Swift.Result<Timetoken, Error>) -> Void)? = nil
)

Input

ParameterTypeRequiredDefaultDescription
meta[String: JSONCodable]Non/aAdditional details of the request.
shouldStoreBoolNotrueIf true, the messages are stored in Message Persistence (PubNub storage).
If shouldStore is not specified, the Message Persistence configuration specified on the Admin Portal keyset is used.
usePostBoolNofalseWhen true, the SDK uses HTTP POST to publish the messages. The message is sent in the BODY of the request instead of the query string when HTTP GET is used. The messages are also compressed to reduce their size.
ttlInt?Non/aDefines if / how long (in hours) the message should be stored in Message Persistence.
  1. If shouldStore = true, and ttl = 0, the message is stored with no expiry time.
  2. If shouldStore = true and ttl = X, the message is stored with an expiry time of X hours.
  3. If shouldStore = false, the ttl parameter is ignored.
  4. If ttl is not specified, then the expiration of the message defaults back to the expiry value for the keyset.

Suppose a user adds elements to the message draft, such as links, quotes, other user mentions, or channel references. In that case, these are not explicitly passed in the send() method but get added to the MessageDraft object through the addMention() and addQuote() methods.

Output

TypeDescription
TimetokenTimetoken of the message.

Basic usage

Send a draft message containing just plain text.

// Create a message draft
if let messageDraft = channel?.createMessageDraft(isTypingIndicatorTriggered: channel?.type != .public) {

// Add text
messageDraft.update(text: "Hello!")

// Send the message
messageDraft.send()
}
Last updated on