Fix crash when opening profile view controller with uncached account
E.g., by tapping a mention in a status
This commit is contained in:
parent
cbbe9ec11f
commit
d5433e9b91
|
@ -147,19 +147,20 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
|||
}
|
||||
|
||||
@discardableResult
|
||||
private func upsert(account: Account) -> AccountMO {
|
||||
if let accountMO = self.account(for: account.id, in: self.backgroundContext) {
|
||||
private func upsert(account: Account, in context: NSManagedObjectContext) -> AccountMO {
|
||||
if let accountMO = self.account(for: account.id, in: context) {
|
||||
accountMO.updateFrom(apiAccount: account, container: self)
|
||||
return accountMO
|
||||
} else {
|
||||
return AccountMO(apiAccount: account, container: self, context: self.backgroundContext)
|
||||
return AccountMO(apiAccount: account, container: self, context: context)
|
||||
}
|
||||
}
|
||||
|
||||
func addOrUpdate(account: Account, completion: ((AccountMO) -> Void)? = nil) {
|
||||
backgroundContext.perform {
|
||||
let accountMO = self.upsert(account: account)
|
||||
self.save(context: self.backgroundContext)
|
||||
func addOrUpdate(account: Account, in context: NSManagedObjectContext? = nil, completion: ((AccountMO) -> Void)? = nil) {
|
||||
let context = context ?? backgroundContext
|
||||
context.perform {
|
||||
let accountMO = self.upsert(account: account, in: context)
|
||||
self.save(context: context)
|
||||
completion?(accountMO)
|
||||
self.accountSubject.send(account.id)
|
||||
}
|
||||
|
@ -199,7 +200,7 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
|||
|
||||
func addAll(accounts: [Account], completion: (() -> Void)? = nil) {
|
||||
backgroundContext.perform {
|
||||
accounts.forEach { self.upsert(account: $0) }
|
||||
accounts.forEach { self.upsert(account: $0, in: self.backgroundContext) }
|
||||
self.save(context: self.backgroundContext)
|
||||
completion?()
|
||||
accounts.forEach { self.accountSubject.send($0.id) }
|
||||
|
@ -213,7 +214,7 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
|||
// since the status has the same account as the notification
|
||||
let accounts = notifications.filter { $0.kind != .mention }.map { $0.account }
|
||||
statuses.forEach { self.upsert(status: $0, context: self.backgroundContext) }
|
||||
accounts.forEach { self.upsert(account: $0) }
|
||||
accounts.forEach { self.upsert(account: $0, in: self.backgroundContext) }
|
||||
self.save(context: self.backgroundContext)
|
||||
completion?()
|
||||
statuses.forEach { self.statusSubject.send($0.id) }
|
||||
|
@ -227,7 +228,7 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
|||
var updatedStatuses = [String]()
|
||||
|
||||
block(self.backgroundContext, { (accounts) in
|
||||
accounts.forEach { self.upsert(account: $0) }
|
||||
accounts.forEach { self.upsert(account: $0, in: self.backgroundContext) }
|
||||
updatedAccounts.append(contentsOf: accounts.map { $0.id })
|
||||
}, { (statuses) in
|
||||
statuses.forEach { self.upsert(status: $0, context: self.backgroundContext) }
|
||||
|
|
|
@ -29,9 +29,10 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
|||
view as! UICollectionView
|
||||
}
|
||||
private(set) var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
||||
|
||||
private(set) var headerCell: ProfileHeaderCollectionViewCell?
|
||||
|
||||
private var state: State = .unloaded
|
||||
|
||||
init(accountID: String?, kind: Kind, owner: ProfileViewController) {
|
||||
self.accountID = accountID
|
||||
self.kind = kind
|
||||
|
@ -92,10 +93,19 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
|||
.receive(on: DispatchQueue.main)
|
||||
.filter { [unowned self] in $0 == self.accountID }
|
||||
.sink { [unowned self] id in
|
||||
switch state {
|
||||
case .unloaded:
|
||||
Task {
|
||||
await load()
|
||||
}
|
||||
case .loading:
|
||||
break
|
||||
case .loaded, .addedHeader:
|
||||
var snapshot = dataSource.snapshot()
|
||||
snapshot.reconfigureItems([.header(id)])
|
||||
dataSource.apply(snapshot, animatingDifferences: true)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
|
@ -159,20 +169,26 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
|||
}
|
||||
|
||||
private func load() async {
|
||||
guard accountID != nil,
|
||||
await controller.state == .notLoadedInitial,
|
||||
isViewLoaded else {
|
||||
guard isViewLoaded,
|
||||
let accountID,
|
||||
case .unloaded = state,
|
||||
mastodonController.persistentContainer.account(for: accountID) != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
state = .loading
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||
snapshot.appendSections([.header, .pinned, .statuses])
|
||||
snapshot.appendItems([.header(accountID)], toSection: .header)
|
||||
await apply(snapshot, animatingDifferences: false)
|
||||
print("added header item")
|
||||
|
||||
state = .addedHeader
|
||||
|
||||
await controller.loadInitial()
|
||||
await tryLoadPinned()
|
||||
|
||||
state = .loaded
|
||||
}
|
||||
|
||||
private func tryLoadPinned() async {
|
||||
|
@ -222,6 +238,15 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
|||
|
||||
}
|
||||
|
||||
extension ProfileStatusesViewController {
|
||||
enum State {
|
||||
case unloaded
|
||||
case loading
|
||||
case addedHeader
|
||||
case loaded
|
||||
}
|
||||
}
|
||||
|
||||
extension ProfileStatusesViewController {
|
||||
enum Kind {
|
||||
case statuses, withReplies, onlyMedia
|
||||
|
|
|
@ -116,7 +116,7 @@ class ProfileViewController: UIPageViewController {
|
|||
let req = Client.getAccount(id: accountID)
|
||||
let (account, _) = try await mastodonController.run(req)
|
||||
let mo = await withCheckedContinuation { continuation in
|
||||
mastodonController.persistentContainer.addOrUpdate(account: account) { (mo) in
|
||||
mastodonController.persistentContainer.addOrUpdate(account: account, in: mastodonController.persistentContainer.viewContext) { (mo) in
|
||||
continuation.resume(returning: mo)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue