Skip to content

Commit 353c9e6

Browse files
Merge pull request #42 from writeas/persist-content-locally
Persist content locally
2 parents 3751118 + 888de9e commit 353c9e6

28 files changed

+632
-472
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import CoreData
2+
3+
extension NSManagedObjectContext {
4+
/// Executes the given `NSBatchDeleteRequest` and directly merges the changes to bring the given
5+
/// managed object context up to date.
6+
///
7+
/// Credit: https://www.avanderlee.com/swift/nsbatchdeleterequest-core-data/
8+
///
9+
/// - Parameter batchDeleteRequest: The `NSBatchDeleteRequest` to execute.
10+
/// - Throws: An error if anything went wrong executing the batch deletion.
11+
public func executeAndMergeChanges(using batchDeleteRequest: NSBatchDeleteRequest) throws {
12+
batchDeleteRequest.resultType = .resultTypeObjectIDs
13+
let result = try execute(batchDeleteRequest) as? NSBatchDeleteResult
14+
let changes: [AnyHashable: Any] = [NSDeletedObjectsKey: result?.result as? [NSManagedObjectID] ?? []]
15+
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self])
16+
}
17+
}

Shared/LocalStorageManager.swift

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import CoreData
2+
3+
#if os(iOS)
4+
import UIKit
5+
#elseif os(macOS)
6+
import AppKit
7+
#endif
8+
9+
class LocalStorageManager {
10+
static let persistentContainer: NSPersistentContainer = {
11+
let container = NSPersistentContainer(name: "LocalStorageModel")
12+
container.loadPersistentStores { _, error in
13+
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
14+
if let error = error {
15+
fatalError("Unresolved error loading persistent store: \(error)")
16+
}
17+
}
18+
return container
19+
}()
20+
21+
init() {
22+
let center = NotificationCenter.default
23+
24+
#if os(iOS)
25+
let notification = UIApplication.willResignActiveNotification
26+
#elseif os(macOS)
27+
let notification = NSApplication.willResignActiveNotification
28+
#endif
29+
30+
// We don't need to worry about removing this observer because we're targeting iOS 9+ / macOS 10.11+; the
31+
// system will clean this up the next time it would be posted to.
32+
// See: https://developer.apple.com/documentation/foundation/notificationcenter/1413994-removeobserver
33+
// And: https://developer.apple.com/documentation/foundation/notificationcenter/1407263-removeobserver
34+
// swiftlint:disable:next discarded_notification_center_observer
35+
center.addObserver(forName: notification, object: nil, queue: nil, using: self.saveContextOnResignActive)
36+
}
37+
38+
func saveContext() {
39+
if LocalStorageManager.persistentContainer.viewContext.hasChanges {
40+
do {
41+
try LocalStorageManager.persistentContainer.viewContext.save()
42+
} catch {
43+
print("Error saving context: \(error)")
44+
}
45+
}
46+
}
47+
48+
func purgeUserCollections() {
49+
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "WFACollection")
50+
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
51+
52+
do {
53+
try LocalStorageManager.persistentContainer.viewContext.executeAndMergeChanges(using: deleteRequest)
54+
} catch {
55+
print("Error: Failed to purge cached collections.")
56+
}
57+
}
58+
}
59+
60+
private extension LocalStorageManager {
61+
func saveContextOnResignActive(_ notification: Notification) {
62+
saveContext()
63+
}
64+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17189" systemVersion="20A5364e" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
3+
<entity name="WFACollection" representedClassName="WFACollection" syncable="YES">
4+
<attribute name="alias" optional="YES" attributeType="String"/>
5+
<attribute name="blogDescription" optional="YES" attributeType="String"/>
6+
<attribute name="email" optional="YES" attributeType="String"/>
7+
<attribute name="isPublic" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
8+
<attribute name="styleSheet" optional="YES" attributeType="String"/>
9+
<attribute name="title" attributeType="String"/>
10+
<attribute name="url" optional="YES" attributeType="String"/>
11+
<uniquenessConstraints>
12+
<uniquenessConstraint>
13+
<constraint value="alias"/>
14+
</uniquenessConstraint>
15+
</uniquenessConstraints>
16+
</entity>
17+
<entity name="WFAPost" representedClassName="WFAPost" syncable="YES">
18+
<attribute name="appearance" optional="YES" attributeType="String"/>
19+
<attribute name="body" attributeType="String"/>
20+
<attribute name="collectionAlias" optional="YES" attributeType="String"/>
21+
<attribute name="createdDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
22+
<attribute name="hasNewerRemoteCopy" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
23+
<attribute name="language" optional="YES" attributeType="String"/>
24+
<attribute name="postId" optional="YES" attributeType="String"/>
25+
<attribute name="rtl" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
26+
<attribute name="slug" optional="YES" attributeType="String"/>
27+
<attribute name="status" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
28+
<attribute name="title" optional="YES" attributeType="String"/>
29+
<attribute name="updatedDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
30+
<uniquenessConstraints>
31+
<uniquenessConstraint>
32+
<constraint value="postId"/>
33+
</uniquenessConstraint>
34+
</uniquenessConstraints>
35+
</entity>
36+
<elements>
37+
<element name="WFACollection" positionX="14.806640625" positionY="202.9156341552734" width="128" height="148"/>
38+
<element name="WFAPost" positionX="287.377197265625" positionY="243.2452697753906" width="128" height="209"/>
39+
</elements>
40+
</model>

Shared/Models/Post.swift

Lines changed: 0 additions & 108 deletions
This file was deleted.

Shared/Models/PostCollection.swift

Lines changed: 0 additions & 23 deletions
This file was deleted.

Shared/Models/PostStatus.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Foundation
2+
3+
enum PostStatus: Int32 {
4+
case local = 0
5+
case edited = 1
6+
case published = 2
7+
}

Shared/Models/PostStore.swift

Lines changed: 0 additions & 66 deletions
This file was deleted.

0 commit comments

Comments
 (0)