๐Ÿ’ก work work work/swift

swift ์‹ค์Šต - 7 : To-do App

hanwitjus 2022. 3. 3. 11:17

์ด๋ฒˆ ์‹ค์Šต์„ ํ†ตํ•ด ์ฃผ๋กœ ๋ฐฐ์šด ๋‚ด์šฉ์€ ๋กœ์ปฌDB๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์•ฑ์„ ์ข…๋ฃŒํ•ด๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚จ์•„์žˆ๊ฒŒ ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด์„œ ๋ฐฐ์› ๋‹ค.

๋จผ์ € ์™„์„ฑ๋ณธ์ด๋‹ค.

 

 

์ด๋Ÿฐ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ• ๋•Œ ์ œ๋ชฉ์ด๋ž‘ ์ค‘์š” ์ˆœ์œ„๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ณ 

์ €์žฅํ•  ๋• ๋“ฑ๋ก ๋‚ ์งœ๊นŒ์ง€ ์ €์žฅํ•ด์„œ ํ…Œ์ด๋ธ”๋ทฐ์— ๋ณด์—ฌ์ค€๋‹ค.

 

์ˆ˜์ •๋„ ํ•  ์ˆ˜ ์žˆ๊ณ , ์‚ญ์ œ๊นŒ์ง€ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

(์•ฑ ์ž์ฒด๋ฅผ ์‚ญ์ œํ•˜๊ณ  ์ƒˆ๋กœ ๊น”์ง€ ์•Š๋Š” ํ•œ) ์•ฑ์„ ์ข…๋ฃŒํ•˜๊ณ 

๋‹ค์‹œ ์‹คํ–‰ํ•ด๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚จ์•„์žˆ๋‹ค.

 

์ด๋Ÿฌํ•œ ๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๊ฒƒ์€

CoreData๋ผ๋Š” ๊ฒƒ์ด๋‹ค.

 

ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ CoreData๋ฅผ Embedํ•˜๊ฒ ๋‹ค๊ณ  ์ฒดํฌํ•ด์•ผ ํ•œ๋‹ค.

 

 

 

 

 

 

 

 

๋˜๊ฒŒ ๋งŽ์€ ์ผ์„ ํ•ด์„œ ๋ฐฐ์šด ๋‚ด์šฉ์„ ๋‹ค ์ •๋ฆฌํ•˜๊ธด ๋ฒ…์ฐจ๊ณ  ๊ธฐ์–ตํ•˜๊ณ  ์‹ถ์€๊ฑฐ ๋ช‡๊ฐœ๋งŒ ์ •๋ฆฌํ• ๊ฑฐ๋‹ค ใ…‹ใ…Žใ…‹ใ…Ž

 

1. Local Database ์‚ฌ์šฉ

 

 

 

 

CoreData๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๊ณ  ํ•˜๋ฉด 

์ €๋ ‡๊ฒŒ ๋ฐ‘์— xcdatamodel ํ™•์žฅ์ž๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์ƒ๊ธด๋‹ค.

 

 

 

 

 

 

 

๊ฑฐ๊ธฐ์— ๋“ค์–ด๊ฐ€๋ฉด ์ด๋ ‡๊ฒŒ ์—”ํ‹ฐํ‹ฐ ์ด๋ฆ„์„ ์„ค์ •ํ•˜๊ณ , ์•ˆ์— ์†์„ฑ๋“ค์˜ ์ด๋ฆ„ - ํƒ€์ž…์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

๊ทธ๋ฆฌ๊ณ  ์ด์ œ ์ด๊ฑธ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ดํŽด๋ด์•ผ ํ•  ๊ฒŒ 

ํ‰์†Œ์—” ๋ˆŒ๋Ÿฌ๋ณด์ง€๋„ ์•Š์•˜๋˜ AppDelegate ํŒŒ์ผ์ด๋‹ค.

 

๊ฑฐ๊ธฐ์—์„œ Core Data Stack ๋ถ€๋ถ„๊ณผ Core Data Saving Support ๋ถ€๋ถ„์„ ๋ณด๋ฉด ๋œ๋‹ค.

 

๋จผ์ € Core Data Stack ๋ถ€๋ถ„์„ ๋ณด๋ฉด

 // MARK: - Core Data stack

    lazy var persistentContainer: NSPersistentContainer = {
        /*
         The persistent container for the application. This implementation
         creates and returns a container, having loaded the store for the
         application to it. This property is optional since there are legitimate
         error conditions that could cause the creation of the store to fail.
        */
        let container = NSPersistentContainer(name: "ToDoApp")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // 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.
                 
                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

 

persistantContainer๋ผ๋Š” ๊ฒƒ์ด ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์˜๊ตฌ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ ๋ผ๋Š” ๋œป์ด๋‹ค.

 

๊ทธ๋ฆฌ๊ณ 

Core Data Saving support์—์„œ๋Š”

 

    // MARK: - Core Data Saving support

    func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // 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.
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }

์ด๋ ‡๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

 

 

๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ถ€๋ถ„์€

 func saveTodo(){
        guard let entityDescription = NSEntityDescription.entity(forEntityName: "TodoList", in: context) else{ return }
        
        guard let object = NSManagedObject(entity: entityDescription, insertInto: context) as? TodoList else { return }
        
        object.title = titleTextField.text
        object.date = Date()
        object.uuid = UUID()
        object.priorityLevel = priority?.rawValue ?? PriorityLevel.level1.rawValue
        
        let appdelegate = (UIApplication.shared.delegate as! AppDelegate)
        appdelegate.saveContext()
        
    }

์ด๋Ÿฐ์‹์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

2. ์šฐ์„ ์ˆœ์œ„ ํ‘œํ˜„

 

(1) ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ ๋งˆ๋‹ค ์ƒ‰์ด ๋ณ€ํ•ด์•ผ ํ•˜๊ณ 

(2) ๋ˆ„๋ฅธ ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ๊ฐ’์ด ์ €์žฅ๋ผ์•ผ ํ•˜๊ณ 

(3) ํ…Œ์ด๋ธ” ๋ทฐ์—์„œ ๊ฐ๊ฐ์˜ ์ƒ‰์œผ๋กœ ํ‘œ์‹œํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

 

์œ„์— ์„ธ๊ฐ€์ง€ ์ผ์„ ํ•˜๋ ค๋ฉด ๋ฒ„ํŠผ๋“ค์ด ๊ตฌ๋ถ„๋ผ์•ผ ํ•œ๋‹ค.

๊ทธ๋ž˜์„œ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ Tag๋ถ€๋ถ„์— ๋ฒˆํ˜ธ๋ฅผ ์ง€์ •ํ•ด์ค€๋‹ค.

Low๋Š” 1 Normal์€ 2 High๋Š” 3์ด๋‹ค.

 

enum PriorityLevel: Int64 {
    case level1
    case level2
    case level3
}

extension PriorityLevel{
    var color: UIColor{
        switch self{
        case .level1:
            return .green.withAlphaComponent(0.4)
        case .level2:
            return .orange.withAlphaComponent(0.4)
        case .level3:
            return .red.withAlphaComponent(0.4)
        }
    }
}

๊ทธ๋ฆฌ๊ณ  ViewController์— ์ด๋ ‡๊ฒŒ enum์œผ๋กœ PriorityLevel ํƒ€์ž…์„ ์„ ์–ธํ•ด์ฃผ๊ณ 

๊ฐ๊ฐ์˜ ์ƒ‰๋„ ์ง€์ •ํ•œ๋‹ค.

 

 

    @IBAction func setPriority(_ sender: UIButton) {
        
        switch sender.tag {
            
        case 1:
            priority = .level1
            break
        case 2:
            priority = .level2
            break
        case 3:
            priority = .level3
            break
            
        default:
            break
        }
        
        makePriorityButtonDesign()
        
    }

๊ทธ๋ฆฌ๊ณ  DetailView์—์„œ 3๊ฐœ์˜ ๋ฒ„ํŠผ ๋ชจ๋‘ setPriority ์•ก์…˜ ํ•จ์ˆ˜์— ์ง€์ •ํ•ด ๋†“์€ ๋‹ค์Œ

ํƒœ๊ทธ๋ฅผ ๋ณด๊ณ  ๊ตฌ๋ถ„ํ•ด์„œ ๋ ˆ๋ฒจ์„ ๋ถ€์—ฌํ•˜๊ณ 

makePriorityButtonDesign() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

 

func makePriorityButtonDesign(){
        lowButton.backgroundColor = .clear
        normalButton.backgroundColor = .clear
        highButton.backgroundColor = .clear
        
        switch priority {
            
        case .level1:
            lowButton.backgroundColor = priority?.color
        case .level2:
            normalButton.backgroundColor = priority?.color
        case .level3:
            highButton.backgroundColor = priority?.color
            
        default:
            break
        }

๊ทธ ํ•จ์ˆ˜๋Š” ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค.

 

๋จผ์ € ๋ฒ„ํŠผ ๋ฐฐ๊ฒฝ ์ƒ‰์„ ๋‹ค ํˆฌ๋ช…์œผ๋กœ ๋ฐ”๊ฟ”๋†“๊ณ  ์„ ํƒ๋  ๋•Œ ๋งˆ๋‹ค enum์—์„œ ์ €์žฅํ•ด ๋†“์€ color ์†์„ฑ ๊ฐ’์„ ๋„ฃ์–ด์ค€๋‹ค.

 

DB์— ๊ฐ’์„ ์ €์žฅํ•  ๋•

loadedData.first?.priorityLevel = self.priority?.rawValue ?? PriorityLevel.level1.rawValue

์ด๋ ‡๊ฒŒ rawValue๋ฅผ ์ €์žฅํ•˜๋ฉด ๋œ๋‹ค.

 

 

 

 

CoreData์— ๋Œ€ํ•œ ์• ํ”Œ ๊ณต์‹ ๋ฌธ์„œ์ด๋‹ค.

https://developer.apple.com/documentation/coredata/core_data_stack

 

Apple Developer Documentation

 

developer.apple.com

 

 

LIST