parent
0a89dd3041
commit
82ad3b9fc4
|
@ -84,8 +84,16 @@ class MastodonController {
|
||||||
run(request) { response in
|
run(request) { response in
|
||||||
guard case let .success(account, _) = response else { fatalError() }
|
guard case let .success(account, _) = response else { fatalError() }
|
||||||
self.account = account
|
self.account = account
|
||||||
self.persistentContainer.addOrUpdate(account: account)
|
self.persistentContainer.backgroundContext.perform {
|
||||||
completion?(account)
|
if let accountMO = self.persistentContainer.account(for: account.id, in: self.persistentContainer.backgroundContext) {
|
||||||
|
accountMO.updateFrom(apiAccount: account, container: self.persistentContainer)
|
||||||
|
} else {
|
||||||
|
// the first time the user's account is added to the store,
|
||||||
|
// increment its reference count so that it's never removed
|
||||||
|
self.persistentContainer.addOrUpdate(account: account, incrementReferenceCount: true)
|
||||||
|
}
|
||||||
|
completion?(account)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ public final class AccountMO: NSManagedObject, AccountProtocol {
|
||||||
@NSManaged public var locked: Bool
|
@NSManaged public var locked: Bool
|
||||||
@NSManaged public var movedCD: Bool
|
@NSManaged public var movedCD: Bool
|
||||||
@NSManaged public var note: String
|
@NSManaged public var note: String
|
||||||
|
@NSManaged public var referenceCount: Int
|
||||||
@NSManaged public var statusesCount: Int
|
@NSManaged public var statusesCount: Int
|
||||||
@NSManaged public var url: URL
|
@NSManaged public var url: URL
|
||||||
@NSManaged public var username: String
|
@NSManaged public var username: String
|
||||||
|
@ -46,12 +47,30 @@ public final class AccountMO: NSManagedObject, AccountProtocol {
|
||||||
public var bot: Bool? { botCD }
|
public var bot: Bool? { botCD }
|
||||||
public var moved: Bool? { movedCD }
|
public var moved: Bool? { movedCD }
|
||||||
|
|
||||||
|
func incrementReferenceCount() {
|
||||||
|
referenceCount += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func decrementReferenceCount() {
|
||||||
|
referenceCount -= 1
|
||||||
|
if referenceCount <= 0 {
|
||||||
|
managedObjectContext!.delete(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func prepareForDeletion() {
|
||||||
|
super.prepareForDeletion()
|
||||||
|
movedTo?.decrementReferenceCount()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AccountMO {
|
extension AccountMO {
|
||||||
convenience init(apiAccount account: Pachyderm.Account, container: MastodonCachePersistentStore, context: NSManagedObjectContext) {
|
convenience init(apiAccount account: Pachyderm.Account, container: MastodonCachePersistentStore, context: NSManagedObjectContext) {
|
||||||
self.init(context: context)
|
self.init(context: context)
|
||||||
self.updateFrom(apiAccount: account, container: container)
|
self.updateFrom(apiAccount: account, container: container)
|
||||||
|
|
||||||
|
movedTo?.incrementReferenceCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateFrom(apiAccount account: Pachyderm.Account, container: MastodonCachePersistentStore) {
|
func updateFrom(apiAccount account: Pachyderm.Account, container: MastodonCachePersistentStore) {
|
||||||
|
|
|
@ -105,18 +105,25 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
private func upsert(account: Account) -> AccountMO {
|
private func upsert(account: Account, incrementReferenceCount: Bool) -> AccountMO {
|
||||||
if let accountMO = self.account(for: account.id, in: self.backgroundContext) {
|
if let accountMO = self.account(for: account.id, in: self.backgroundContext) {
|
||||||
accountMO.updateFrom(apiAccount: account, container: self)
|
accountMO.updateFrom(apiAccount: account, container: self)
|
||||||
|
if incrementReferenceCount {
|
||||||
|
accountMO.incrementReferenceCount()
|
||||||
|
}
|
||||||
return accountMO
|
return accountMO
|
||||||
} else {
|
} else {
|
||||||
return AccountMO(apiAccount: account, container: self, context: self.backgroundContext)
|
let accountMO = AccountMO(apiAccount: account, container: self, context: self.backgroundContext)
|
||||||
|
if incrementReferenceCount {
|
||||||
|
accountMO.incrementReferenceCount()
|
||||||
|
}
|
||||||
|
return accountMO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addOrUpdate(account: Account, completion: ((AccountMO) -> Void)? = nil) {
|
func addOrUpdate(account: Account, incrementReferenceCount: Bool, completion: ((AccountMO) -> Void)? = nil) {
|
||||||
backgroundContext.perform {
|
backgroundContext.perform {
|
||||||
let accountMO = self.upsert(account: account)
|
let accountMO = self.upsert(account: account, incrementReferenceCount: incrementReferenceCount)
|
||||||
if self.backgroundContext.hasChanges {
|
if self.backgroundContext.hasChanges {
|
||||||
try! self.backgroundContext.save()
|
try! self.backgroundContext.save()
|
||||||
}
|
}
|
||||||
|
@ -127,7 +134,7 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
||||||
|
|
||||||
func addAll(accounts: [Account], completion: (() -> Void)? = nil) {
|
func addAll(accounts: [Account], completion: (() -> Void)? = nil) {
|
||||||
backgroundContext.perform {
|
backgroundContext.perform {
|
||||||
accounts.forEach { self.upsert(account: $0) }
|
accounts.forEach { self.upsert(account: $0, incrementReferenceCount: true) }
|
||||||
if self.backgroundContext.hasChanges {
|
if self.backgroundContext.hasChanges {
|
||||||
try! self.backgroundContext.save()
|
try! self.backgroundContext.save()
|
||||||
}
|
}
|
||||||
|
@ -139,9 +146,11 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
||||||
func addAll(notifications: [Pachyderm.Notification], completion: (() -> Void)? = nil) {
|
func addAll(notifications: [Pachyderm.Notification], completion: (() -> Void)? = nil) {
|
||||||
backgroundContext.perform {
|
backgroundContext.perform {
|
||||||
let statuses = notifications.compactMap { $0.status }
|
let statuses = notifications.compactMap { $0.status }
|
||||||
let accounts = notifications.map { $0.account }
|
// filter out mentions, otherwise we would double increment the reference count of those accounts
|
||||||
|
// 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, incrementReferenceCount: true) }
|
statuses.forEach { self.upsert(status: $0, incrementReferenceCount: true) }
|
||||||
accounts.forEach { self.upsert(account: $0) }
|
accounts.forEach { self.upsert(account: $0, incrementReferenceCount: true) }
|
||||||
if self.backgroundContext.hasChanges {
|
if self.backgroundContext.hasChanges {
|
||||||
try! self.backgroundContext.save()
|
try! self.backgroundContext.save()
|
||||||
}
|
}
|
||||||
|
@ -157,7 +166,7 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
||||||
var updatedStatuses = [String]()
|
var updatedStatuses = [String]()
|
||||||
|
|
||||||
block(self.backgroundContext, { (accounts) in
|
block(self.backgroundContext, { (accounts) in
|
||||||
accounts.forEach { self.upsert(account: $0) }
|
accounts.forEach { self.upsert(account: $0, incrementReferenceCount: true) }
|
||||||
updatedAccounts.append(contentsOf: accounts.map { $0.id })
|
updatedAccounts.append(contentsOf: accounts.map { $0.id })
|
||||||
}, { (statuses) in
|
}, { (statuses) in
|
||||||
statuses.forEach { self.upsert(status: $0, incrementReferenceCount: true) }
|
statuses.forEach { self.upsert(status: $0, incrementReferenceCount: true) }
|
||||||
|
|
|
@ -82,6 +82,7 @@ public final class StatusMO: NSManagedObject, StatusProtocol {
|
||||||
public override func prepareForDeletion() {
|
public override func prepareForDeletion() {
|
||||||
super.prepareForDeletion()
|
super.prepareForDeletion()
|
||||||
reblog?.decrementReferenceCount()
|
reblog?.decrementReferenceCount()
|
||||||
|
account.decrementReferenceCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,6 +93,7 @@ extension StatusMO {
|
||||||
self.updateFrom(apiStatus: status, container: container)
|
self.updateFrom(apiStatus: status, container: container)
|
||||||
|
|
||||||
reblog?.incrementReferenceCount()
|
reblog?.incrementReferenceCount()
|
||||||
|
account.incrementReferenceCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateFrom(apiStatus status: Pachyderm.Status, container: MastodonCachePersistentStore) {
|
func updateFrom(apiStatus status: Pachyderm.Status, container: MastodonCachePersistentStore) {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
<attribute name="locked" attributeType="Boolean" usesScalarValueType="YES"/>
|
<attribute name="locked" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||||
<attribute name="movedCD" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
<attribute name="movedCD" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||||
<attribute name="note" attributeType="String"/>
|
<attribute name="note" attributeType="String"/>
|
||||||
|
<attribute name="referenceCount" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<attribute name="statusesCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
<attribute name="statusesCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<attribute name="url" attributeType="URI"/>
|
<attribute name="url" attributeType="URI"/>
|
||||||
<attribute name="username" attributeType="String"/>
|
<attribute name="username" attributeType="String"/>
|
||||||
|
@ -49,7 +50,6 @@
|
||||||
<attribute name="uri" attributeType="String"/>
|
<attribute name="uri" attributeType="String"/>
|
||||||
<attribute name="url" optional="YES" attributeType="URI"/>
|
<attribute name="url" optional="YES" attributeType="URI"/>
|
||||||
<attribute name="visibilityString" attributeType="String"/>
|
<attribute name="visibilityString" attributeType="String"/>
|
||||||
|
|
||||||
<relationship name="account" maxCount="1" deletionRule="Nullify" destinationEntity="Account"/>
|
<relationship name="account" maxCount="1" deletionRule="Nullify" destinationEntity="Account"/>
|
||||||
<relationship name="reblog" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status"/>
|
<relationship name="reblog" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status"/>
|
||||||
<uniquenessConstraints>
|
<uniquenessConstraints>
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
</uniquenessConstraints>
|
</uniquenessConstraints>
|
||||||
</entity>
|
</entity>
|
||||||
<elements>
|
<elements>
|
||||||
<element name="Account" positionX="169.21875" positionY="78.9609375" width="128" height="313"/>
|
<element name="Account" positionX="169.21875" positionY="78.9609375" width="128" height="328"/>
|
||||||
<element name="Status" positionX="-63" positionY="-18" width="128" height="418"/>
|
<element name="Status" positionX="-63" positionY="-18" width="128" height="418"/>
|
||||||
</elements>
|
</elements>
|
||||||
</model>
|
</model>
|
|
@ -61,6 +61,15 @@ class ProfileTableViewController: EnhancedTableViewController {
|
||||||
fatalError("init(coder:) has not been implemeneted")
|
fatalError("init(coder:) has not been implemeneted")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
if let id = accountID {
|
||||||
|
let container = mastodonController.persistentContainer
|
||||||
|
container.backgroundContext.perform {
|
||||||
|
container.account(for: id, in: container.backgroundContext)?.decrementReferenceCount()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
@ -90,7 +99,7 @@ class ProfileTableViewController: EnhancedTableViewController {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.mastodonController.persistentContainer.addOrUpdate(account: account) { (_) in
|
self.mastodonController.persistentContainer.addOrUpdate(account: account, incrementReferenceCount: true) { (_) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.updateAccountUI()
|
self.updateAccountUI()
|
||||||
self.tableView.reloadData()
|
self.tableView.reloadData()
|
||||||
|
|
|
@ -134,11 +134,10 @@ class SearchResultsViewController: EnhancedTableViewController {
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.performBatchUpdates({ (context, addAccounts, addStatuses) in
|
self.mastodonController.persistentContainer.performBatchUpdates({ (context, addAccounts, addStatuses) in
|
||||||
// todo: reference count accounts
|
oldSnapshot.itemIdentifiers(inSection: .accounts).forEach { (item) in
|
||||||
// oldSnapshot.itemIdentifiers(inSection: .accounts).forEach { (item) in
|
guard case let .account(id) = item else { return }
|
||||||
// guard case let .account(id) = item else { return }
|
self.mastodonController.persistentContainer.account(for: id, in: context)?.decrementReferenceCount()
|
||||||
// self.mastodonController.persistentContainer.account(for: id, in: context)?.decrementReferenceCount()
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
oldSnapshot.itemIdentifiers(inSection: .statuses).forEach { (item) in
|
oldSnapshot.itemIdentifiers(inSection: .statuses).forEach { (item) in
|
||||||
guard case let .status(id, _) = item else { return }
|
guard case let .status(id, _) = item else { return }
|
||||||
|
|
|
@ -58,6 +58,17 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
if let accountIDs = self.accountIDs {
|
||||||
|
let container = self.mastodonController.persistentContainer
|
||||||
|
container.backgroundContext.perform {
|
||||||
|
for id in accountIDs {
|
||||||
|
container.account(for: id, in: container.backgroundContext)?.decrementReferenceCount()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
@ -71,7 +82,11 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))
|
tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))
|
||||||
|
|
||||||
if accountIDs == nil {
|
if let accountIDs = accountIDs {
|
||||||
|
accountIDs.forEach { (id) in
|
||||||
|
self.mastodonController.persistentContainer.account(for: id)?.incrementReferenceCount()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// account IDs haven't been set, so perform a request to load them
|
// account IDs haven't been set, so perform a request to load them
|
||||||
guard let status = mastodonController.persistentContainer.status(for: statusID) else {
|
guard let status = mastodonController.persistentContainer.status(for: statusID) else {
|
||||||
fatalError("Missing cached status \(statusID)")
|
fatalError("Missing cached status \(statusID)")
|
||||||
|
|
Loading…
Reference in New Issue