Fix crash when viewing instance public timelines

Use a CoreData in-memory store for public timelines.
This commit is contained in:
Shadowfacts 2020-05-11 17:57:50 -04:00
parent 04496aca1d
commit cd78287a87
Signed by untrusted user: shadowfacts
GPG Key ID: 94A5AB95422746E5
6 changed files with 24 additions and 13 deletions

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public final class Status: StatusProtocol, Decodable { public final class Status: /*StatusProtocol,*/ Decodable {
public let id: String public let id: String
public let uri: String public let uri: String
public let url: URL? public let url: URL?
@ -23,8 +23,8 @@ public final class Status: StatusProtocol, Decodable {
// public let repliesCount: Int // public let repliesCount: Int
public let reblogsCount: Int public let reblogsCount: Int
public let favouritesCount: Int public let favouritesCount: Int
public let reblogged: Bool public let reblogged: Bool?
public let favourited: Bool public let favourited: Bool?
public let muted: Bool? public let muted: Bool?
public let sensitive: Bool public let sensitive: Bool
public let spoilerText: String public let spoilerText: String

View File

@ -30,7 +30,8 @@ class MastodonController {
} }
} }
private(set) lazy var persistentContainer = MastodonCachePersistentStore(for: self) private let transient: Bool
private(set) lazy var persistentContainer = MastodonCachePersistentStore(for: accountInfo, transient: transient)
let instanceURL: URL let instanceURL: URL
var accountInfo: LocalData.UserAccountInfo? var accountInfo: LocalData.UserAccountInfo?
@ -40,10 +41,11 @@ class MastodonController {
var account: Account! var account: Account!
var instance: Instance! var instance: Instance!
init(instanceURL: URL) { init(instanceURL: URL, transient: Bool = false) {
self.instanceURL = instanceURL self.instanceURL = instanceURL
self.accountInfo = nil self.accountInfo = nil
self.client = Client(baseURL: instanceURL) self.client = Client(baseURL: instanceURL)
self.transient = transient
} }
func run<Result>(_ request: Request<Result>, completion: @escaping Client.Callback<Result>) { func run<Result>(_ request: Request<Result>, completion: @escaping Client.Callback<Result>) {

View File

@ -23,8 +23,17 @@ class MastodonCachePersistentStore: NSPersistentContainer {
let statusSubject = PassthroughSubject<String, Never>() let statusSubject = PassthroughSubject<String, Never>()
let accountSubject = PassthroughSubject<String, Never>() let accountSubject = PassthroughSubject<String, Never>()
init(for controller: MastodonController) { init(for accountInfo: LocalData.UserAccountInfo?, transient: Bool = false) {
super.init(name: "\(controller.accountInfo!.id)_cache", managedObjectModel: MastodonCachePersistentStore.managedObjectModel) if transient {
super.init(name: "transient_cache", managedObjectModel: MastodonCachePersistentStore.managedObjectModel)
let storeDescription = NSPersistentStoreDescription()
storeDescription.type = NSInMemoryStoreType
persistentStoreDescriptions = [storeDescription]
} else {
super.init(name: "\(accountInfo!.id)_cache", managedObjectModel: MastodonCachePersistentStore.managedObjectModel)
}
loadPersistentStores { (description, error) in loadPersistentStores { (description, error) in
if let error = error { if let error = error {
fatalError("Unable to load persistent store: \(error)") fatalError("Unable to load persistent store: \(error)")

View File

@ -106,7 +106,7 @@ extension StatusMO {
self.content = status.content self.content = status.content
self.createdAt = status.createdAt self.createdAt = status.createdAt
self.emojis = status.emojis self.emojis = status.emojis
self.favourited = status.favourited self.favourited = status.favourited ?? false
self.favouritesCount = status.favouritesCount self.favouritesCount = status.favouritesCount
self.hashtags = status.hashtags self.hashtags = status.hashtags
self.inReplyToAccountID = status.inReplyToAccountID self.inReplyToAccountID = status.inReplyToAccountID
@ -115,7 +115,7 @@ extension StatusMO {
self.mentions = status.mentions self.mentions = status.mentions
self.muted = status.muted ?? false self.muted = status.muted ?? false
self.pinnedInternal = status.pinned ?? false self.pinnedInternal = status.pinned ?? false
self.reblogged = status.reblogged self.reblogged = status.reblogged ?? false
self.reblogsCount = status.reblogsCount self.reblogsCount = status.reblogsCount
self.sensitive = status.sensitive self.sensitive = status.sensitive
self.spoilerText = status.spoilerText self.spoilerText = status.spoilerText

View File

@ -37,7 +37,7 @@ class InstanceTimelineViewController: TimelineTableViewController {
self.instanceURL = url self.instanceURL = url
// the timeline VC only stores a weak reference to it, so we need to store a strong reference to make sure it's not released immediately // the timeline VC only stores a weak reference to it, so we need to store a strong reference to make sure it's not released immediately
instanceMastodonController = MastodonController(instanceURL: url) instanceMastodonController = MastodonController(instanceURL: url, transient: true)
super.init(for: .public(local: true), mastodonController: instanceMastodonController) super.init(for: .public(local: true), mastodonController: instanceMastodonController)

View File

@ -261,7 +261,7 @@ class BaseStatusTableViewCell: UITableViewCell {
mastodonController.run(request) { response in mastodonController.run(request) { response in
DispatchQueue.main.async { DispatchQueue.main.async {
if case let .success(newStatus, _) = response { if case let .success(newStatus, _) = response {
self.favorited = newStatus.favourited self.favorited = newStatus.favourited ?? false
self.mastodonController.persistentContainer.addOrUpdate(status: newStatus, incrementReferenceCount: false) self.mastodonController.persistentContainer.addOrUpdate(status: newStatus, incrementReferenceCount: false)
UIImpactFeedbackGenerator(style: .light).impactOccurred() UIImpactFeedbackGenerator(style: .light).impactOccurred()
} else { } else {
@ -286,7 +286,7 @@ class BaseStatusTableViewCell: UITableViewCell {
mastodonController.run(request) { response in mastodonController.run(request) { response in
DispatchQueue.main.async { DispatchQueue.main.async {
if case let .success(newStatus, _) = response { if case let .success(newStatus, _) = response {
self.reblogged = newStatus.reblogged self.reblogged = newStatus.reblogged ?? false
self.mastodonController.persistentContainer.addOrUpdate(status: newStatus, incrementReferenceCount: false) self.mastodonController.persistentContainer.addOrUpdate(status: newStatus, incrementReferenceCount: false)
UIImpactFeedbackGenerator(style: .light).impactOccurred() UIImpactFeedbackGenerator(style: .light).impactOccurred()
} else { } else {