├── ShoppingList
├── Resources
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ └── Preview Content
│ │ └── Preview Assets.xcassets
│ │ └── Contents.json
├── Extensions
│ ├── Item.swift
│ ├── View.swift
│ └── FetchedResults.swift
├── Models
│ ├── ShoppingList.xcdatamodeld
│ │ ├── .xccurrentversion
│ │ └── ShoppingList.xcdatamodel
│ │ │ └── contents
│ └── ListManager.swift
├── Views
│ ├── AddButton.swift
│ ├── Cell.swift
│ └── ContentView.swift
├── Delegates
│ ├── Scene.swift
│ └── App.swift
└── App Launch
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ └── Info.plist
├── ShoppingList.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── ericlewis.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
├── README.md
├── LICENSE
└── .gitignore
/ShoppingList/Resources/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/ShoppingList/Resources/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/ShoppingList.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ShoppingList.xcodeproj/xcuserdata/ericlewis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/ShoppingList.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ShoppingList/Extensions/Item.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | extension Item: OrderableManagedObjectProtocol {}
4 |
5 | extension Item {
6 | var checkbox: String {
7 | isComplete ? "checkmark.square.fill" : "square"
8 | }
9 |
10 | var checkboxColor: Color {
11 | isComplete ? .green : .secondary
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ShoppingList/Models/ShoppingList.xcdatamodeld/.xccurrentversion:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | _XCCurrentVersionName
6 | ShoppingList.xcdatamodel
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ShoppingList/Extensions/View.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import CoreData
3 |
4 | extension View {
5 | static var listFetchRequest: NSFetchRequest- {
6 | let request: NSFetchRequest
- = Item.fetchRequest()
7 | request.sortDescriptors = [NSSortDescriptor(key: "order", ascending: true)]
8 |
9 | return request
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ShoppingList
2 | An example of using SwiftUI + CoreData
3 |
4 | ## Screenshots
5 | |
|
|
6 |
7 | ## Running
8 | Must use the latest Xcode 11 beta, and be running some sort of beta software probably. This tries to use CloudKit, but haven't tested if it actually works.
9 |
--------------------------------------------------------------------------------
/ShoppingList.xcodeproj/xcuserdata/ericlewis.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ShoppingList.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ShoppingList/Views/AddButton.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct AddButton: View {
4 |
5 | // MARK: Type aliases
6 |
7 | typealias Action = () -> Void
8 |
9 | // MARK: Public properties
10 |
11 | var showAddField: Bool
12 |
13 | var action: Action
14 |
15 | // MARK: Initializers
16 |
17 | init(_ showAddField: Bool, action: @escaping Action) {
18 | self.showAddField = showAddField
19 | self.action = action
20 | }
21 |
22 | // MARK: Render
23 |
24 | var body: some View {
25 | Button(action: action) {
26 | if showAddField {
27 | Text("Cancel")
28 | } else {
29 | Image(systemName: "plus")
30 | }
31 | }
32 | }
33 | }
34 |
35 | // MARK: Preview
36 |
37 | #if DEBUG
38 | struct AddButton_Previews: PreviewProvider {
39 | static var previews: some View {
40 | AddButton(false) {}
41 | }
42 | }
43 | #endif
44 |
--------------------------------------------------------------------------------
/ShoppingList/Models/ShoppingList.xcdatamodeld/ShoppingList.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Eric Lewis
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ShoppingList/Models/ListManager.swift:
--------------------------------------------------------------------------------
1 | import CoreData
2 |
3 | class ListManager: ObservableObject {
4 | var context: NSManagedObjectContext
5 |
6 | init(context: NSManagedObjectContext) {
7 | self.context = context
8 | }
9 |
10 | func toggleComplete(_ item: Item) -> () -> Void {
11 | func toggleComplete() {
12 | context.perform {
13 | item.objectWillChange.send()
14 | item.isComplete.toggle()
15 | try? self.context.save()
16 | }
17 | }
18 |
19 | return toggleComplete
20 | }
21 |
22 | func add(_ title: String, count: Int, notes: String? = nil) {
23 | context.perform {
24 | let item = Item(context: self.context)
25 |
26 | if title.isEmpty && notes != nil && !notes!.isEmpty {
27 | item.title = notes
28 | } else {
29 | item.title = title
30 | item.notes = notes
31 | }
32 |
33 | item.order = Int32(count)
34 |
35 | try? self.context.save()
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ShoppingList/Views/Cell.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct Cell: View {
4 |
5 | // MARK: Environment properties
6 |
7 | @EnvironmentObject var manager: ListManager
8 |
9 | // MARK: Observed objects
10 |
11 | @ObservedObject var item: Item
12 |
13 | // MARK: Render
14 |
15 | var body: some View {
16 | Button(action: manager.toggleComplete(item)) {
17 | HStack {
18 | Image(systemName: item.checkbox)
19 | .foregroundColor(item.checkboxColor)
20 | VStack(alignment: .leading) {
21 | Text(item.title ?? "")
22 | .font(.headline)
23 | .foregroundColor(.primary)
24 | if item.notes != nil {
25 | Text(item.notes ?? "")
26 | .font(.subheadline)
27 | .foregroundColor(.secondary)
28 | }
29 | }
30 | }
31 | }
32 | }
33 | }
34 |
35 | // MARK: Preview
36 |
37 | #if DEBUG
38 | struct Cell_Previews: PreviewProvider {
39 | static var previews: some View {
40 | Cell(item: Item())
41 | }
42 | }
43 | #endif
44 |
--------------------------------------------------------------------------------
/ShoppingList/Delegates/Scene.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import SwiftUI
3 |
4 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
5 |
6 | var window: UIWindow?
7 |
8 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
9 | if let windowScene = scene as? UIWindowScene {
10 | let container = (UIApplication.shared.delegate as? AppDelegate)!.persistentContainer
11 | let context = container.viewContext
12 | let rootView = ContentView()
13 | .environment(\.managedObjectContext, context)
14 | .environmentObject(ListManager(context: context))
15 |
16 | let window = UIWindow(windowScene: windowScene)
17 | window.rootViewController = UIHostingController(rootView: rootView)
18 | self.window = window
19 | window.makeKeyAndVisible()
20 | }
21 | }
22 |
23 | func sceneDidEnterBackground(_ scene: UIScene) {
24 | // Called as the scene transitions from the foreground to the background.
25 | // Use this method to save data, release shared resources, and store enough scene-specific state information
26 | // to restore the scene back to its current state.
27 |
28 | // Save changes in the application's managed object context when the application transitions to the background.
29 | (UIApplication.shared.delegate as? AppDelegate)?.saveContext()
30 | }
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/ShoppingList/Extensions/FetchedResults.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import CoreData
3 |
4 | protocol OrderableManagedObjectProtocol: AnyObject {
5 | var order: Int32 {get set}
6 | }
7 |
8 | extension FetchedResults where Result: NSManagedObject {
9 | func delete(_ managedObjectContext: NSManagedObjectContext) -> (IndexSet) -> Void {
10 | func delete(_ offset: IndexSet) {
11 | var arr = Array(self)
12 | arr.remove(atOffsets: offset)
13 |
14 | let diff = arr.difference(from: self)
15 | for change in diff {
16 | switch change {
17 | case let .remove(_, element, _):
18 | managedObjectContext.delete(element)
19 | try? managedObjectContext.save()
20 | case .insert(_, _, _):
21 | print("nothing")
22 | }
23 | }
24 | }
25 |
26 | return delete
27 | }
28 | }
29 |
30 | extension FetchedResults where Result: OrderableManagedObjectProtocol {
31 | func move(_ managedObjectContext: NSManagedObjectContext) -> (IndexSet, Int) -> Void {
32 | func move(_ offset: IndexSet, _ destination: Int) {
33 | managedObjectContext.perform {
34 | var arr = Array(self)
35 | arr.move(fromOffsets: offset, toOffset: destination)
36 | for i in 0..
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 |
--------------------------------------------------------------------------------
/ShoppingList/Resources/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 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/ShoppingList/App Launch/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UIBackgroundModes
41 |
42 | remote-notification
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIRequiredDeviceCapabilities
47 |
48 | armv7
49 |
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 | UISupportedInterfaceOrientations~ipad
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationPortraitUpsideDown
60 | UIInterfaceOrientationLandscapeLeft
61 | UIInterfaceOrientationLandscapeRight
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/ShoppingList/Views/ContentView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import CoreData
3 |
4 | struct ContentView: View {
5 |
6 | // MARK: Environment properties
7 |
8 | @Environment(\.managedObjectContext) var managedObjectContext
9 |
10 | @EnvironmentObject var manager: ListManager
11 |
12 | // MARK: State properties
13 |
14 | @State private var text = ""
15 |
16 | @State private var notes = ""
17 |
18 | @State private var isAdding = false {
19 | didSet {
20 | if !isAdding {
21 | self.text = ""
22 | self.notes = ""
23 | }
24 | }
25 | }
26 |
27 | // MARK: CoreData properties
28 |
29 | @FetchRequest(fetchRequest: listFetchRequest) var items: FetchedResults-
30 |
31 | // MARK: Private methods
32 |
33 | private func toggleAdding() {
34 | isAdding.toggle()
35 | }
36 |
37 | private func save() {
38 | manager.add(text, count: items.count, notes: notes.isEmpty ? nil : notes)
39 | isAdding = false
40 | }
41 |
42 | // MARK: Render
43 |
44 | var body: some View {
45 | NavigationView {
46 | Form {
47 | if isAdding {
48 | Section(header: Text("Add an Item")) {
49 | TextField("Title", text: $text, onCommit: save)
50 | TextField("Notes", text: $notes, onCommit: save)
51 | }
52 | }
53 | Section {
54 | ForEach(items, id: \.objectID) {
55 | Cell(item: $0)
56 | }
57 | .onDelete(perform: items.delete(managedObjectContext))
58 | .onMove(perform: items.move(managedObjectContext))
59 | }
60 | }
61 | .navigationBarTitle("My List")
62 | .navigationBarItems(leading: EditButton(),
63 | trailing: AddButton(isAdding,
64 | action: toggleAdding))
65 | }
66 | }
67 | }
68 |
69 | // MARK: Preview
70 |
71 | #if DEBUG
72 | struct ContentView_Previews: PreviewProvider {
73 | static var previews: some View {
74 | ContentView()
75 | }
76 | }
77 | #endif
78 |
--------------------------------------------------------------------------------
/ShoppingList/Delegates/App.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import CoreData
3 |
4 | @UIApplicationMain
5 | class AppDelegate: UIResponder, UIApplicationDelegate {
6 |
7 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
8 | // Override point for customization after application launch.
9 | return true
10 | }
11 |
12 | // MARK: UISceneSession Lifecycle
13 |
14 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
15 | // Called when a new scene session is being created.
16 | // Use this method to select a configuration to create the new scene with.
17 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
18 | }
19 |
20 | // MARK: - Core Data stack
21 |
22 | lazy var persistentContainer: NSPersistentCloudKitContainer = {
23 | /*
24 | The persistent container for the application. This implementation
25 | creates and returns a container, having loaded the store for the
26 | application to it. This property is optional since there are legitimate
27 | error conditions that could cause the creation of the store to fail.
28 | */
29 | let container = NSPersistentCloudKitContainer(name: "ShoppingList")
30 | container.loadPersistentStores(completionHandler: { (storeDescription, error) in
31 | if let error = error as NSError? {
32 | // Replace this implementation with code to handle the error appropriately.
33 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
34 |
35 | /*
36 | Typical reasons for an error here include:
37 | * The parent directory does not exist, cannot be created, or disallows writing.
38 | * The persistent store is not accessible, due to permissions or data protection when the device is locked.
39 | * The device is out of space.
40 | * The store could not be migrated to the current model version.
41 | Check the error message to determine what the actual problem was.
42 | */
43 | fatalError("Unresolved error \(error), \(error.userInfo)")
44 | }
45 | })
46 | return container
47 | }()
48 |
49 | // MARK: - Core Data Saving support
50 |
51 | func saveContext () {
52 | let context = persistentContainer.viewContext
53 | if context.hasChanges {
54 | do {
55 | try context.save()
56 | } catch {
57 | // Replace this implementation with code to handle the error appropriately.
58 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
59 | let nserror = error as NSError
60 | fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
61 | }
62 | }
63 | }
64 |
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/ShoppingList.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 68722F0422FC904700F00B6C /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68722F0322FC904700F00B6C /* App.swift */; };
11 | 68722F0622FC904700F00B6C /* Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68722F0522FC904700F00B6C /* Scene.swift */; };
12 | 68722F0922FC904700F00B6C /* ShoppingList.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 68722F0722FC904700F00B6C /* ShoppingList.xcdatamodeld */; };
13 | 68722F0B22FC904700F00B6C /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68722F0A22FC904700F00B6C /* ContentView.swift */; };
14 | 68722F0D22FC904900F00B6C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 68722F0C22FC904900F00B6C /* Assets.xcassets */; };
15 | 68722F1022FC904900F00B6C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 68722F0F22FC904900F00B6C /* Preview Assets.xcassets */; };
16 | 68722F1322FC904900F00B6C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 68722F1122FC904900F00B6C /* LaunchScreen.storyboard */; };
17 | 68722F1B22FCAE8C00F00B6C /* FetchedResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68722F1A22FCAE8C00F00B6C /* FetchedResults.swift */; };
18 | 68722F2322FCB2AA00F00B6C /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68722F2222FCB2AA00F00B6C /* Item.swift */; };
19 | 68722F2522FCB2D700F00B6C /* ListManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68722F2422FCB2D700F00B6C /* ListManager.swift */; };
20 | 68722F2722FCB32100F00B6C /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68722F2622FCB32100F00B6C /* Cell.swift */; };
21 | 68722F2922FCB76A00F00B6C /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68722F2822FCB76A00F00B6C /* View.swift */; };
22 | 68722F2B22FCB88E00F00B6C /* AddButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68722F2A22FCB88E00F00B6C /* AddButton.swift */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXFileReference section */
26 | 68722F0022FC904700F00B6C /* ShoppingList.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShoppingList.app; sourceTree = BUILT_PRODUCTS_DIR; };
27 | 68722F0322FC904700F00B6C /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; };
28 | 68722F0522FC904700F00B6C /* Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scene.swift; sourceTree = ""; };
29 | 68722F0822FC904700F00B6C /* ShoppingList.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = ShoppingList.xcdatamodel; sourceTree = ""; };
30 | 68722F0A22FC904700F00B6C /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
31 | 68722F0C22FC904900F00B6C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
32 | 68722F0F22FC904900F00B6C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
33 | 68722F1222FC904900F00B6C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
34 | 68722F1422FC904900F00B6C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
35 | 68722F1A22FCAE8C00F00B6C /* FetchedResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchedResults.swift; sourceTree = ""; };
36 | 68722F2222FCB2AA00F00B6C /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = ""; };
37 | 68722F2422FCB2D700F00B6C /* ListManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListManager.swift; sourceTree = ""; };
38 | 68722F2622FCB32100F00B6C /* Cell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cell.swift; sourceTree = ""; };
39 | 68722F2822FCB76A00F00B6C /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; };
40 | 68722F2A22FCB88E00F00B6C /* AddButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddButton.swift; sourceTree = ""; };
41 | /* End PBXFileReference section */
42 |
43 | /* Begin PBXFrameworksBuildPhase section */
44 | 68722EFD22FC904700F00B6C /* Frameworks */ = {
45 | isa = PBXFrameworksBuildPhase;
46 | buildActionMask = 2147483647;
47 | files = (
48 | );
49 | runOnlyForDeploymentPostprocessing = 0;
50 | };
51 | /* End PBXFrameworksBuildPhase section */
52 |
53 | /* Begin PBXGroup section */
54 | 68722EF722FC904700F00B6C = {
55 | isa = PBXGroup;
56 | children = (
57 | 68722F0222FC904700F00B6C /* ShoppingList */,
58 | 68722F0122FC904700F00B6C /* Products */,
59 | );
60 | sourceTree = "";
61 | };
62 | 68722F0122FC904700F00B6C /* Products */ = {
63 | isa = PBXGroup;
64 | children = (
65 | 68722F0022FC904700F00B6C /* ShoppingList.app */,
66 | );
67 | name = Products;
68 | sourceTree = "";
69 | };
70 | 68722F0222FC904700F00B6C /* ShoppingList */ = {
71 | isa = PBXGroup;
72 | children = (
73 | 68722F2122FCB22800F00B6C /* App Launch */,
74 | 68722F1E22FCB1EC00F00B6C /* Delegates */,
75 | 68722F1C22FCB1BF00F00B6C /* Extensions */,
76 | 68722F1F22FCB20500F00B6C /* Models */,
77 | 68722F2022FCB21E00F00B6C /* Resources */,
78 | 68722F1D22FCB1E300F00B6C /* Views */,
79 | );
80 | path = ShoppingList;
81 | sourceTree = "";
82 | };
83 | 68722F0E22FC904900F00B6C /* Preview Content */ = {
84 | isa = PBXGroup;
85 | children = (
86 | 68722F0F22FC904900F00B6C /* Preview Assets.xcassets */,
87 | );
88 | path = "Preview Content";
89 | sourceTree = "";
90 | };
91 | 68722F1C22FCB1BF00F00B6C /* Extensions */ = {
92 | isa = PBXGroup;
93 | children = (
94 | 68722F1A22FCAE8C00F00B6C /* FetchedResults.swift */,
95 | 68722F2222FCB2AA00F00B6C /* Item.swift */,
96 | 68722F2822FCB76A00F00B6C /* View.swift */,
97 | );
98 | path = Extensions;
99 | sourceTree = "";
100 | };
101 | 68722F1D22FCB1E300F00B6C /* Views */ = {
102 | isa = PBXGroup;
103 | children = (
104 | 68722F0A22FC904700F00B6C /* ContentView.swift */,
105 | 68722F2622FCB32100F00B6C /* Cell.swift */,
106 | 68722F2A22FCB88E00F00B6C /* AddButton.swift */,
107 | );
108 | path = Views;
109 | sourceTree = "";
110 | };
111 | 68722F1E22FCB1EC00F00B6C /* Delegates */ = {
112 | isa = PBXGroup;
113 | children = (
114 | 68722F0322FC904700F00B6C /* App.swift */,
115 | 68722F0522FC904700F00B6C /* Scene.swift */,
116 | );
117 | path = Delegates;
118 | sourceTree = "";
119 | };
120 | 68722F1F22FCB20500F00B6C /* Models */ = {
121 | isa = PBXGroup;
122 | children = (
123 | 68722F2422FCB2D700F00B6C /* ListManager.swift */,
124 | 68722F0722FC904700F00B6C /* ShoppingList.xcdatamodeld */,
125 | );
126 | path = Models;
127 | sourceTree = "";
128 | };
129 | 68722F2022FCB21E00F00B6C /* Resources */ = {
130 | isa = PBXGroup;
131 | children = (
132 | 68722F0E22FC904900F00B6C /* Preview Content */,
133 | 68722F0C22FC904900F00B6C /* Assets.xcassets */,
134 | );
135 | path = Resources;
136 | sourceTree = "";
137 | };
138 | 68722F2122FCB22800F00B6C /* App Launch */ = {
139 | isa = PBXGroup;
140 | children = (
141 | 68722F1122FC904900F00B6C /* LaunchScreen.storyboard */,
142 | 68722F1422FC904900F00B6C /* Info.plist */,
143 | );
144 | path = "App Launch";
145 | sourceTree = "";
146 | };
147 | /* End PBXGroup section */
148 |
149 | /* Begin PBXNativeTarget section */
150 | 68722EFF22FC904700F00B6C /* ShoppingList */ = {
151 | isa = PBXNativeTarget;
152 | buildConfigurationList = 68722F1722FC904900F00B6C /* Build configuration list for PBXNativeTarget "ShoppingList" */;
153 | buildPhases = (
154 | 68722EFC22FC904700F00B6C /* Sources */,
155 | 68722EFD22FC904700F00B6C /* Frameworks */,
156 | 68722EFE22FC904700F00B6C /* Resources */,
157 | );
158 | buildRules = (
159 | );
160 | dependencies = (
161 | );
162 | name = ShoppingList;
163 | productName = ShoppingList;
164 | productReference = 68722F0022FC904700F00B6C /* ShoppingList.app */;
165 | productType = "com.apple.product-type.application";
166 | };
167 | /* End PBXNativeTarget section */
168 |
169 | /* Begin PBXProject section */
170 | 68722EF822FC904700F00B6C /* Project object */ = {
171 | isa = PBXProject;
172 | attributes = {
173 | LastSwiftUpdateCheck = 1100;
174 | LastUpgradeCheck = 1100;
175 | ORGANIZATIONNAME = "Eric Lewis, Inc.";
176 | TargetAttributes = {
177 | 68722EFF22FC904700F00B6C = {
178 | CreatedOnToolsVersion = 11.0;
179 | };
180 | };
181 | };
182 | buildConfigurationList = 68722EFB22FC904700F00B6C /* Build configuration list for PBXProject "ShoppingList" */;
183 | compatibilityVersion = "Xcode 9.3";
184 | developmentRegion = en;
185 | hasScannedForEncodings = 0;
186 | knownRegions = (
187 | en,
188 | Base,
189 | );
190 | mainGroup = 68722EF722FC904700F00B6C;
191 | productRefGroup = 68722F0122FC904700F00B6C /* Products */;
192 | projectDirPath = "";
193 | projectRoot = "";
194 | targets = (
195 | 68722EFF22FC904700F00B6C /* ShoppingList */,
196 | );
197 | };
198 | /* End PBXProject section */
199 |
200 | /* Begin PBXResourcesBuildPhase section */
201 | 68722EFE22FC904700F00B6C /* Resources */ = {
202 | isa = PBXResourcesBuildPhase;
203 | buildActionMask = 2147483647;
204 | files = (
205 | 68722F1322FC904900F00B6C /* LaunchScreen.storyboard in Resources */,
206 | 68722F1022FC904900F00B6C /* Preview Assets.xcassets in Resources */,
207 | 68722F0D22FC904900F00B6C /* Assets.xcassets in Resources */,
208 | );
209 | runOnlyForDeploymentPostprocessing = 0;
210 | };
211 | /* End PBXResourcesBuildPhase section */
212 |
213 | /* Begin PBXSourcesBuildPhase section */
214 | 68722EFC22FC904700F00B6C /* Sources */ = {
215 | isa = PBXSourcesBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | 68722F0922FC904700F00B6C /* ShoppingList.xcdatamodeld in Sources */,
219 | 68722F1B22FCAE8C00F00B6C /* FetchedResults.swift in Sources */,
220 | 68722F0422FC904700F00B6C /* App.swift in Sources */,
221 | 68722F2B22FCB88E00F00B6C /* AddButton.swift in Sources */,
222 | 68722F2522FCB2D700F00B6C /* ListManager.swift in Sources */,
223 | 68722F0B22FC904700F00B6C /* ContentView.swift in Sources */,
224 | 68722F2922FCB76A00F00B6C /* View.swift in Sources */,
225 | 68722F2722FCB32100F00B6C /* Cell.swift in Sources */,
226 | 68722F2322FCB2AA00F00B6C /* Item.swift in Sources */,
227 | 68722F0622FC904700F00B6C /* Scene.swift in Sources */,
228 | );
229 | runOnlyForDeploymentPostprocessing = 0;
230 | };
231 | /* End PBXSourcesBuildPhase section */
232 |
233 | /* Begin PBXVariantGroup section */
234 | 68722F1122FC904900F00B6C /* LaunchScreen.storyboard */ = {
235 | isa = PBXVariantGroup;
236 | children = (
237 | 68722F1222FC904900F00B6C /* Base */,
238 | );
239 | name = LaunchScreen.storyboard;
240 | sourceTree = "";
241 | };
242 | /* End PBXVariantGroup section */
243 |
244 | /* Begin XCBuildConfiguration section */
245 | 68722F1522FC904900F00B6C /* Debug */ = {
246 | isa = XCBuildConfiguration;
247 | buildSettings = {
248 | ALWAYS_SEARCH_USER_PATHS = NO;
249 | CLANG_ANALYZER_NONNULL = YES;
250 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
251 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
252 | CLANG_CXX_LIBRARY = "libc++";
253 | CLANG_ENABLE_MODULES = YES;
254 | CLANG_ENABLE_OBJC_ARC = YES;
255 | CLANG_ENABLE_OBJC_WEAK = YES;
256 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
257 | CLANG_WARN_BOOL_CONVERSION = YES;
258 | CLANG_WARN_COMMA = YES;
259 | CLANG_WARN_CONSTANT_CONVERSION = YES;
260 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
262 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
263 | CLANG_WARN_EMPTY_BODY = YES;
264 | CLANG_WARN_ENUM_CONVERSION = YES;
265 | CLANG_WARN_INFINITE_RECURSION = YES;
266 | CLANG_WARN_INT_CONVERSION = YES;
267 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
268 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
269 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
270 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
271 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
272 | CLANG_WARN_STRICT_PROTOTYPES = YES;
273 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
274 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
275 | CLANG_WARN_UNREACHABLE_CODE = YES;
276 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
277 | COPY_PHASE_STRIP = NO;
278 | DEBUG_INFORMATION_FORMAT = dwarf;
279 | ENABLE_STRICT_OBJC_MSGSEND = YES;
280 | ENABLE_TESTABILITY = YES;
281 | GCC_C_LANGUAGE_STANDARD = gnu11;
282 | GCC_DYNAMIC_NO_PIC = NO;
283 | GCC_NO_COMMON_BLOCKS = YES;
284 | GCC_OPTIMIZATION_LEVEL = 0;
285 | GCC_PREPROCESSOR_DEFINITIONS = (
286 | "DEBUG=1",
287 | "$(inherited)",
288 | );
289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
291 | GCC_WARN_UNDECLARED_SELECTOR = YES;
292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
293 | GCC_WARN_UNUSED_FUNCTION = YES;
294 | GCC_WARN_UNUSED_VARIABLE = YES;
295 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
296 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
297 | MTL_FAST_MATH = YES;
298 | ONLY_ACTIVE_ARCH = YES;
299 | SDKROOT = iphoneos;
300 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
301 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
302 | };
303 | name = Debug;
304 | };
305 | 68722F1622FC904900F00B6C /* Release */ = {
306 | isa = XCBuildConfiguration;
307 | buildSettings = {
308 | ALWAYS_SEARCH_USER_PATHS = NO;
309 | CLANG_ANALYZER_NONNULL = YES;
310 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
311 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
312 | CLANG_CXX_LIBRARY = "libc++";
313 | CLANG_ENABLE_MODULES = YES;
314 | CLANG_ENABLE_OBJC_ARC = YES;
315 | CLANG_ENABLE_OBJC_WEAK = YES;
316 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
317 | CLANG_WARN_BOOL_CONVERSION = YES;
318 | CLANG_WARN_COMMA = YES;
319 | CLANG_WARN_CONSTANT_CONVERSION = YES;
320 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
321 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
322 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
323 | CLANG_WARN_EMPTY_BODY = YES;
324 | CLANG_WARN_ENUM_CONVERSION = YES;
325 | CLANG_WARN_INFINITE_RECURSION = YES;
326 | CLANG_WARN_INT_CONVERSION = YES;
327 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
328 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
329 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
330 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
331 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
332 | CLANG_WARN_STRICT_PROTOTYPES = YES;
333 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
334 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
335 | CLANG_WARN_UNREACHABLE_CODE = YES;
336 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
337 | COPY_PHASE_STRIP = NO;
338 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
339 | ENABLE_NS_ASSERTIONS = NO;
340 | ENABLE_STRICT_OBJC_MSGSEND = YES;
341 | GCC_C_LANGUAGE_STANDARD = gnu11;
342 | GCC_NO_COMMON_BLOCKS = YES;
343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
345 | GCC_WARN_UNDECLARED_SELECTOR = YES;
346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
347 | GCC_WARN_UNUSED_FUNCTION = YES;
348 | GCC_WARN_UNUSED_VARIABLE = YES;
349 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
350 | MTL_ENABLE_DEBUG_INFO = NO;
351 | MTL_FAST_MATH = YES;
352 | SDKROOT = iphoneos;
353 | SWIFT_COMPILATION_MODE = wholemodule;
354 | SWIFT_OPTIMIZATION_LEVEL = "-O";
355 | VALIDATE_PRODUCT = YES;
356 | };
357 | name = Release;
358 | };
359 | 68722F1822FC904900F00B6C /* Debug */ = {
360 | isa = XCBuildConfiguration;
361 | buildSettings = {
362 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
363 | CODE_SIGN_STYLE = Automatic;
364 | DEVELOPMENT_ASSET_PATHS = "ShoppingList/Resources/Preview\\ Content";
365 | DEVELOPMENT_TEAM = F9PGNEMEHU;
366 | ENABLE_PREVIEWS = YES;
367 | INFOPLIST_FILE = "ShoppingList/App Launch/Info.plist";
368 | LD_RUNPATH_SEARCH_PATHS = (
369 | "$(inherited)",
370 | "@executable_path/Frameworks",
371 | );
372 | PRODUCT_BUNDLE_IDENTIFIER = ericlewis.ShoppingList;
373 | PRODUCT_NAME = "$(TARGET_NAME)";
374 | SWIFT_VERSION = 5.0;
375 | TARGETED_DEVICE_FAMILY = "1,2";
376 | };
377 | name = Debug;
378 | };
379 | 68722F1922FC904900F00B6C /* Release */ = {
380 | isa = XCBuildConfiguration;
381 | buildSettings = {
382 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
383 | CODE_SIGN_STYLE = Automatic;
384 | DEVELOPMENT_ASSET_PATHS = "ShoppingList/Resources/Preview\\ Content";
385 | DEVELOPMENT_TEAM = F9PGNEMEHU;
386 | ENABLE_PREVIEWS = YES;
387 | INFOPLIST_FILE = "ShoppingList/App Launch/Info.plist";
388 | LD_RUNPATH_SEARCH_PATHS = (
389 | "$(inherited)",
390 | "@executable_path/Frameworks",
391 | );
392 | PRODUCT_BUNDLE_IDENTIFIER = ericlewis.ShoppingList;
393 | PRODUCT_NAME = "$(TARGET_NAME)";
394 | SWIFT_VERSION = 5.0;
395 | TARGETED_DEVICE_FAMILY = "1,2";
396 | };
397 | name = Release;
398 | };
399 | /* End XCBuildConfiguration section */
400 |
401 | /* Begin XCConfigurationList section */
402 | 68722EFB22FC904700F00B6C /* Build configuration list for PBXProject "ShoppingList" */ = {
403 | isa = XCConfigurationList;
404 | buildConfigurations = (
405 | 68722F1522FC904900F00B6C /* Debug */,
406 | 68722F1622FC904900F00B6C /* Release */,
407 | );
408 | defaultConfigurationIsVisible = 0;
409 | defaultConfigurationName = Release;
410 | };
411 | 68722F1722FC904900F00B6C /* Build configuration list for PBXNativeTarget "ShoppingList" */ = {
412 | isa = XCConfigurationList;
413 | buildConfigurations = (
414 | 68722F1822FC904900F00B6C /* Debug */,
415 | 68722F1922FC904900F00B6C /* Release */,
416 | );
417 | defaultConfigurationIsVisible = 0;
418 | defaultConfigurationName = Release;
419 | };
420 | /* End XCConfigurationList section */
421 |
422 | /* Begin XCVersionGroup section */
423 | 68722F0722FC904700F00B6C /* ShoppingList.xcdatamodeld */ = {
424 | isa = XCVersionGroup;
425 | children = (
426 | 68722F0822FC904700F00B6C /* ShoppingList.xcdatamodel */,
427 | );
428 | currentVersion = 68722F0822FC904700F00B6C /* ShoppingList.xcdatamodel */;
429 | path = ShoppingList.xcdatamodeld;
430 | sourceTree = "";
431 | versionGroupType = wrapper.xcdatamodel;
432 | };
433 | /* End XCVersionGroup section */
434 | };
435 | rootObject = 68722EF822FC904700F00B6C /* Project object */;
436 | }
437 |
--------------------------------------------------------------------------------