├── BetterCoreData
├── BetterCoreData
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-60@2x.png
│ │ │ ├── Icon-60@3x.png
│ │ │ ├── Icon-Small@2x.png
│ │ │ ├── Icon-Small@3x.png
│ │ │ ├── Icon-Spotlight-40@2x.png
│ │ │ ├── Icon-Spotlight-40@3x.png
│ │ │ └── Contents.json
│ ├── ManagedObjectConvertible.swift
│ ├── User.swift
│ ├── UserMO+CoreDataProperties.swift
│ ├── UserMO+CoreDataClass.swift
│ ├── DataModel.xcdatamodeld
│ │ └── DataModel.xcdatamodel
│ │ │ └── contents
│ ├── Info.plist
│ ├── NewUserDataController.swift
│ ├── UserDataController.swift
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── CoreDataStack.swift
│ ├── ManagedObjectProtocol.swift
│ ├── AppDelegate.swift
│ ├── CoreDataWorker2.swift
│ ├── CoreDataWorker1.swift
│ └── ViewController.swift
└── BetterCoreData.xcodeproj
│ ├── project.xcworkspace
│ └── contents.xcworkspacedata
│ ├── xcuserdata
│ └── michal.xcuserdatad
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── BetterCoreData.xcscheme
│ └── project.pbxproj
├── README.md
└── .gitignore
/BetterCoreData/BetterCoreData/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swiftingio/BetterSwifterCoreData/HEAD/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swiftingio/BetterSwifterCoreData/HEAD/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swiftingio/BetterSwifterCoreData/HEAD/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swiftingio/BetterSwifterCoreData/HEAD/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swiftingio/BetterSwifterCoreData/HEAD/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swiftingio/BetterSwifterCoreData/HEAD/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/ManagedObjectConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ManagedObjectConvertible.swift
3 | // Created by swifting.io Team
4 | //
5 |
6 | import CoreData
7 |
8 | protocol ManagedObjectConvertible {
9 | associatedtype ManagedObject: NSManagedObject, ManagedObjectProtocol
10 | func toManagedObject(in context: NSManagedObjectContext) -> ManagedObject?
11 | }
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BetterSwifterCoreData
2 | Sample project for model structs and their conversion to Core Data entities.
3 |
4 | Refer Companion Blog:
5 | - [#25 Core Data in iOS10: NSPersistentContainer](https://swifting.io/blog/2016/09/25/25-core-data-in-ios10-nspersistentcontainer/)
6 | - [#28 Better CoreData with Swift Generics](https://swifting.io/blog/2016/09/25/25-core-data-in-ios10-nspersistentcontainer/)
7 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/User.swift:
--------------------------------------------------------------------------------
1 | //
2 | // User.swift
3 | // BetterCoreData
4 | //
5 | // Created by Michal Wojtysiak on 23/11/2016.
6 | // Copyright © 2016 Michal Wojtysiak. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct User {
12 | let id: String
13 | var username: String?
14 | var name: String?
15 | var birthday: Date?
16 | }
17 |
18 | extension User {
19 | init(id: String){
20 | self.id = id
21 | self.username = nil
22 | self.name = nil
23 | self.birthday = Date()
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData.xcodeproj/xcuserdata/michal.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | BetterCoreData.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 90C7682C1DE61BD100EF2926
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/UserMO+CoreDataProperties.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserMO+CoreDataProperties.swift
3 | // BetterCoreData
4 | //
5 | // Created by Michal Wojtysiak on 23/11/2016.
6 | // Copyright © 2016 Michal Wojtysiak. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreData
11 |
12 |
13 | extension UserMO {
14 |
15 | @nonobjc public class func fetchRequest() -> NSFetchRequest {
16 | return NSFetchRequest(entityName: "UserMO");
17 | }
18 |
19 | @NSManaged public var birthday: NSDate?
20 | @NSManaged public var identifier: String
21 | @NSManaged public var name: String?
22 | @NSManaged public var username: String?
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/UserMO+CoreDataClass.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserMO+CoreDataClass.swift
3 | // BetterCoreData
4 | //
5 | // Created by Michal Wojtysiak on 23/11/2016.
6 | // Copyright © 2016 Michal Wojtysiak. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreData
11 |
12 |
13 | public class UserMO: NSManagedObject {}
14 |
15 | extension UserMO: ManagedObjectProtocol {
16 | func toEntity() -> User? {
17 | return User(id: identifier, username: username, name: name, birthday: birthday as Date?)
18 | }
19 | }
20 |
21 | extension User: ManagedObjectConvertible {
22 | func toManagedObject(in context: NSManagedObjectContext) -> UserMO? {
23 | let user = UserMO.getOrCreateSingle(with: id, from: context)
24 | user.birthday = birthday as NSDate?
25 | user.name = name
26 | user.username = username
27 | return user
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "size" : "29x29",
15 | "idiom" : "iphone",
16 | "filename" : "Icon-Small@2x.png",
17 | "scale" : "2x"
18 | },
19 | {
20 | "size" : "29x29",
21 | "idiom" : "iphone",
22 | "filename" : "Icon-Small@3x.png",
23 | "scale" : "3x"
24 | },
25 | {
26 | "size" : "40x40",
27 | "idiom" : "iphone",
28 | "filename" : "Icon-Spotlight-40@2x.png",
29 | "scale" : "2x"
30 | },
31 | {
32 | "size" : "40x40",
33 | "idiom" : "iphone",
34 | "filename" : "Icon-Spotlight-40@3x.png",
35 | "scale" : "3x"
36 | },
37 | {
38 | "size" : "60x60",
39 | "idiom" : "iphone",
40 | "filename" : "Icon-60@2x.png",
41 | "scale" : "2x"
42 | },
43 | {
44 | "size" : "60x60",
45 | "idiom" : "iphone",
46 | "filename" : "Icon-60@3x.png",
47 | "scale" : "3x"
48 | }
49 | ],
50 | "info" : {
51 | "version" : 1,
52 | "author" : "xcode"
53 | }
54 | }
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/NewUserDataController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDataController.swift
3 | // BetterCoreData
4 | //
5 | // Created by Michal Wojtysiak on 25/11/2016.
6 | // Copyright © 2016 Michal Wojtysiak. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class NewUserDataController: UserDataControllerProtocol {
12 | let worker: NewCoreDataWorkerProtocol
13 | private var currentUser: User?
14 |
15 | init(worker: NewCoreDataWorkerProtocol = NewCoreDataWorker()){
16 | self.worker = worker
17 | }
18 |
19 | func fetchUser(completion: @escaping (User?) -> Void) {
20 | worker.get{ [weak self](result: Result<[User], Error>) in
21 | switch result {
22 | case .success(let users):
23 | self?.currentUser = users.first
24 | completion(users.first)
25 | case .failure(let error):
26 | print("\(error)")
27 | completion(nil)
28 | }
29 | }
30 | }
31 |
32 | func updateUser(name: String?, username: String?){
33 | var user: User = currentUser ?? User(id: UUID().uuidString)
34 | user.name = name
35 | user.username = username
36 | worker.upsert(entities: [user]){ (error) in
37 | guard let error = error else { return }
38 | print("\(error)")
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/UserDataController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDataController.swift
3 | // BetterCoreData
4 | //
5 | // Created by Michal Wojtysiak on 26/11/2016.
6 | // Copyright © 2016 Michal Wojtysiak. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol UserDataControllerProtocol {
12 | func fetchUser(completion: @escaping (User?) -> Void)
13 | func updateUser(name: String?, username: String?)
14 | }
15 |
16 | class UserDataController: UserDataControllerProtocol {
17 | let worker: CoreDataWorker
18 | private var currentUser: User?
19 |
20 | init(worker: CoreDataWorker = CoreDataWorker()){
21 | self.worker = worker
22 | }
23 |
24 | func fetchUser(completion: @escaping (User?) -> Void) {
25 | worker.get{ [weak self](result: Result<[User], Error>) in
26 | switch result {
27 | case .success(let users):
28 | self?.currentUser = users.first
29 | completion(users.first)
30 | case .failure(let error):
31 | print("\(error)")
32 | completion(nil)
33 | }
34 | }
35 | }
36 |
37 | func updateUser(name: String?, username: String?){
38 | var user: User = currentUser ?? User(id: UUID().uuidString)
39 | user.name = name
40 | user.username = username
41 | worker.upsert(entities: [user]){ (error) in
42 | guard let error = error else { return }
43 | print("\(error)")
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xcuserstate
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | ## Playgrounds
31 | timeline.xctimeline
32 | playground.xcworkspace
33 |
34 | # Swift Package Manager
35 | #
36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
37 | # Packages/
38 | .build/
39 |
40 | # CocoaPods
41 | #
42 | # We recommend against adding the Pods directory to your .gitignore. However
43 | # you should judge for yourself, the pros and cons are mentioned at:
44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
45 | #
46 | # Pods/
47 |
48 | # Carthage
49 | #
50 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
51 | # Carthage/Checkouts
52 |
53 | Carthage/Build
54 |
55 | # fastlane
56 | #
57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
58 | # screenshots whenever they are needed.
59 | # For more information about the recommended setup visit:
60 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
61 |
62 | fastlane/report.xml
63 | fastlane/Preview.html
64 | fastlane/screenshots
65 | fastlane/test_output
66 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/CoreDataStack.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CoreDataStack.swift
3 | // BetterCoreData
4 | //
5 | // Created by Michal Wojtysiak on 23/11/2016.
6 | // Copyright © 2016 Michal Wojtysiak. All rights reserved.
7 | //
8 |
9 | import CoreData
10 |
11 | protocol CoreDataServiceProtocol:class {
12 | var errorHandler: (Error) -> Void {get set}
13 | var persistentContainer: NSPersistentContainer {get}
14 | var viewContext: NSManagedObjectContext {get}
15 | var backgroundContext: NSManagedObjectContext {get}
16 | func performBackgroundTask(_ block: @escaping (NSManagedObjectContext) -> Void)
17 | func performForegroundTask(_ block: @escaping (NSManagedObjectContext) -> Void)
18 | }
19 |
20 | final class CoreDataService: CoreDataServiceProtocol {
21 |
22 | static let shared = CoreDataService()
23 | var errorHandler: (Error) -> Void = {_ in }
24 |
25 | lazy var persistentContainer: NSPersistentContainer = {
26 | let container = NSPersistentContainer(name: "DataModel")
27 | container.loadPersistentStores(completionHandler: { [weak self](storeDescription, error) in
28 | if let error = error {
29 | NSLog("CoreData error \(error), \(String(describing: error._userInfo))")
30 | self?.errorHandler(error)
31 | }
32 | })
33 | return container
34 | }()
35 |
36 | lazy var viewContext: NSManagedObjectContext = {
37 | let context:NSManagedObjectContext = self.persistentContainer.viewContext
38 | context.automaticallyMergesChangesFromParent = true
39 | return context
40 | }()
41 |
42 | lazy var backgroundContext: NSManagedObjectContext = {
43 | return self.persistentContainer.newBackgroundContext()
44 | }()
45 |
46 | func performForegroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) {
47 | self.viewContext.perform {
48 | block(self.viewContext)
49 | }
50 | }
51 |
52 | func performBackgroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) {
53 | self.persistentContainer.performBackgroundTask(block)
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/ManagedObjectProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ManagedObjectProtocol.swift
3 | // Created by swifting.io Team
4 | //
5 |
6 | import CoreData
7 |
8 | protocol ManagedObjectProtocol {
9 | associatedtype Entity
10 | func toEntity() -> Entity?
11 | }
12 |
13 | extension ManagedObjectProtocol where Self: NSManagedObject {
14 |
15 | static func getOrCreateSingle(with id: String, from context: NSManagedObjectContext) -> Self {
16 | let result = single(with: id, from: context) ?? insertNew(in: context)
17 | result.setValue(id, forKey: "identifier")
18 | return result
19 | }
20 |
21 | static func single(from context: NSManagedObjectContext, with predicate: NSPredicate?,
22 | sortDescriptors: [NSSortDescriptor]?) -> Self? {
23 | return fetch(from: context, with: predicate,
24 | sortDescriptors: sortDescriptors, fetchLimit: 1)?.first
25 | }
26 |
27 | static func single(with id: String, from context: NSManagedObjectContext) -> Self? {
28 | let predicate = NSPredicate(format: "identifier == %@", id)
29 | return single(from: context, with: predicate, sortDescriptors: nil)
30 | }
31 |
32 | static func insertNew(in context: NSManagedObjectContext) -> Self {
33 | return Self(context:context)
34 | }
35 |
36 | static func fetch(from context: NSManagedObjectContext, with predicate: NSPredicate?,
37 | sortDescriptors: [NSSortDescriptor]?, fetchLimit: Int?) -> [Self]? {
38 |
39 | let fetchRequest = Self.fetchRequest()
40 | fetchRequest.sortDescriptors = sortDescriptors
41 | fetchRequest.predicate = predicate
42 | fetchRequest.returnsObjectsAsFaults = false
43 |
44 | if let fetchLimit = fetchLimit {
45 | fetchRequest.fetchLimit = fetchLimit
46 | }
47 |
48 | var result: [Self]?
49 | context.performAndWait { () -> Void in
50 | do {
51 | result = try context.fetch(fetchRequest) as? [Self]
52 | } catch {
53 | result = nil
54 | //Report Error
55 | print("CoreData fetch error \(error)")
56 | }
57 | }
58 | return result
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // BetterCoreData
4 | //
5 | // Created by Michal Wojtysiak on 23/11/2016.
6 | // Copyright © 2016 Michal Wojtysiak. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/CoreDataWorker2.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CoreDataWorker2.swift
3 | // BetterCoreData
4 | //
5 | // Created by Michal Wojtysiak on 23/11/2016.
6 | // Copyright © 2016 Michal Wojtysiak. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol NewCoreDataWorkerProtocol {
12 | func get
13 | (with predicate: NSPredicate?,
14 | sortDescriptors: [NSSortDescriptor]?,
15 | fetchLimit: Int?,
16 | completion: @escaping (Result<[Entity], Error>) -> Void)
17 | func upsert
18 | (entities: [Entity],
19 | completion: @escaping (Error?) -> Void)
20 |
21 | }
22 |
23 | extension NewCoreDataWorkerProtocol {
24 | func get
25 | (with predicate: NSPredicate? = nil,
26 | sortDescriptors: [NSSortDescriptor]? = nil,
27 | fetchLimit: Int? = nil,
28 | completion: @escaping (Result<[Entity], Error>) -> Void) {
29 | get(with: predicate,
30 | sortDescriptors: sortDescriptors,
31 | fetchLimit: fetchLimit,
32 | completion: completion)
33 | }
34 | }
35 |
36 |
37 | class NewCoreDataWorker: NewCoreDataWorkerProtocol {
38 | let coreData: CoreDataServiceProtocol
39 |
40 | init(coreData: CoreDataServiceProtocol = CoreDataService.shared) {
41 | self.coreData = coreData
42 | }
43 |
44 | func get
45 | (with predicate: NSPredicate?,
46 | sortDescriptors: [NSSortDescriptor]?,
47 | fetchLimit: Int?,
48 | completion: @escaping (Result<[Entity], Error>) -> Void) {
49 | coreData.performForegroundTask { context in
50 | do {
51 | let fetchRequest = Entity.ManagedObject.fetchRequest()
52 | fetchRequest.predicate = predicate
53 | fetchRequest.sortDescriptors = sortDescriptors
54 | if let fetchLimit = fetchLimit {
55 | fetchRequest.fetchLimit = fetchLimit
56 | }
57 | let results = try context.fetch(fetchRequest) as? [Entity.ManagedObject]
58 | let items: [Entity] = results?.compactMap { $0.toEntity() as? Entity } ?? []
59 | completion(.success(items))
60 | } catch {
61 | let fetchError = CoreDataWorkerError.cannotFetch("Cannot fetch error: \(error))")
62 | completion(.failure(fetchError))
63 | }
64 | }
65 | }
66 |
67 | func upsert
68 | (entities: [Entity],
69 | completion: @escaping (Error?) -> Void) {
70 |
71 | coreData.performBackgroundTask { context in
72 | _ = entities.compactMap({ (entity) -> Entity.ManagedObject? in
73 | return entity.toManagedObject(in: context)
74 | })
75 | do {
76 | try context.save()
77 | completion(nil)
78 | } catch {
79 | completion(CoreDataWorkerError.cannotSave(error))
80 | }
81 | }
82 | }
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/CoreDataWorker1.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CoreDataWorker1.swift
3 | // BetterCoreData
4 | //
5 | // Created by Michal Wojtysiak on 23/11/2016.
6 | // Copyright © 2016 Michal Wojtysiak. All rights reserved.
7 | //
8 |
9 | import CoreData
10 |
11 | protocol CoreDataWorkerProtocol {
12 | associatedtype EntityType
13 | func get(with predicate: NSPredicate?,
14 | sortDescriptors: [NSSortDescriptor]?,
15 | fetchLimit: Int?,
16 | completion: @escaping (Result<[EntityType], Error>) -> Void)
17 | func upsert(entities: [EntityType],
18 | completion: @escaping (Error?) -> Void)
19 | }
20 |
21 | extension CoreDataWorkerProtocol {
22 | func get(with predicate: NSPredicate? = nil,
23 | sortDescriptors: [NSSortDescriptor]? = nil,
24 | fetchLimit: Int? = nil,
25 | completion: @escaping (Result<[EntityType], Error>) -> Void){
26 | get(with: predicate,
27 | sortDescriptors: sortDescriptors,
28 | fetchLimit: fetchLimit,
29 | completion: completion)
30 | }
31 | }
32 |
33 | enum CoreDataWorkerError: Error{
34 | case cannotFetch(String)
35 | case cannotSave(Error)
36 | }
37 |
38 | class CoreDataWorker: CoreDataWorkerProtocol where
39 | ManagedEntity: NSManagedObject,
40 | ManagedEntity: ManagedObjectProtocol,
41 | Entity: ManagedObjectConvertible {
42 |
43 | let coreData: CoreDataServiceProtocol
44 | init(coreData: CoreDataServiceProtocol = CoreDataService.shared) {
45 | self.coreData = coreData
46 | }
47 |
48 | func get(with predicate: NSPredicate?, sortDescriptors: [NSSortDescriptor]?, fetchLimit: Int?,
49 | completion: @escaping (Result<[Entity], Error>) -> Void) {
50 |
51 | coreData.performForegroundTask { (context) in
52 | do {
53 | let fetchRequest = ManagedEntity.fetchRequest()
54 | fetchRequest.predicate = predicate
55 | fetchRequest.sortDescriptors = sortDescriptors
56 | if let fetchLimit = fetchLimit {
57 | fetchRequest.fetchLimit = fetchLimit
58 | }
59 | let results = try context.fetch(fetchRequest) as? [ManagedEntity]
60 | let items: [Entity] = results?.compactMap { $0.toEntity() as? Entity } ?? []
61 | completion(.success(items))
62 | } catch {
63 | let fetchError = CoreDataWorkerError.cannotFetch("Cannot fetch error: \(error))")
64 | completion(.failure(fetchError))
65 | }
66 | }
67 | }
68 |
69 | func upsert(entities: [Entity], completion: @escaping (Error?) -> Void) {
70 | coreData.performBackgroundTask { (context) in
71 | _ = entities.compactMap({ (entity) -> ManagedEntity? in
72 | return entity.toManagedObject(in: context) as? ManagedEntity
73 | })
74 | do {
75 | try context.save()
76 | completion(nil)
77 | } catch {
78 | completion(CoreDataWorkerError.cannotSave(error))
79 | }
80 | }
81 | }
82 |
83 | // other methods: remove, ...
84 | }
85 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData.xcodeproj/xcuserdata/michal.xcuserdatad/xcschemes/BetterCoreData.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
68 |
69 |
70 |
71 |
75 |
76 |
77 |
78 |
79 |
80 |
86 |
88 |
94 |
95 |
96 |
97 |
99 |
100 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // BetterCoreData
4 | //
5 | // Created by Michal Wojtysiak on 23/11/2016.
6 | // Copyright © 2016 Michal Wojtysiak. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 | let userController: UserDataControllerProtocol = NewUserDataController()
13 | // Switch between two implementations of CoreDataWorker
14 | //let userController: UserDataControllerProtocol = UserDataController()
15 |
16 | let nameTextField: UITextField = UITextField()
17 | let usernameTextField: UITextField = UITextField()
18 | let loadButton: UIButton = UIButton(type: UIButton.ButtonType.system)
19 | let updateButton: UIButton = UIButton(type: UIButton.ButtonType.system)
20 | let clearButton: UIButton = UIButton(type: UIButton.ButtonType.system)
21 |
22 | override func viewDidLoad() {
23 | super.viewDidLoad()
24 |
25 | configure(textField: nameTextField, with: "name")
26 | configure(textField: usernameTextField, with: "username")
27 | configure(button: loadButton, with: "Load", and: #selector(loadPressed))
28 | configure(button: updateButton, with: "Update", and: #selector(updatePressed))
29 | configure(button: clearButton, with: "Clear", and: #selector(clearPressed))
30 |
31 | view.addSubview(nameTextField)
32 | view.addSubview(usernameTextField)
33 | view.addSubview(loadButton)
34 | view.addSubview(updateButton)
35 | view.addSubview(clearButton)
36 |
37 | setupConstraints()
38 | loadUser()
39 | }
40 |
41 | private func configure(textField: UITextField, with placeholder: String? = nil){
42 | textField.translatesAutoresizingMaskIntoConstraints = false
43 | textField.placeholder = placeholder
44 | textField.textAlignment = .center
45 | textField.autocapitalizationType = .none
46 | textField.layer.borderWidth = 0.5
47 | textField.layer.borderColor = UIColor.lightGray.cgColor
48 | textField.layer.cornerRadius = 5.0
49 | textField.widthAnchor.constraint(equalToConstant: 200.0).isActive = true
50 | textField.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
51 | }
52 |
53 | private func configure(button: UIButton, with title: String, and action: Selector){
54 | button.translatesAutoresizingMaskIntoConstraints = false
55 | button.setTitle(title, for: .normal)
56 | button.addTarget(self, action: action, for: .touchUpInside)
57 | button.widthAnchor.constraint(equalToConstant: 60.0).isActive = true
58 | button.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
59 | }
60 |
61 | private func setupConstraints(){
62 |
63 | nameTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
64 | nameTextField.centerYAnchor.constraint(equalTo: view.topAnchor,
65 | constant: 100.0).isActive = true
66 |
67 | usernameTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
68 | usernameTextField.topAnchor.constraint(equalTo: nameTextField.bottomAnchor,
69 | constant: 20.0).isActive = true
70 |
71 | updateButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
72 | updateButton.topAnchor.constraint(equalTo: usernameTextField.bottomAnchor,
73 | constant: 20.0).isActive = true
74 |
75 | loadButton.trailingAnchor.constraint(equalTo: updateButton.leadingAnchor,
76 | constant: -20).isActive = true
77 | loadButton.topAnchor.constraint(equalTo: updateButton.topAnchor).isActive = true
78 |
79 | clearButton.leadingAnchor.constraint(equalTo: updateButton.trailingAnchor,
80 | constant: 20).isActive = true
81 | clearButton.topAnchor.constraint(equalTo: updateButton.topAnchor).isActive = true
82 | }
83 |
84 | private func loadUser(){
85 | userController.fetchUser { (user) in
86 | guard let user = user else { return }
87 | self.nameTextField.text = user.name
88 | self.usernameTextField.text = user.username
89 | }
90 | }
91 |
92 | @objc private func updatePressed(){
93 | userController.updateUser(name: nameTextField.text ?? "",
94 | username: usernameTextField.text ?? "")
95 | }
96 |
97 | @objc private func loadPressed(){
98 | loadUser()
99 | }
100 |
101 | @objc private func clearPressed(){
102 | nameTextField.text = nil
103 | usernameTextField.text = nil
104 | }
105 | }
106 |
107 |
--------------------------------------------------------------------------------
/BetterCoreData/BetterCoreData.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 9028456D1DE8EB3B0004F96E /* NewUserDataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9028456C1DE8EB3B0004F96E /* NewUserDataController.swift */; };
11 | 9028456F1DE971490004F96E /* UserDataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9028456E1DE971490004F96E /* UserDataController.swift */; };
12 | 90C768311DE61BD200EF2926 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C768301DE61BD200EF2926 /* AppDelegate.swift */; };
13 | 90C768331DE61BD200EF2926 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C768321DE61BD200EF2926 /* ViewController.swift */; };
14 | 90C768361DE61BD200EF2926 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90C768341DE61BD200EF2926 /* Main.storyboard */; };
15 | 90C768381DE61BD200EF2926 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 90C768371DE61BD200EF2926 /* Assets.xcassets */; };
16 | 90C7683B1DE61BD200EF2926 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90C768391DE61BD200EF2926 /* LaunchScreen.storyboard */; };
17 | 90C768471DE61C5600EF2926 /* DataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 90C768451DE61C5600EF2926 /* DataModel.xcdatamodeld */; };
18 | 90C7684A1DE61D0100EF2926 /* UserMO+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C768481DE61D0100EF2926 /* UserMO+CoreDataClass.swift */; };
19 | 90C7684B1DE61D0100EF2926 /* UserMO+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C768491DE61D0100EF2926 /* UserMO+CoreDataProperties.swift */; };
20 | 90C7684D1DE61D1900EF2926 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C7684C1DE61D1900EF2926 /* User.swift */; };
21 | 90C7684F1DE61F5A00EF2926 /* ManagedObjectProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C7684E1DE61F5A00EF2926 /* ManagedObjectProtocol.swift */; };
22 | 90C768511DE61F6900EF2926 /* ManagedObjectConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C768501DE61F6900EF2926 /* ManagedObjectConvertible.swift */; };
23 | 90C768531DE6205300EF2926 /* CoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C768521DE6205300EF2926 /* CoreDataStack.swift */; };
24 | 90C7685A1DE620E600EF2926 /* CoreDataWorker1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C768591DE620E600EF2926 /* CoreDataWorker1.swift */; };
25 | 90C7685C1DE620F600EF2926 /* CoreDataWorker2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C7685B1DE620F600EF2926 /* CoreDataWorker2.swift */; };
26 | /* End PBXBuildFile section */
27 |
28 | /* Begin PBXFileReference section */
29 | 9028456C1DE8EB3B0004F96E /* NewUserDataController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewUserDataController.swift; sourceTree = ""; };
30 | 9028456E1DE971490004F96E /* UserDataController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDataController.swift; sourceTree = ""; };
31 | 90C7682D1DE61BD100EF2926 /* BetterCoreData.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BetterCoreData.app; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 90C768301DE61BD200EF2926 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
33 | 90C768321DE61BD200EF2926 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
34 | 90C768351DE61BD200EF2926 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
35 | 90C768371DE61BD200EF2926 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
36 | 90C7683A1DE61BD200EF2926 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
37 | 90C7683C1DE61BD200EF2926 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
38 | 90C768461DE61C5600EF2926 /* DataModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = DataModel.xcdatamodel; sourceTree = ""; };
39 | 90C768481DE61D0100EF2926 /* UserMO+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserMO+CoreDataClass.swift"; sourceTree = ""; };
40 | 90C768491DE61D0100EF2926 /* UserMO+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserMO+CoreDataProperties.swift"; sourceTree = ""; };
41 | 90C7684C1DE61D1900EF2926 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; };
42 | 90C7684E1DE61F5A00EF2926 /* ManagedObjectProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedObjectProtocol.swift; sourceTree = ""; };
43 | 90C768501DE61F6900EF2926 /* ManagedObjectConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedObjectConvertible.swift; sourceTree = ""; };
44 | 90C768521DE6205300EF2926 /* CoreDataStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataStack.swift; sourceTree = ""; };
45 | 90C768591DE620E600EF2926 /* CoreDataWorker1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataWorker1.swift; sourceTree = ""; };
46 | 90C7685B1DE620F600EF2926 /* CoreDataWorker2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataWorker2.swift; sourceTree = ""; };
47 | /* End PBXFileReference section */
48 |
49 | /* Begin PBXFrameworksBuildPhase section */
50 | 90C7682A1DE61BD100EF2926 /* Frameworks */ = {
51 | isa = PBXFrameworksBuildPhase;
52 | buildActionMask = 2147483647;
53 | files = (
54 | );
55 | runOnlyForDeploymentPostprocessing = 0;
56 | };
57 | /* End PBXFrameworksBuildPhase section */
58 |
59 | /* Begin PBXGroup section */
60 | 90C768241DE61BD100EF2926 = {
61 | isa = PBXGroup;
62 | children = (
63 | 90C7682F1DE61BD200EF2926 /* BetterCoreData */,
64 | 90C7682E1DE61BD200EF2926 /* Products */,
65 | );
66 | sourceTree = "";
67 | };
68 | 90C7682E1DE61BD200EF2926 /* Products */ = {
69 | isa = PBXGroup;
70 | children = (
71 | 90C7682D1DE61BD100EF2926 /* BetterCoreData.app */,
72 | );
73 | name = Products;
74 | sourceTree = "";
75 | };
76 | 90C7682F1DE61BD200EF2926 /* BetterCoreData */ = {
77 | isa = PBXGroup;
78 | children = (
79 | 90C768301DE61BD200EF2926 /* AppDelegate.swift */,
80 | 90C768321DE61BD200EF2926 /* ViewController.swift */,
81 | 9028456C1DE8EB3B0004F96E /* NewUserDataController.swift */,
82 | 9028456E1DE971490004F96E /* UserDataController.swift */,
83 | 90C768581DE620D100EF2926 /* CoreData */,
84 | 90C768441DE61C3F00EF2926 /* Model */,
85 | 90C768431DE61C1F00EF2926 /* Storyboards */,
86 | 90C768421DE61C0E00EF2926 /* Resources */,
87 | );
88 | path = BetterCoreData;
89 | sourceTree = "";
90 | };
91 | 90C768421DE61C0E00EF2926 /* Resources */ = {
92 | isa = PBXGroup;
93 | children = (
94 | 90C7683C1DE61BD200EF2926 /* Info.plist */,
95 | 90C768371DE61BD200EF2926 /* Assets.xcassets */,
96 | );
97 | name = Resources;
98 | sourceTree = "";
99 | };
100 | 90C768431DE61C1F00EF2926 /* Storyboards */ = {
101 | isa = PBXGroup;
102 | children = (
103 | 90C768341DE61BD200EF2926 /* Main.storyboard */,
104 | 90C768391DE61BD200EF2926 /* LaunchScreen.storyboard */,
105 | );
106 | name = Storyboards;
107 | sourceTree = "";
108 | };
109 | 90C768441DE61C3F00EF2926 /* Model */ = {
110 | isa = PBXGroup;
111 | children = (
112 | 90C7684C1DE61D1900EF2926 /* User.swift */,
113 | 90C768481DE61D0100EF2926 /* UserMO+CoreDataClass.swift */,
114 | 90C768491DE61D0100EF2926 /* UserMO+CoreDataProperties.swift */,
115 | 90C768451DE61C5600EF2926 /* DataModel.xcdatamodeld */,
116 | 90C7684E1DE61F5A00EF2926 /* ManagedObjectProtocol.swift */,
117 | 90C768501DE61F6900EF2926 /* ManagedObjectConvertible.swift */,
118 | );
119 | name = Model;
120 | sourceTree = "";
121 | };
122 | 90C768581DE620D100EF2926 /* CoreData */ = {
123 | isa = PBXGroup;
124 | children = (
125 | 90C768521DE6205300EF2926 /* CoreDataStack.swift */,
126 | 90C768591DE620E600EF2926 /* CoreDataWorker1.swift */,
127 | 90C7685B1DE620F600EF2926 /* CoreDataWorker2.swift */,
128 | );
129 | name = CoreData;
130 | sourceTree = "";
131 | };
132 | /* End PBXGroup section */
133 |
134 | /* Begin PBXNativeTarget section */
135 | 90C7682C1DE61BD100EF2926 /* BetterCoreData */ = {
136 | isa = PBXNativeTarget;
137 | buildConfigurationList = 90C7683F1DE61BD200EF2926 /* Build configuration list for PBXNativeTarget "BetterCoreData" */;
138 | buildPhases = (
139 | 90C768291DE61BD100EF2926 /* Sources */,
140 | 90C7682A1DE61BD100EF2926 /* Frameworks */,
141 | 90C7682B1DE61BD100EF2926 /* Resources */,
142 | );
143 | buildRules = (
144 | );
145 | dependencies = (
146 | );
147 | name = BetterCoreData;
148 | productName = BetterCoreData;
149 | productReference = 90C7682D1DE61BD100EF2926 /* BetterCoreData.app */;
150 | productType = "com.apple.product-type.application";
151 | };
152 | /* End PBXNativeTarget section */
153 |
154 | /* Begin PBXProject section */
155 | 90C768251DE61BD100EF2926 /* Project object */ = {
156 | isa = PBXProject;
157 | attributes = {
158 | LastSwiftUpdateCheck = 0810;
159 | LastUpgradeCheck = 1020;
160 | ORGANIZATIONNAME = "Michal Wojtysiak";
161 | TargetAttributes = {
162 | 90C7682C1DE61BD100EF2926 = {
163 | CreatedOnToolsVersion = 8.1;
164 | ProvisioningStyle = Automatic;
165 | SystemCapabilities = {
166 | com.apple.DataProtection = {
167 | enabled = 0;
168 | };
169 | };
170 | };
171 | };
172 | };
173 | buildConfigurationList = 90C768281DE61BD100EF2926 /* Build configuration list for PBXProject "BetterCoreData" */;
174 | compatibilityVersion = "Xcode 3.2";
175 | developmentRegion = English;
176 | hasScannedForEncodings = 0;
177 | knownRegions = (
178 | English,
179 | en,
180 | Base,
181 | );
182 | mainGroup = 90C768241DE61BD100EF2926;
183 | productRefGroup = 90C7682E1DE61BD200EF2926 /* Products */;
184 | projectDirPath = "";
185 | projectRoot = "";
186 | targets = (
187 | 90C7682C1DE61BD100EF2926 /* BetterCoreData */,
188 | );
189 | };
190 | /* End PBXProject section */
191 |
192 | /* Begin PBXResourcesBuildPhase section */
193 | 90C7682B1DE61BD100EF2926 /* Resources */ = {
194 | isa = PBXResourcesBuildPhase;
195 | buildActionMask = 2147483647;
196 | files = (
197 | 90C7683B1DE61BD200EF2926 /* LaunchScreen.storyboard in Resources */,
198 | 90C768381DE61BD200EF2926 /* Assets.xcassets in Resources */,
199 | 90C768361DE61BD200EF2926 /* Main.storyboard in Resources */,
200 | );
201 | runOnlyForDeploymentPostprocessing = 0;
202 | };
203 | /* End PBXResourcesBuildPhase section */
204 |
205 | /* Begin PBXSourcesBuildPhase section */
206 | 90C768291DE61BD100EF2926 /* Sources */ = {
207 | isa = PBXSourcesBuildPhase;
208 | buildActionMask = 2147483647;
209 | files = (
210 | 90C7684A1DE61D0100EF2926 /* UserMO+CoreDataClass.swift in Sources */,
211 | 90C7685C1DE620F600EF2926 /* CoreDataWorker2.swift in Sources */,
212 | 90C7684F1DE61F5A00EF2926 /* ManagedObjectProtocol.swift in Sources */,
213 | 90C768511DE61F6900EF2926 /* ManagedObjectConvertible.swift in Sources */,
214 | 9028456D1DE8EB3B0004F96E /* NewUserDataController.swift in Sources */,
215 | 90C768531DE6205300EF2926 /* CoreDataStack.swift in Sources */,
216 | 9028456F1DE971490004F96E /* UserDataController.swift in Sources */,
217 | 90C7684B1DE61D0100EF2926 /* UserMO+CoreDataProperties.swift in Sources */,
218 | 90C7685A1DE620E600EF2926 /* CoreDataWorker1.swift in Sources */,
219 | 90C7684D1DE61D1900EF2926 /* User.swift in Sources */,
220 | 90C768471DE61C5600EF2926 /* DataModel.xcdatamodeld in Sources */,
221 | 90C768331DE61BD200EF2926 /* ViewController.swift in Sources */,
222 | 90C768311DE61BD200EF2926 /* AppDelegate.swift in Sources */,
223 | );
224 | runOnlyForDeploymentPostprocessing = 0;
225 | };
226 | /* End PBXSourcesBuildPhase section */
227 |
228 | /* Begin PBXVariantGroup section */
229 | 90C768341DE61BD200EF2926 /* Main.storyboard */ = {
230 | isa = PBXVariantGroup;
231 | children = (
232 | 90C768351DE61BD200EF2926 /* Base */,
233 | );
234 | name = Main.storyboard;
235 | sourceTree = "";
236 | };
237 | 90C768391DE61BD200EF2926 /* LaunchScreen.storyboard */ = {
238 | isa = PBXVariantGroup;
239 | children = (
240 | 90C7683A1DE61BD200EF2926 /* Base */,
241 | );
242 | name = LaunchScreen.storyboard;
243 | sourceTree = "";
244 | };
245 | /* End PBXVariantGroup section */
246 |
247 | /* Begin XCBuildConfiguration section */
248 | 90C7683D1DE61BD200EF2926 /* Debug */ = {
249 | isa = XCBuildConfiguration;
250 | buildSettings = {
251 | ALWAYS_SEARCH_USER_PATHS = NO;
252 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
253 | CLANG_ANALYZER_NONNULL = YES;
254 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
255 | CLANG_CXX_LIBRARY = "libc++";
256 | CLANG_ENABLE_MODULES = YES;
257 | CLANG_ENABLE_OBJC_ARC = YES;
258 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
259 | CLANG_WARN_BOOL_CONVERSION = YES;
260 | CLANG_WARN_COMMA = YES;
261 | CLANG_WARN_CONSTANT_CONVERSION = YES;
262 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
263 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
264 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
265 | CLANG_WARN_EMPTY_BODY = YES;
266 | CLANG_WARN_ENUM_CONVERSION = YES;
267 | CLANG_WARN_INFINITE_RECURSION = YES;
268 | CLANG_WARN_INT_CONVERSION = YES;
269 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
270 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
271 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
272 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
273 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
274 | CLANG_WARN_STRICT_PROTOTYPES = YES;
275 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
276 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
277 | CLANG_WARN_UNREACHABLE_CODE = YES;
278 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
279 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
280 | COPY_PHASE_STRIP = NO;
281 | DEBUG_INFORMATION_FORMAT = dwarf;
282 | ENABLE_STRICT_OBJC_MSGSEND = YES;
283 | ENABLE_TESTABILITY = YES;
284 | GCC_C_LANGUAGE_STANDARD = gnu99;
285 | GCC_DYNAMIC_NO_PIC = NO;
286 | GCC_NO_COMMON_BLOCKS = YES;
287 | GCC_OPTIMIZATION_LEVEL = 0;
288 | GCC_PREPROCESSOR_DEFINITIONS = (
289 | "DEBUG=1",
290 | "$(inherited)",
291 | );
292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
294 | GCC_WARN_UNDECLARED_SELECTOR = YES;
295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
296 | GCC_WARN_UNUSED_FUNCTION = YES;
297 | GCC_WARN_UNUSED_VARIABLE = YES;
298 | IPHONEOS_DEPLOYMENT_TARGET = 10.1;
299 | MTL_ENABLE_DEBUG_INFO = YES;
300 | ONLY_ACTIVE_ARCH = YES;
301 | SDKROOT = iphoneos;
302 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
303 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
304 | };
305 | name = Debug;
306 | };
307 | 90C7683E1DE61BD200EF2926 /* Release */ = {
308 | isa = XCBuildConfiguration;
309 | buildSettings = {
310 | ALWAYS_SEARCH_USER_PATHS = NO;
311 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
312 | CLANG_ANALYZER_NONNULL = YES;
313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
314 | CLANG_CXX_LIBRARY = "libc++";
315 | CLANG_ENABLE_MODULES = YES;
316 | CLANG_ENABLE_OBJC_ARC = YES;
317 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
318 | CLANG_WARN_BOOL_CONVERSION = YES;
319 | CLANG_WARN_COMMA = YES;
320 | CLANG_WARN_CONSTANT_CONVERSION = YES;
321 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
322 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
323 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
324 | CLANG_WARN_EMPTY_BODY = YES;
325 | CLANG_WARN_ENUM_CONVERSION = YES;
326 | CLANG_WARN_INFINITE_RECURSION = YES;
327 | CLANG_WARN_INT_CONVERSION = YES;
328 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
329 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
330 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
331 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
332 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
333 | CLANG_WARN_STRICT_PROTOTYPES = YES;
334 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
335 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
336 | CLANG_WARN_UNREACHABLE_CODE = YES;
337 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
338 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
339 | COPY_PHASE_STRIP = NO;
340 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
341 | ENABLE_NS_ASSERTIONS = NO;
342 | ENABLE_STRICT_OBJC_MSGSEND = YES;
343 | GCC_C_LANGUAGE_STANDARD = gnu99;
344 | GCC_NO_COMMON_BLOCKS = YES;
345 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
346 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
347 | GCC_WARN_UNDECLARED_SELECTOR = YES;
348 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
349 | GCC_WARN_UNUSED_FUNCTION = YES;
350 | GCC_WARN_UNUSED_VARIABLE = YES;
351 | IPHONEOS_DEPLOYMENT_TARGET = 10.1;
352 | MTL_ENABLE_DEBUG_INFO = NO;
353 | SDKROOT = iphoneos;
354 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
355 | VALIDATE_PRODUCT = YES;
356 | };
357 | name = Release;
358 | };
359 | 90C768401DE61BD200EF2926 /* Debug */ = {
360 | isa = XCBuildConfiguration;
361 | buildSettings = {
362 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
363 | DEVELOPMENT_TEAM = "";
364 | INFOPLIST_FILE = BetterCoreData/Info.plist;
365 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
366 | PRODUCT_BUNDLE_IDENTIFIER = com.swiftingio.BetterCoreData;
367 | PRODUCT_NAME = "$(TARGET_NAME)";
368 | SWIFT_VERSION = 5.0;
369 | };
370 | name = Debug;
371 | };
372 | 90C768411DE61BD200EF2926 /* Release */ = {
373 | isa = XCBuildConfiguration;
374 | buildSettings = {
375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
376 | DEVELOPMENT_TEAM = "";
377 | INFOPLIST_FILE = BetterCoreData/Info.plist;
378 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
379 | PRODUCT_BUNDLE_IDENTIFIER = com.swiftingio.BetterCoreData;
380 | PRODUCT_NAME = "$(TARGET_NAME)";
381 | SWIFT_VERSION = 5.0;
382 | };
383 | name = Release;
384 | };
385 | /* End XCBuildConfiguration section */
386 |
387 | /* Begin XCConfigurationList section */
388 | 90C768281DE61BD100EF2926 /* Build configuration list for PBXProject "BetterCoreData" */ = {
389 | isa = XCConfigurationList;
390 | buildConfigurations = (
391 | 90C7683D1DE61BD200EF2926 /* Debug */,
392 | 90C7683E1DE61BD200EF2926 /* Release */,
393 | );
394 | defaultConfigurationIsVisible = 0;
395 | defaultConfigurationName = Release;
396 | };
397 | 90C7683F1DE61BD200EF2926 /* Build configuration list for PBXNativeTarget "BetterCoreData" */ = {
398 | isa = XCConfigurationList;
399 | buildConfigurations = (
400 | 90C768401DE61BD200EF2926 /* Debug */,
401 | 90C768411DE61BD200EF2926 /* Release */,
402 | );
403 | defaultConfigurationIsVisible = 0;
404 | defaultConfigurationName = Release;
405 | };
406 | /* End XCConfigurationList section */
407 |
408 | /* Begin XCVersionGroup section */
409 | 90C768451DE61C5600EF2926 /* DataModel.xcdatamodeld */ = {
410 | isa = XCVersionGroup;
411 | children = (
412 | 90C768461DE61C5600EF2926 /* DataModel.xcdatamodel */,
413 | );
414 | currentVersion = 90C768461DE61C5600EF2926 /* DataModel.xcdatamodel */;
415 | path = DataModel.xcdatamodeld;
416 | sourceTree = "";
417 | versionGroupType = wrapper.xcdatamodel;
418 | };
419 | /* End XCVersionGroup section */
420 | };
421 | rootObject = 90C768251DE61BD100EF2926 /* Project object */;
422 | }
423 |
--------------------------------------------------------------------------------