Swift/Xcode

[Swift] CoreData ํ™œ์šฉํ•ด๋ณด๊ธฐ (Subclass ์ƒ์„ฑ๋ฒ•, Double ํƒ€์ž… ์„ ์–ธ ์•ˆ๋˜๋Š” ์ด์œ )

yeggrrr๐Ÿผ 2024. 12. 12. 23:04

 CoreData๋ฅผ ํ™œ์šฉํ•ด์„œ ์ž‘์€ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์„œ ์—ฐ์Šตํ•ด๋ณผ๊นŒํ•ฉ๋‹ˆ๋‹ค! 

< ์—ฐ์Šต ํ”„๋กœ์ ํŠธ >
์ด๋ฆ„, ์„ฑ๋ณ„, ๋‚˜์ด๋ฅผ ์ž…๋ ฅํ•œ ํ›„
์ €์žฅ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, CoreData์— ์ €์žฅ๋˜๊ณ 
์ „์ฒด์‚ญ์ œ๋ฅผ ๋ˆ„๋ฅด๋ฉด ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

0



โ‘  ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ


์šฐ์„  ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ํ•˜๋‹จ์— CoreData๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.


๊ทธ๋Ÿฌ๋ฉด ์œ„์™€ ๊ฐ™์ด xcdatamodeld ํŒŒ์ผ์ด ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.



๋งŒ์•ฝ์— ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰์ค‘์— CoreData๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค๋ฉด?

๋”๋ณด๊ธฐ

Command + N ์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.


โ‘ก Entity, Attributes, Relationships ์„ค์ •

์ด์ œ ํ•˜๋‹จ Add Entity๋ฅผ ํด๋ฆญํ•ด์„œ Entity๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ Entity์ด๋ฆ„์€ ์ค‘์š”ํ•˜๋‹ˆ๊นŒ ์ž˜ ๊ธฐ์–ตํ•˜๊ธฐ!
(์ €๋Š” Testํ”„๋กœ์ ํŠธ๋ผ ์ œ ์ด๋ฆ„ Yegr๋ผ๊ณ  ์ง€์—ˆ์Šต๋‹ˆ๋‹ค :D)

๊ทธ๋ฆฌ๊ณ  + ๋ฒ„ํŠผ์œผ๋กœ Attributes ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. (๊ฐ์ฒด ์ด๋ฆ„, ํƒ€์ž… ์„ค์ •)
์ด ๋ถ€๋ถ„์€ ์ €์žฅํ•  ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ ํƒ€์ž…์„ ์˜ต์…”๋„๋กœ ๋งŒ๋“ค์–ด์ง€๋Š”๋ฐ,
์šฐ์ธก ์ƒ๋‹จ ์ธ์ŠคํŽ™ํ„ฐ ์˜์—ญ์„ ํ†ตํ•ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



๋‹ค์Œ์œผ๋กœ Entity์˜ Class ํ•˜๋‹จ์— ์žˆ๋Š” Codegen์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•˜๋ฉด,

์ด๋ ‡๊ฒŒ! ์ƒํ™ฉ์— ๋งž๊ฒŒ ์„ค์ •ํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค!

 

NSManagedObject Subclass ์ƒ์„ฑ ๋ฐฉ๋ฒ•

๋”๋ณด๊ธฐ


์ œ๊ฐ€ ์ด์ „์— CoreData๋ฅผ Attributes๊ฐ€ ์ถ”๊ฐ€์ ์œผ๋กœ ํ•„์š”ํ•ด์„œ
์ค‘๊ฐ„์— ํ•˜๋‚˜๋ฅผ ๋” ์ถ”๊ฐ€ํ•œ์ ์ด ์žˆ๋Š”๋ฐ,
๋ถ„๋ช… Double? ํƒ€์ž…์œผ๋กœ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ๋„ ๋ถˆ๊ตฌํ•˜๊ณ 
์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์ปดํŒŒ์ผ์—์„œ Double ํƒ€์ž…์œผ๋กœ ์ธ์‹๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.๐Ÿคฏ


