AmityObject
instance for observing changes in a single object whereas Live Collection is represented by AmityCollection
instance for observing changes in a list of objects.
These generic classes encapsulate any other object and notify observers whenever any property of the encapsulated object changes.
Examples:
AmityObject<AmityPost>
, AmityCollection<AmityMessage>
, or AmityObject<AmityChannel>
.How it Works
SDK handles lots of data received from various sources. Data can be present in local cache. It might also be queried from the server or received from some real-time events. What this means is that same data is constantly updating. The data that you are accessing at the moment can get updated by other sources and becomes out of sync. Live Object and Live Collection help in syncing these constantly updating data, so you will always get the most recent one. Whenever the data gets updated, you will be notified through helper methods in live objects and live collection classes. New data gets automatically collected every time when there is an updation and the user need not refresh to get the recent data.Data Sources
Local Cache
Data present in local storage
Server Queries
Data queried from the server
Real-time Events
Data received from real-time events
AmityObject
and AmityCollection
provide methods for observing changes in objects. The life cycle of observation is tied to its token. As soon as the token is invalidated or deallocated, observation ends.
AmityNotificationToken
AmityNotificationToken
is a simple object which keeps track of what is being observed. Each Live Object or Live Collection observation is tied to its respective token. As soon as the token is invalidated or deallocated, observation ends. The token is declared within the scope of the class.
The token is used in combination with AmityObject or AmityCollection. We will explore it more in AmityObject and AmityCollection concepts.
AmityObject
AmityObject
is a generic class that keeps track of a single object. It is a live object. In iOS AmitySDK, any object which is encapsulated by AmityObject is a live object.
Examples: AmityObject<AmityMessage>
, AmityObject<AmityChannel>
AmityObject class exposes the following methods: observe
and observeOnce
. These methods help observe a live object. Whenever any property for the observed object changes, the observer is triggered.
Please make sure that the user is logged in before observing AmityObject. You can also refer to the session state section for more details.
Observer
observe
method can be triggered multiple times throughout the lifetime of the application as long as its associated AmityNotificationToken is retained in memory. observeOnce
method, on the other hand, can only be triggered once.
Both observe
and observeOnce
methods will be called from the main thread so you can perform any UI update-related tasks from within the observed block itself.
If the requested object data is stored locally on the device, the block will be called immediately with the local version of the data. This can be verified through the dataStatus property of AmityObject.
In parallel, a request is made to the server to fetch the latest version of the data. Once the data is returned, the observed block will be triggered again.
Any future changes to that data from any sources can trigger an observer.
Lifecycle: The life cycle of the observer is tied to its token. If the token is not retained, then the observer can get deallocated at any time and will not be called.
Observer Implementation
Observer Implementation
Invalidate Token
Invalidate Token
Accessing Objects
There are multiple ways to access data from AmityObject. AmityObject exposes the following properties:- dataStatus: Indicates whether the data is fresh or local
- loadingStatus: Indicates if the data is being loaded from server or not
- object: The actual object that is being tracked or encapsulated by this AmityObject
Basic Object Access
Basic Object Access
Fresh Data Only
Fresh Data Only
Direct Object Access
Direct Object Access
observe
or observeOnce
block depending on your requirement.observeOnce
method, if data is present locally, this observer will be triggered only once with that local data. If you are looking for fresh data, use the observe
block and invalidate the token once fresh data is received as shown above.
AmityLoadingStatus
AmityObject can be tracked for their loading status by accessing theloadingStatus
property, which is of type AmityLoadingStatus
and it can have one of four possible values.
- 0 (notLoading): Indicates that the data is already fresh locally and does not need to be loaded.
- 1 (loading): Indicates that the client is currently loading the data from the server.
- 2 (loaded): Indicates that the client has successfully loaded fresh data from the server and is up to date.
- 3 (error): Indicates that the data is unable to load due from a specific error.
AmityCollection
AmityCollection
is a generic class that keeps track of a collection of objects. It is a live collection. In iOS SDK, any object which is encapsulated by AmityCollection class is a live collection.
Examples: AmityCollection<AmityMessage>
, AmityCollection<AmityChannel>
AmityCollection exposes these methods: observe
and observeOnce
. These methods help to observe a live collection. Whenever any property for any object within the collection changes, the observer is triggered.
Please make sure that the user is logged in before observing AmityCollection. You can also refer to session state section for more details.
Observer
observe
method can get triggered multiple times throughout the lifetime of the application as long as it’s associated AmityNotificationToken is retained in memory. observeOnce
, on the other hand, can only be triggered once.
Both observe
and observeOnce
method will be called from the main thread so you can perform any UI update related task within the observe block itself.
If the requested data collection is stored locally on the device, the block will be called immediately with the local version of the data. This can be verified through the dataStatus property of AmityCollection.
In parallel, a request is made to the server to fetch the latest version of the data. Once the data is returned, the observe block will be triggered again.
Any future changes to the data from any sources can trigger observer.
Lifecycle: The life cycle of the observer for AmityCollection is also tied to its token. If the token is not retained, the observer can get deallocated at any time and will not be called.
Accessing Collection
Unlike most databases, AmityCollection does not return all data in an array. Instead, data is fetched one by one using theobjectAtIndex:
method. This allows the framework to store most of the actual result on disk, and load them in memory only when necessary.
AmityCollection also exposes a count
property which determines the number of objects present in a collection.
With these two public interfaces, you can create a robust list UI for your use case. Similar to AmityObject, AmityCollection also exposes dataStatus
and loadingStatus
property.
Basic Collection Access
Basic Collection Access
Pagination
Pagination
nextPage()
and previousPage()
method to fetch more data. It also exposes hasNext
and hasPrevious
property to check if next page or previous page is present.SwiftUI Support
AmityObject and AmityCollection are now observable object with its properties marked with @Published annotation. Now you can use live object & live collection directly within your SwiftUI views. Live Object @Published: dataStatus ✅, loadingStatus ✅, snapshot ✅, error ✅, object ❌ Live Collection @Published: dataStatus ✅, loadingStatus ✅, snapshot ✅, error ✅Access AmityObject & AmityCollection in SwiftUI views
Since AmityObject & AmityCollection are observable object, it can be used as an ObservedObject within SwiftUI views. We recommend to create small view which observes AmityCollection & AmityObject as ObservedObject as shown in code sample below.Live Object - SwiftUI
Live Object - SwiftUI
Live Collection - SwiftUI
Live Collection - SwiftUI
Live Object - Combine
Live Object - Combine
Live Collection - Combine
Live Collection - Combine
States of live collection & live object are published before snapshots so that you can compare the state from within subscriber.
FAQ’s
#1: LiveCollection is not updated when used from inside of another observable class
#1: LiveCollection is not updated when used from inside of another observable class
AmityCollection & AmityObject is an ObservableObject. When this live collection or live object is embedded inside another Observable Object, SwiftUI cannot observe the changes in snapshot occurring within Live collection & Live object. As a result, there might be a situation where you see your view is not getting updated even when snapshot(s) are updated. This is a common problem with nested observable object in SwiftUI.❌ Error: View where list does not update✅ Success: View where list updates successfullyTo solve this issue we recommend to create a specific view which observes AmityCollection & AmityObject as @ObservedObject as shown in code example.
#2: Published property still returns old values
#2: Published property still returns old values
Since the properties of AmityCollection & AmityObject are marked with @Published annotation, the publishing of changes occurs in the property’s willSet block, meaning that any subscribers will receive an update before the property is changed. This behaviour can easily lead to unexpected bugs.
Best Practices
Token Management
Token Management
Proper Retention: Always retain
AmityNotificationToken
in appropriate scope to maintain observations. Store tokens as instance variables to prevent deallocation.Observer Selection
Observer Selection
Choose Appropriate Method: Use
observe
for ongoing updates throughout the application lifecycle, and observeOnce
for single-time data retrieval.Data Status Verification
Data Status Verification
Check Freshness: Always verify
dataStatus
to determine if data is fresh or local before processing, especially when you need the most recent data.SwiftUI Integration
SwiftUI Integration
Dedicated Views: Create dedicated views that observe live objects as
@ObservedObject
to avoid nested ObservableObject issues in SwiftUI.Combine Subscriptions
Combine Subscriptions
Parameter Usage: When using Combine framework, always use parameter values in sink closures rather than accessing properties directly to avoid timing issues.