import Combine
import StreamFeeds
class MyViewController: UIViewController {
@State private var cancellables = Set<AnyCancellable>()
let feedsClient: FeedsClient
override func viewDidLoad() {
super.viewDidLoad()
setupEventListening()
}
private func setupEventListening() {
feedsClient.eventPublisher
.sink { event in
self.handleEvent(event)
}
.store(in: &cancellables)
}
private func handleEvent(_ event: Event) {
switch event {
case let activityEvent as ActivityAddedEvent:
print("📝 New activity: \(activityEvent.activity.id)")
updateFeedUI()
case let pollEvent as PollClosedFeedEvent:
print("📊 Poll closed: \(pollEvent.poll.id)")
refreshPollData()
case let commentEvent as CommentAddedEvent:
print("💬 New comment: \(commentEvent.comment.id)")
updateCommentsUI()
case let reactionEvent as ActivityReactionAddedEvent:
print("👍 Reaction added: \(reactionEvent.reaction.kind)")
updateReactionsUI()
case let followEvent as FollowCreatedEvent:
print("👥 New follow: \(followEvent.follow.target)")
updateFollowCount()
case let bookmarkEvent as BookmarkAddedEvent:
print("🔖 Bookmark added: \(bookmarkEvent.bookmark.id)")
updateBookmarksUI()
case let feedEvent as FeedCreatedEvent:
print("📋 Feed created: \(feedEvent.fid)")
refreshFeedList()
case let connectedEvent as ConnectedEvent:
print("🔗 Connected to Stream with ID: \(connectedEvent.connectionId)")
case let errorEvent as ConnectionErrorEvent:
print("❌ Connection error: \(errorEvent.error)")
handleConnectionError()
default:
print("📡 Received event: \(type(of: event))")
}
}
}Event Handling
This document explains how to listen to real-time events from Stream Feeds using the FeedsClient event publisher.
Overview
The FeedsClient provides two ways to listen to events:
- All Events: Listen to all events and handle them with type checking
- Specific Event Types: Listen to only specific event types for type-safe handling
Listening to All Events
Use the main eventPublisher to receive all events and handle them with type checking:
Listening to Specific Event Types
For type-safe event handling, use the generic eventPublisher(for:) method:
class ActivityHandler {
private var cancellables = Set<AnyCancellable>()
let feedsClient: FeedsClient
init(feedsClient: FeedsClient) {
self.feedsClient = feedsClient
setupActivityListeners()
}
private func setupActivityListeners() {
// Listen only to activity added events
feedsClient.eventPublisher(for: ActivityAddedEvent.self)
.sink { activityEvent in
print("New activity: \(activityEvent.activity.id)")
self.handleNewActivity(activityEvent)
}
.store(in: &cancellables)
// Listen only to activity updated events
feedsClient.eventPublisher(for: ActivityUpdatedEvent.self)
.sink { activityEvent in
print("Activity updated: \(activityEvent.activity.id)")
self.handleActivityUpdate(activityEvent)
}
.store(in: &cancellables)
// Listen only to activity deleted events
feedsClient.eventPublisher(for: ActivityDeletedEvent.self)
.sink { activityEvent in
print("Activity deleted: \(activityEvent.activity.id)")
self.handleActivityDeletion(activityEvent)
}
.store(in: &cancellables)
}
private func handleNewActivity(_ event: ActivityAddedEvent) {
// Handle new activity
}
private func handleActivityUpdate(_ event: ActivityUpdatedEvent) {
// Handle activity update
}
private func handleActivityDeletion(_ event: ActivityDeletedEvent) {
// Handle activity deletion
}
}Multiple Event Type Listeners
You can set up multiple listeners for different event types:
class FeedManager {
private var cancellables = Set<AnyCancellable>()
let feedsClient: FeedsClient
init(feedsClient: FeedsClient) {
self.feedsClient = feedsClient
setupEventListeners()
}
private func setupEventListeners() {
// Activity events
feedsClient.eventPublisher(for: ActivityAddedEvent.self)
.sink { [weak self] event in
self?.handleActivityAdded(event)
}
.store(in: &cancellables)
// Comment events
feedsClient.eventPublisher(for: CommentAddedEvent.self)
.sink { [weak self] event in
self?.handleCommentAdded(event)
}
.store(in: &cancellables)
// Poll events
feedsClient.eventPublisher(for: PollVoteCastedFeedEvent.self)
.sink { [weak self] event in
self?.handlePollVote(event)
}
.store(in: &cancellables)
// Connection events
feedsClient.eventPublisher(for: ConnectedEvent.self)
.sink { [weak self] event in
self?.handleConnection(event)
}
.store(in: &cancellables)
}
}SwiftUI Integration
Here's how to listen to events in SwiftUI:
struct FeedView: View {
@StateObject private var viewModel: FeedViewModel
@State private var cancellables = Set<AnyCancellable>()
var body: some View {
List(viewModel.activities) { activity in
ActivityRow(activity: activity)
}
.onAppear {
setupEventListening()
}
.onDisappear {
cancellables.removeAll()
}
}
private func setupEventListening() {
viewModel.feedsClient.eventPublisher(for: ActivityAddedEvent.self)
.receive(on: DispatchQueue.main)
.sink { event in
viewModel.addActivity(event.activity)
}
.store(in: &cancellables)
viewModel.feedsClient.eventPublisher(for: ActivityUpdatedEvent.self)
.receive(on: DispatchQueue.main)
.sink { event in
viewModel.updateActivity(event.activity)
}
.store(in: &cancellables)
}
}Available Event Types
Below is a comprehensive table of all available event types and their descriptions:
| Event Name | Description |
|---|---|
| Activity Events | |
ActivityAddedEvent | Fired when a new activity is added to a feed |
ActivityUpdatedEvent | Fired when an activity is modified |
ActivityDeletedEvent | Fired when an activity is removed |
ActivityRestoredEvent | Fired when an activity is restored |
ActivityRemovedFromFeedEvent | Fired when an activity is removed from a specific feed |
ActivityMarkEvent | Fired when activities are marked as read/seen |
ActivityPinnedEvent | Fired when an activity is pinned to the top |
ActivityUnpinnedEvent | Fired when an activity is unpinned |
| Comment Events | |
CommentAddedEvent | Fired when a new comment is added to an activity |
CommentUpdatedEvent | Fired when a comment is modified |
CommentDeletedEvent | Fired when a comment is removed |
| Reaction Events | |
ActivityReactionAddedEvent | Fired when a reaction is added to an activity |
ActivityReactionDeletedEvent | Fired when a reaction is removed from an activity |
CommentReactionAddedEvent | Fired when a reaction is added to a comment |
CommentReactionDeletedEvent | Fired when a reaction is removed from a comment |
| Poll Events | |
PollClosedFeedEvent | Fired when a poll is closed |
PollDeletedFeedEvent | Fired when a poll is deleted |
PollUpdatedFeedEvent | Fired when a poll is modified |
PollVoteCastedFeedEvent | Fired when a vote is cast |
PollVoteChangedFeedEvent | Fired when a vote is changed |
PollVoteRemovedFeedEvent | Fired when a vote is removed |
| Feed Events | |
FeedCreatedEvent | Fired when a new feed is created |
FeedUpdatedEvent | Fired when a feed is modified |
FeedDeletedEvent | Fired when a feed is deleted |
FeedGroupChangedEvent | Fired when a feed group is modified |
FeedGroupDeletedEvent | Fired when a feed group is deleted |
| Member Events | |
FeedMemberAddedEvent | Fired when a member is added to a feed |
FeedMemberRemovedEvent | Fired when a member is removed from a feed |
FeedMemberUpdatedEvent | Fired when a member's role/permissions change |
| Follow Events | |
FollowCreatedEvent | Fired when a follow relationship is created |
FollowDeletedEvent | Fired when a follow relationship is removed |
FollowUpdatedEvent | Fired when follow settings are modified |
| Bookmark Events | |
BookmarkAddedEvent | Fired when an activity is bookmarked |
BookmarkDeletedEvent | Fired when a bookmark is removed |
BookmarkUpdatedEvent | Fired when bookmark metadata is modified |
| Connection Events | |
ConnectedEvent | Fired when successfully connected to WebSocket |
ConnectionErrorEvent | Fired when connection fails or errors occur |
HealthCheckEvent | Fired when health check is received |
Server-side webhooks
Webhooks are configured with your API secret, so they belong on your backend rather than in the app you ship. Setting up an endpoint, verifying signatures, retries and event failover are covered under Event handling in the server-side docs, with the full transport reference in the platform webhooks guide.