๊ทธ๋ž˜์„œ Subclass ์ƒ์„ฑํ•ด์„œ ํƒ€์ž…์„ ์ˆ˜๋™์œผ๋กœ ๋ณ€๊ฒฝํ•ด์คฌ์Šต๋‹ˆ๋‹ค.

์ƒ๋‹จ Editor์—์„œ Create NSManagedObject Subclass๋ฅผ ์„ ํƒํ•ด์ค๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์ด๋ ‡๊ฒŒ ํŒŒ์ผ ๋‘๊ฐœ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.



๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด,
https://developer.apple.com/documentation/coredata/modeling_data/generating_code

 

Generating code | Apple Developer Documentation

Automatically or manually generate managed object subclasses from entities.

developer.apple.com

 


CoreData๋Š” Entities, Attriubtes ๋ฐ relationships์„ ์ •์˜ํ•œ ํ›„,
Entity ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š”๋ฐ ์‚ฌ์šฉํ•  ํด๋ž˜์Šค๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
CoreData๋Š” ์„ ํƒ์ ์œผ๋กœ ํด๋ž˜์Šค ํŒŒ์ผ๊ณผ ์†์„ฑ ํŒŒ์ผ์ด๋ผ๋Š” ๋‘ ๊ฐœ์˜ ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

ํด๋ž˜์Šค ํŒŒ์ผ์€ ํด๋ž˜์Šค๋ฅผ NSManagedObject์˜ ํ•˜์œ„ ํด๋ž˜์Šค๋กœ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.
์†์„ฑ ํŒŒ์ผ์€ attributes, relationships, ํ•ด๋‹น ์ ‘๊ทผ์ž ๋ฐ ์ด ์œ ํ˜•์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ๋„์›€์„ ์ฃผ๋Š”
@NSManaged ์†์„ฑ์„ ๊ฐ€์ง„ extension์œผ๋กœ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

๊ด€๋ฆฌ๋˜๋Š” ๊ฐ์ฒด ์„œ๋ธŒํด๋ž˜์Šค ์ƒ์„ฑ์€ CoreData๊ฐ€ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ,
๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์†์„ฑ์„ ํŽธ์ง‘ํ•ด์•ผ ํ•  ๋•Œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



๋„ค.. ์ด๋ ‡๋‹ต๋‹ˆ๋‹ค.

์ƒํ™ฉ์— ๋”ฐ๋ผ ๋ฐ”๋กœ ์œ„์— Codegen์— ๋Œ€ํ•ด ์ •๋ฆฌํ–ˆ๋˜๋Œ€๋กœ
ํด๋ž˜์Šค ์ •์˜๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง์ธ ๊ฒƒ ๊ฐ™์•„์š”.

๊ทธ๋ฆฌ๊ณ  Create NSManagedObject Subclass๋ฅผ ํ†ตํ•ด ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋ฉด,
์ƒˆ ํŒŒ์ผ์€ ํ•ด๋‹น ์œ„์น˜์˜ ๊ธฐ์กด ํŒŒ์ผ์„ ๋ฎ์–ด ์“ด๋‹ค๋Š”๋Š” ์ ์— ์œ ์˜ํ•˜๋ผ๊ณ  ์ ํ˜€์žˆ์Šต๋‹ˆ๋‹ค!

 

CoreData Subclass์˜ Double? ํƒ€์ž…์ด ์„ ์–ธ์ด ์•ˆ๋˜๋Š” ๊ฒฝ์šฐ

๋”๋ณด๊ธฐ

Double? ํƒ€์ž…์œผ๋กœ ์„ ์–ธํ•˜๋ ค๊ณ  ๋ณด๋‹ˆ,

'Property cannot be marked @NSManaged because its type cannot be represented in Objective-C'

์ด๋Ÿฐ ์—๋Ÿฌ ๋ฌธ๊ตฌ๊ฐ€ ๋œจ๋”๋ผ๊ณ ์š”..๐Ÿ˜ง


์•Œ์•„๋ณด๋‹ˆ,
CoreData๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Objective-C์™€ ํ•จ๊ป˜ ๊ฐœ๋ฐœ๋œ ํ”„๋ ˆ์ž„์›Œํฌ๋ผ์„œ
Swift์—์„œ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ์ผ๋ถ€ Objective-C ํŠน์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

Objective-C๋Š” Double์ด๋ผ๋Š” ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๊ณ ,
๋Œ€์‹ ์— NSNumber ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ํ•ด์š”.

(Double ํƒ€์ž… ๋ง๊ณ ๋„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ํƒ€์ž…์ด ์žˆ๋‹ค๊ณ  ํ•ด์š”.
์‚ฌ์šฉ ์‹œ, CoreData์—์„œ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ํƒ€์ž…๋“ค์„ ์ฐพ์•„๋ณด์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค!)

extension Yegr {

    @nonobjc class func fetchRequest() -> NSFetchRequest<Yegr> {
        return NSFetchRequest<Yegr>(entityName: "Yegr")
    }

    @NSManaged var aspectRatioValue: NSNumber?
    
    var aspectRatio: Double? {
        get {
            aspectRatioValue?.doubleValue
        }
        set {
            aspectRatioValue = newValue as NSNumber?
        }
    }
}

๊ทธ๋ž˜์„œ ์œ„์™€ ๊ฐ™์ด Double? ํƒ€์ž…์ด ์•„๋‹Œ NSNumber? ํƒ€์ž…์œผ๋กœ ์„ ์–ธํ•˜๊ณ ,
Swift์— ๋งž๊ฒŒ ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ํƒ€์ž…์„ ๋ณ€ํ™˜ํ•˜์—ฌ Double? ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๐Ÿ˜€


โ‘ข PersistentContainer ์„ค์ •

Entity, Attributes, Relationships ๋“ฑ ํ•„์š”ํ•œ ์„ค์ •์ด ๋๋‚ธ ํ›„,

