Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move xcdatamodeld into WordPressData #24166

Draft
wants to merge 13 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion Modules/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ let package = Package(
.library(name: "AsyncImageKit", targets: ["AsyncImageKit"]),
.library(name: "DesignSystem", targets: ["DesignSystem"]),
.library(name: "JetpackStatsWidgetsCore", targets: ["JetpackStatsWidgetsCore"]),
.library(name: "WordPressData", targets: ["WordPressData"]),
.library(name: "WordPressFlux", targets: ["WordPressFlux"]),
.library(name: "WordPressShared", targets: ["WordPressShared"]),
.library(name: "WordPressUI", targets: ["WordPressUI"]),
Expand Down Expand Up @@ -63,6 +64,14 @@ let package = Package(
.product(name: "ScreenObject", package: "ScreenObject"),
.product(name: "XCUITestHelpers", package: "ScreenObject"),
], swiftSettings: [.swiftLanguageMode(.v5)]),
.target(name: "WordPressDataObjC"),
.target(
name: "WordPressData",
dependencies: [
.target(name: "WordPressDataObjC"),
.target(name: "WordPressSharedObjC")
]
),
.target(name: "WordPressFlux", swiftSettings: [.swiftLanguageMode(.v5)]),
.target(name: "WordPressCore", dependencies: [.target(name: "WordPressShared"), .product(name: "WordPressAPI", package: "wordpress-rs")]),
.target(name: "WordPressSharedObjC", resources: [.process("Resources")], swiftSettings: [.swiftLanguageMode(.v5)]),
Expand Down Expand Up @@ -105,7 +114,7 @@ let package = Package(
///
/// ## Known Issues
///
///   - SwiftPM copies resource bundles from a target, including dynamic frameworks,
/// - SwiftPM copies resource bundles from a target, including dynamic frameworks,
/// into every target that depends on it. Make sure to avoid including frameworks
/// with large resources bundled into multiple targets.
enum XcodeSupport {
Expand Down Expand Up @@ -159,6 +168,7 @@ enum XcodeSupport {
.xcodeTarget("XcodeTarget_App", dependencies: [
"DesignSystem",
"JetpackStatsWidgetsCore",
"WordPressData",
"WordPressFlux",
"WordPressShared",
"WordPressReader",
Expand Down
38 changes: 38 additions & 0 deletions Modules/Sources/WordPressData/CoreDataStackSwift.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import CoreData
import WordPressDataObjC

public protocol CoreDataStackSwift: CoreDataStack {

/// Execute the given block with a background context and save the changes.
///
/// This function _does not block_ its running thread. The block is executed in background and its return value
/// is passed onto the `completion` block which is executed on the given `queue`.
///
/// - Parameters:
/// - block: A closure which uses the given `NSManagedObjectContext` to make Core Data model changes.
/// - completion: A closure which is called with the return value of the `block`, after the changed made
/// by the `block` is saved.
/// - queue: A queue on which to execute the completion block.
func performAndSave<T>(_ block: @escaping (NSManagedObjectContext) -> T, completion: ((T) -> Void)?, on queue: DispatchQueue)

/// Execute the given block with a background context and save the changes _if the block does not throw an error_.
///
/// This function _does not block_ its running thread. The block is executed in background and the return value
/// (or an error) is passed onto the `completion` block which is executed on the given `queue`.
///
/// - Parameters:
/// - block: A closure that uses the given `NSManagedObjectContext` to make Core Data model changes. The changes
/// are only saved if the block does not throw an error.
/// - completion: A closure which is called with the `block`'s execution result, which is either an error thrown
/// by the `block` or the return value of the `block`.
/// - queue: A queue on which to execute the completion block.
func performAndSave<T>(_ block: @escaping (NSManagedObjectContext) throws -> T, completion: ((Result<T, Error>) -> Void)?, on queue: DispatchQueue)

/// Execute the given block with a background context and save the changes _if the block does not throw an error_.
///
/// - Parameter block: A closure that uses the given `NSManagedObjectContext` to make Core Data model changes.
/// The changes are only saved if the block does not throw an error.
/// - Returns: The value returned by the `block`
/// - Throws: The error thrown by the `block`, in which case the Core Data changes made by the `block` is discarded.
func performAndSave<T>(_ block: @escaping (NSManagedObjectContext) throws -> T) async throws -> T
}
45 changes: 45 additions & 0 deletions Modules/Sources/WordPressData/Models/BloggingPrompt.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import CoreData
import WordPressSharedObjC

public class BloggingPrompt: NSManagedObject {

/// The unique ID for the prompt, received from the server.
@NSManaged public var promptID: Int32

/// The site ID for the prompt.
@NSManaged public var siteID: Int32

/// The prompt content to be displayed at entry points.
@NSManaged public var text: String

/// The attribution source for the prompt.
@NSManaged public var attribution: String

/// The prompt date. Time information should be ignored.
@NSManaged public var date: Date

/// Whether the current user has answered the prompt in `siteID`.
@NSManaged public var answered: Bool

/// The number of users that has answered the prompt.
@NSManaged public var answerCount: Int32

/// Contains avatar URLs of some users that have answered the prompt.
@NSManaged public var displayAvatarURLs: [URL]

/// Contains additional tags that should be appended to the post for this prompt's answer.
@NSManaged public var additionalPostTags: [String]?

@nonobjc public class func fetchRequest() -> NSFetchRequest<BloggingPrompt> {
return NSFetchRequest<BloggingPrompt>(entityName: Self.classNameWithoutNamespaces())
}

@nonobjc public class func newObject(in context: NSManagedObjectContext) -> BloggingPrompt? {
return NSEntityDescription.insertNewObject(forEntityName: Self.classNameWithoutNamespaces(), into: context) as? BloggingPrompt
}

public override func awakeFromInsert() {
self.date = .init(timeIntervalSince1970: 0)
self.displayAvatarURLs = []
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22757" systemVersion="23E224" minimumToolsVersion="Xcode 9.0" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="23605" systemVersion="24D70" minimumToolsVersion="Xcode 9.0" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="AbstractPost" representedClassName="AbstractPost" isAbstract="YES" parentEntity="BasePost">
<attribute name="autosaveContent" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="autosaveExcerpt" optional="YES" attributeType="String" syncable="YES"/>
Expand Down Expand Up @@ -215,7 +215,7 @@
<attribute name="username" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="blog" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Blog" inverseName="authors" inverseEntity="Blog" syncable="YES"/>
</entity>
<entity name="BloggingPrompt" representedClassName=".BloggingPrompt" syncable="YES">
<entity name="BloggingPrompt" representedClassName="WordPressData.BloggingPrompt" syncable="YES">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before

image

After

image

<attribute name="additionalPostTags" optional="YES" attributeType="Transformable" valueTransformerName="NSSecureUnarchiveFromData" customClassName="[String]" syncable="YES"/>
<attribute name="answerCount" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
<attribute name="answered" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
Expand Down
29 changes: 29 additions & 0 deletions Modules/Sources/WordPressData/WordPressData.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@_exported import WordPressDataObjC

public let modelURL: URL = {
guard let url = Bundle.module.url(forResource: "WordPress", withExtension: "momd") else {
fatalError("Cannot find model file.")
}
return url
}()

public func urlForModel(name: String, in directory: String?) -> URL? {
let bundle = Bundle(for: TemporaryDummyClassToPickUpModule.self)
var url = bundle.url(forResource: name, withExtension: "mom", subdirectory: directory)

if url != nil {
return url
}

let momdPaths = bundle.paths(forResourcesOfType: "momd", inDirectory: directory)
momdPaths.forEach { (path) in
if url != nil {
return
}
url = bundle.url(forResource: name, withExtension: "mom", subdirectory: URL(fileURLWithPath: path).lastPathComponent)
}

return url
}
Comment on lines +3 to +27
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These free functions should go into an object at some point.

It was just simpler to chuck them in here at this stage while I figure things out.

Also, I'd like to think there will be no need to have them public once all the types involved in setting up the Core Data stack have been moved.


private class TemporaryDummyClassToPickUpModule {}
6 changes: 6 additions & 0 deletions Modules/Sources/WordPressDataObjC/WordPressData.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FOUNDATION_EXPORT double WordPressDataVersionNumber;

FOUNDATION_EXPORT const unsigned char WordPressDataVersionString[];

#import <WordPressData/CoreDataService.h>
#import <WordPressData/CoreDataStack.h>
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#import <Foundation/Foundation.h>

#import "CoreDataStack.h"

NS_ASSUME_NONNULL_BEGIN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@
NS_ASSUME_NONNULL_BEGIN

@protocol CoreDataStack

@property (nonatomic, readonly, strong) NSManagedObjectContext *mainContext;

- (NSManagedObjectContext *const)newDerivedContext DEPRECATED_MSG_ATTRIBUTE("Use `performAndSave` instead");

- (void)saveContextAndWait:(NSManagedObjectContext *)context;

- (void)saveContext:(NSManagedObjectContext *)context;
- (void)saveContext:(NSManagedObjectContext *)context withCompletionBlock:(void (^ _Nullable)(void))completionBlock onQueue:(dispatch_queue_t)queue NS_SWIFT_NAME(save(_:completion:on:));

- (void)saveContext:(NSManagedObjectContext *)context
withCompletionBlock:(void (^ _Nullable)(void))completionBlock
onQueue:(dispatch_queue_t)queue NS_SWIFT_NAME(save(_:completion:on:));

/// Execute the given block with a background context and save the changes.
///
Expand All @@ -27,7 +34,8 @@ NS_ASSUME_NONNULL_BEGIN
/// - aBlock: A block which uses the given `NSManagedObjectContext` to make Core Data model changes.
/// - completion: A block which is called after the changes made by the `block` are saved.
/// - queue: A queue on which to execute the `completion` block.
- (void)performAndSaveUsingBlock:(void (^)(NSManagedObjectContext *context))aBlock completion:(void (^ _Nullable)(void))completion onQueue:(dispatch_queue_t)queue;
- (void)performAndSaveUsingBlock:(void (^)(NSManagedObjectContext *context))aBlock
completion:(void (^ _Nullable)(void))completion onQueue:(dispatch_queue_t)queue;

@end

Expand Down
11 changes: 11 additions & 0 deletions Modules/Sources/WordPressSharedObjC/Utility/NSObject+ClassName.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#import "NSObject+ClassName.h"

@implementation NSObject (ClassName)

+ (NSString *)classNameWithoutNamespaces
{
// Note that Swift prepends the module name to the class name itself
return [[NSStringFromClass(self) componentsSeparatedByString:@"."] lastObject];
}

@end
11 changes: 11 additions & 0 deletions Modules/Sources/WordPressSharedObjC/include/NSObject+ClassName.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSObject (ClassName)

+ (NSString *)classNameWithoutNamespaces;

@end

NS_ASSUME_NONNULL_END
2 changes: 1 addition & 1 deletion WordPress/Classes/Categories/Media+Extensions.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#import "Media+Extensions.h"
#import "MediaService.h"
#import "Blog.h"
#import "CoreDataStack.h"
@import WordPressDataObjC;
#import "WordPress-Swift.h"

@implementation Media (Extensions)
Expand Down
4 changes: 4 additions & 0 deletions WordPress/Classes/Categories/NSObject+Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ NS_ASSUME_NONNULL_BEGIN

@interface NSObject (Helpers)

// FIXME: Currently duplicated in WordPressSharedObjC because it'll be used in WordPressData (which depends on WordPressSharedObjc)
// It's not convenient to replace all usages in the main targets at this time.
// They should progressively diminish as we move all the Core Data related code into WordPressData.
// At that point, we should be able to remove this method from the main target.
+ (NSString *)classNameWithoutNamespaces;

- (void)debounce:(SEL)selector afterDelay:(NSTimeInterval)timeInterval;
Expand Down
1 change: 1 addition & 0 deletions WordPress/Classes/Extensions/Media/Media+Sync.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import CoreData
import WordPressData

extension Media {

Expand Down
1 change: 1 addition & 0 deletions WordPress/Classes/Extensions/Post+BloggingPrompts.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import WordPressData

extension Post {

Expand Down
4 changes: 2 additions & 2 deletions WordPress/Classes/Login/WordPressDotComAuthenticator.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Alamofire
import AuthenticationServices
import Foundation
import UIKit

import Alamofire
import WordPressData

/// Log in or sign up a WordPress.com account via web.
///
Expand Down
2 changes: 1 addition & 1 deletion WordPress/Classes/Models/AbstractPost.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#import "AbstractPost.h"
#import "Media.h"
#import "CoreDataStack.h"
@import WordPressDataObjC;
#import "WordPress-Swift.h"
#import "BasePost.h"

Expand Down
2 changes: 1 addition & 1 deletion WordPress/Classes/Models/BasePost.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#import "BasePost.h"
#import "Media.h"
#import "CoreDataStack.h"
@import WordPressDataObjC;

@import WordPressShared;

Expand Down
2 changes: 1 addition & 1 deletion WordPress/Classes/Models/Blog/Blog.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#import "Blog.h"
#import "WPAccount.h"
#import "AccountService.h"
#import "CoreDataStack.h"
@import WordPressDataObjC;
#import "Constants.h"
#import "WPUserAgent.h"
#import "WordPress-Swift.h"
Expand Down
24 changes: 6 additions & 18 deletions WordPress/Classes/Models/BloggingPrompt+CoreDataClass.swift
Original file line number Diff line number Diff line change
@@ -1,25 +1,9 @@
import Foundation
import CoreData
import WordPressData
import WordPressKit

public class BloggingPrompt: NSManagedObject {

@nonobjc public class func fetchRequest() -> NSFetchRequest<BloggingPrompt> {
return NSFetchRequest<BloggingPrompt>(entityName: Self.classNameWithoutNamespaces())
}

@nonobjc public class func newObject(in context: NSManagedObjectContext) -> BloggingPrompt? {
return NSEntityDescription.insertNewObject(forEntityName: Self.classNameWithoutNamespaces(), into: context) as? BloggingPrompt
}

public override func awakeFromInsert() {
self.date = .init(timeIntervalSince1970: 0)
self.displayAvatarURLs = []
}

var promptAttribution: BloggingPromptsAttribution? {
BloggingPromptsAttribution(rawValue: attribution.lowercased())
}
extension BloggingPrompt {

/// Convenience method to map properties from `BloggingPromptRemoteObject`.
///
Expand All @@ -42,6 +26,10 @@ public class BloggingPrompt: NSManagedObject {
}
}

var promptAttribution: BloggingPromptsAttribution? {
BloggingPromptsAttribution(rawValue: attribution.lowercased())
}

func textForDisplay() -> String {
return text.stringByDecodingXMLCharacters().trim()
}
Expand Down
29 changes: 1 addition & 28 deletions WordPress/Classes/Models/BloggingPrompt+CoreDataProperties.swift
Original file line number Diff line number Diff line change
@@ -1,31 +1,4 @@
import Foundation
import CoreData

extension BloggingPrompt {
/// The unique ID for the prompt, received from the server.
@NSManaged public var promptID: Int32

/// The site ID for the prompt.
@NSManaged public var siteID: Int32

/// The prompt content to be displayed at entry points.
@NSManaged public var text: String

/// The attribution source for the prompt.
@NSManaged public var attribution: String

/// The prompt date. Time information should be ignored.
@NSManaged public var date: Date

/// Whether the current user has answered the prompt in `siteID`.
@NSManaged public var answered: Bool

/// The number of users that has answered the prompt.
@NSManaged public var answerCount: Int32

/// Contains avatar URLs of some users that have answered the prompt.
@NSManaged public var displayAvatarURLs: [URL]

/// Contains additional tags that should be appended to the post for this prompt's answer.
@NSManaged public var additionalPostTags: [String]?
}
// FIXME: Delete
2 changes: 1 addition & 1 deletion WordPress/Classes/Models/Media.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#import "Media.h"
#import "CoreDataStack.h"
@import WordPressDataObjC;
#import "WordPress-Swift.h"

@implementation Media
Expand Down
2 changes: 1 addition & 1 deletion WordPress/Classes/Models/ReaderPost.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#import "ReaderPost.h"
#import "AccountService.h"
#import "CoreDataStack.h"
@import WordPressDataObjC;
#import "SourcePostAttribution.h"
#import "WPAccount.h"
#import "WordPress-Swift.h"
Expand Down
Loading