[Bug]: Encoding/Decoding array of AppBskyLexicon.Feed.FeedViewPostDefinition not working
Summary
When caching feeds, they don't correctly save the Unknown types so decoding doesn't show the text content of the post.
Reproduction Steps
- Save/cache the array of AppBskyLexicon.Feed.FeedViewPostDefinition
- Fetch and decode from the saved location
- Record data has wrong type and is therefore missing
Expected Results
Correct saving and decoding of Unknown types.
Actual Results
Missing or wrong types.
What operating systems did you experience this bug?
iOS/iPadOS
Operating System Version
iOS 18
ATProtoKit Version
0.62.5
Additional Context
No response
This is a bit confusing. Could you show me the code you used in order to accomplish this? What method did you use to output AppBskyLexicon.Feed.FeedViewPostDefinition? How are you caching the data?
Using the following to output the data: try await atProto.getTimeline(limit: 100).feed, and caching using the Disk library which saves to the device's Documents folder, and retrieved from there too (whilst decoding back to an array of AppBskyLexicon.Feed.FeedViewPostDefinition). Hope this helps!
Hey, just wanted to ask whether there was any updates/progress on this issue? Would love to cache the timelines feed data correctly.
I'm struggling to replicate this issue. I do have some questions if you don't mind me asking:
- Are you using a third-party library to cache the data, using an Apple API, or using your own code?
- Do you mind sending me a GitHub Gist (private) of the code in question and send the link to me via a DM so I can potentially replicate it?
- Do you have an output of the JSON?
The answers should help me to pinpoint the problem better.
I'm using the Disk library for caching data (but the same happens with Apple's own APIs).
Here's the gist: https://gist.github.com/ShihabM/ef994ebbe22e0fab4a9b402ba023a23b
Thanks. I have a better understanding of it, but I haven't had time to test this until now. Please bare with me a little while longer.
Thank you for the heads up. Wondering if there's any new updates on this?
Yes, and I'm still looking into it; I'm just having to juggle many other tasks at the same time. I'll get back to you shortly.
Thank you for waiting.
I've tested your gist and it does indeed not show anything. However, I made some tweaks with the code. Here is what it looks like:
import UIKit
import ATProtoKit
import Disk
class ViewController: UIViewController {
var allPosts: [AppBskyLexicon.Feed.FeedViewPostDefinition] = []
var getTimelineResult: [AppBskyLexicon.Feed.FeedViewPostDefinition] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
Task {
do {
try await loadFromDisk()
} catch {
throw error
}
}
}
func saveToDisk() async {
do {
try Disk.save(getTimelineResult, to: .documents, as: "allPosts.json")
} catch {
print("error saving to Disk: \(error)")
}
}
func loadFromDisk() async throws {
let config = ATProtocolConfiguration()
try await config.authenticate(with: "[handle]", password: "[password]")
let atProtoKit = await ATProtoKit(sessionConfiguration: config)
getTimelineResult = try await atProtoKit.getTimeline(limit: 3).feed
print("allPosts: \(allPosts)")
await saveToDisk()
allPosts = try Disk.retrieve("allPosts.json", from: .documents, as: [AppBskyLexicon.Feed.FeedViewPostDefinition].self)
print(
"First post text:\(allPosts.first?.post.record.getRecord(ofType: AppBskyLexicon.Feed.PostRecord.self)?.text ?? "No data.")\n\nSecond post text: \(allPosts[1].post.record.getRecord(ofType: AppBskyLexicon.Feed.PostRecord.self)?.text ?? "No data.")"
)
}
}
This is similar to your gist except that I'm calling the saveToDisk method, I've checked that allPosts is empty before the Disk Swift package is saving to and retrieving from the cache, and I've printed the first two post text. This works as intended without the need to change ATProtoKit directly.
From your GitHub Gist, it appears that you forgot to call the saveToDisk function. Because of this, the cache was never created in the first place.
Also, in the "Actual Results" section, you mentioned "[...] wrong types." I've tested this with various method calls and I haven't been able to find an instance where the wrong type appears.
Please check your code to see if you forgot to save the cache.
Thank you for investigating. When I retrieve immediately, it seems to work. But when I retrieve in viewDidLoad after a fresh launch, it doesn't. The type of the record is ATProtoKit.UnknownType.unknown([]), which I don't think is handled in ATRecordProtocol.swift:
public func getRecord<Record: ATRecordProtocol>(ofType type: Record.Type) -> Record? {
guard case .record(let record as Record) = self else {
return nil
}
return record
}
And so when attempting to use getRecord, it's empty.
I don't follow. Do you mind sending a private gist of what you're doing that causes this issue?