AppDelegate์—์„œ ๊ด€๋ฆฌํ•˜๋Š” persistentContainer๋ฅผ ๊ฐ€์ ธ์˜ฌ๊ฒ๋‹ˆ๋‹ค!
(persistentContainer๋Š” CoreData์˜ ๋ฐ์ดํ„ฐ ์Šคํƒ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด์ด๊ณ ,
์ด ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด์„œ CoreData์˜ NSManagedObjectContext์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

    private func configurePersistentContainer() {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        self.container = appDelegate.persistentContainer
    }

์ด ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ AppDelegate์—์„œ ์ดˆ๊ธฐํ™”ํ•œ persistentContainer๋ฅผ ๋ทฐ์ปจ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค!
(์ฐธ๊ณ ๋กœ NSManagedObjectContext๋Š” CoreData ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๊ณ , ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€, ์ˆ˜์ •, ์‚ญ์ œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.)

 

โ‘ฃ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ (Create)

์ฒ˜์Œ์— Entity ์„ค์ •ํ•  ๋•Œ, ์ด๋ฆ„ ๊ผญ ๊ธฐ์–ตํ•˜๋ผ๊ณ  ํ–ˆ๋˜๊ฑฐ ๊ธฐ์–ตํ•˜์‹œ์ฃ ?
๊ทธ ์ด๋ฆ„์„ EntityName์— ๋„ฃ์–ด ํ•ด๋‹น Entity๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , NSManagedObject๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ• ๊ฒ๋‹ˆ๋‹ค.

    private func createEntity(name: String, gender: String, age: Int) {
        if let entity = NSEntityDescription.entity(forEntityName: "Yegr", in: self.container.viewContext) {
            let object = NSManagedObject(entity: entity, insertInto: self.container.viewContext)
            object.setValue(name, forKey: "name")
            object.setValue(gender, forKey: "gender")
            object.setValue(age, forKey: "age")
        }
        
        saveData() // ์ด ๋ฉ”์„œ๋“œ๋Š” ๋‹ค์Œ ์„ค๋ช…์— ์žˆ์Šต๋‹ˆ๋‹ค.
    }

NSEntityDescription.entity(forEntityName: in:)๋กœ "Yegr" ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ ,
NSManagedObject๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  setValue(forKey:) ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ…์ŠคํŠธ ํ•„๋“œ์—์„œ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•ด๋‹น ๊ฐ์ฒด์˜ ์†์„ฑ์— ์„ค์ •ํ•ด์คฌ์Šต๋‹ˆ๋‹ค.
(์ €๋Š” '์ €์žฅ'๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ, ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ์‹ถ์–ด์„œ ๋„ฃ์–ด์ค„ ๊ฐ’์€ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„์คฌ์Šต๋‹ˆ๋‹ค.)



โ‘ค ๋ฐ์ดํ„ฐ ์ €์žฅ(Save)

container.viewContext.save()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅ์†Œ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

    private func saveData() {
        do {
            try self.container.viewContext.save()
        } catch {
            print("error!: \(error.localizedDescription)")
        }
    }



โ‘ฅ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ(Fetch)

Yegr.fetchRequest()๋กœ Yegr ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

    private func fetchData() -> [Yegr]? {
        do {
            let data = try self.container.viewContext.fetch(Yegr.fetchRequest())
            return data
        } catch {
            print("error!: \(error.localizedDescription)")
        }
        
        return nil
    }

(์ €๋Š” tableView์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.)


โ‘ฆ ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™” (Reset)

NSBatchDeleteRequest๋ฅผ ์‚ฌ์šฉํ•ด์„œ "Yegr" ์—”ํ‹ฐํ‹ฐ์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.
execute(deleteRequest)๋กœ ์‚ญ์ œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    private func resetData() {
        let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Yegr")
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

        do {
            try container.viewContext.execute(deleteRequest)
        } catch {
            print("Error deleting data: \(error)")
        }
        
        coreDataView.tableView.reloadData() // ์ „์ฒด ์‚ญ์ œ ๋ฒ„ํŠผ ํด๋ฆญ ํ›„, ํ…Œ์ด๋ธ”๋ทฐ ๋ฆฌ๋กœ๋“œ
    }


์ด๋ฒˆ ๊ธ€์—์„œ๋Š” CoreData๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ CRUD์ž‘์—…์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ•ด๋ดค์Šต๋‹ˆ๋‹ค.
CoreData๋Š” ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ์ž‘์—…์„ ๊ฐ„์†Œํ™”ํ•ด์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋กœ,
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ฐ์ฒด ๋ชจ๋ธ์„ ์—ฐ๊ฒฐํ•˜์—ฌ ๊ฐ์ฒด์ง€ํ–ฅ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

์ด๋ฒˆ CoreDataEX ํ”„๋กœ์ ํŠธ๋ฅผ ํ†ตํ•ด ๊ธฐ๋ณธ์ ์ธ ํŒจํ„ด์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.๐Ÿ˜†
์•ž์œผ๋กœ๋„ ์•ฑ์„ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ๊ธฐํšŒ๊ฐ€ ์ƒ๊ธด๋‹ค๋ฉด CoreData๋ฅผ ๊ณ„์† ํ™œ์šฉํ•ด๋ด์•ผ๊ฒ ๋„ค์š”!


<ํ”„๋กœ์ ํŠธ github ๋งํฌ>
https://github.com/yeggrrr/CoreDataEX

 

GitHub - yeggrrr/CoreDataEX: CoreData ์—ฐ์Šต

CoreData ์—ฐ์Šต. Contribute to yeggrrr/CoreDataEX development by creating an account on GitHub.

github.com


 

728x90

'Swift > Xcode' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Swift] CLLocationManager  (0) 2024.05.31
[Swift] UIButton Configuration  (0) 2024.05.30
[Swift] View Drawing Cycle  (0) 2024.05.28
[Swift] Delegate ํŒจํ„ด  (0) 2024.05.26
[Swift] UserDefaults  (0) 2024.05.25