코어 데이터 모델과 일반 Struct 과 같이 사용하려고 생각했다.
AOS 에서는 한 모델을 기준으로 Sqlite 도 같은 형변환이 될 수 있도록 치환이 가능했기 때문이다.
그 부분때문에 당연히 IOS 에서도 가능하겠지 하고 계속 시도해보았지만 잘 안됐다. 흠...
그럼 CoreData / Extension / Struct 란 무엇인지 한번 알아보자 !!
1. CoreData Model
✅ CoreData란?
CoreData는 iOS/macOS 앱에서 데이터를 저장하고 관리하는 프레임워크입니다.
데이터베이스(SQL)처럼 사용 가능하지만, 직접 SQL을 다루지 않아도 됨
✅ CoreData Model 정의
CoreData에서 데이터를 저장하려면 **엔티티(Entity)**를 정의해야 합니다.
Swift에서는 NSManagedObject를 상속받아 모델을 생성합니다.
✅ CoreData Model 예제
import CoreData
@objc(User) // CoreData에서 사용할 엔티티(User)
class User: NSManagedObject {
@NSManaged var name: String
@NSManaged var age: Int16
}
📌 설명
- NSManagedObject: CoreData에서 사용되는 객체
- @NSManaged: CoreData가 관리하는 속성 (자동 저장/로드됨)
- @objc(User): CoreData에서 인식할 수 있도록 클래스 등록
2. Extension (확장)
✅ Extension이란?
**Extension(확장)**은 기존 클래스, 구조체, 열거형, 프로토콜에 새로운 기능을 추가하는 기능입니다.
(원본 코드를 수정하지 않고도 기능을 확장 가능!)
✅ Extension 예제 1 - CoreData Model 확장하기
CoreData의 User 모델에 추가 기능을 확장해보겠습니다.
extension User {
func userInfo() -> String {
return "Name: \(name), Age: \(age)"
}
}
📌 설명
- extension User → 기존 User 모델을 확장하여 userInfo() 메서드 추가
✅ Extension 예제 2 - Swift 기본 타입 확장
extension Int {
func squared() -> Int {
return self * self
}
}
let number = 5
print(number.squared()) // 출력: 25
📌 설명
- Int 타입에 squared() 메서드 추가
- number.squared() 호출 시 number * number 결과 반환
3. Struct (구조체)
✅ Struct란?
**Struct(구조체)**는 값 타입(Value Type)을 가지는 데이터 구조입니다.
→ 클래스(Class)는 참조 타입(Reference Type)
📌 클래스(Class) vs 구조체(Struct) 차이점
클래스 (Class)구조체 (Struct)
메모리 할당 | Heap | Stack |
값 변경 | 참조(Reference) | 값(Value) 복사 |
상속 가능 여부 | ✅ 가능 | ❌ 불가능 |
사용 용도 | 복잡한 데이터 관리 | 가벼운 데이터 관리 |
✅ Struct 예제
struct User {
var name: String
var age: Int
func userInfo() -> String {
return "Name: \(name), Age: \(age)"
}
}
let user1 = User(name: "Alice", age: 25)
print(user1.userInfo()) // 출력: Name: Alice, Age: 25
📌 설명
- struct User → 사용자 정보를 저장하는 구조체
- userInfo() 메서드로 정보 반환
- user1을 생성해도 값이 복사되므로 원본이 변경되지 않음
4. CoreData Model + Struct + Extension 함께 사용하기
CoreData와 Struct를 함께 사용하는 경우도 많습니다.
→ CoreData는 NSManagedObject를 사용하지만, Struct로 변환하여 사용하면 더 편리
✅ CoreData Model을 Struct로 변환
import CoreData
// CoreData 모델 (NSManagedObject)
@objc(UserEntity)
class UserEntity: NSManagedObject {
@NSManaged var name: String
@NSManaged var age: Int16
}
// Struct 변환
struct User {
var name: String
var age: Int
}
// CoreData → Struct 변환 Extension
extension User {
init(userEntity: UserEntity) {
self.name = userEntity.name
self.age = Int(userEntity.age)
}
}
📌 설명
- UserEntity: CoreData에서 사용하는 모델
- User: Struct로 변환하여 값 타입으로 사용 가능
- init(userEntity:)을 사용하여 CoreData 데이터를 Struct로 변환
이렇게 기본적인 각 요소들의 의미를 알아보았으니 이제 내가 하려는 부분에 대해 깊이 이해해보자 !!
enum Gender: String, Codable {
case M = "M"
case F = "F"
case NULL = "NULL"
}
enum CurrentStatus: String, Codable {
case IN = "IN"
case OUT = "OUT"
case NULL = "NULL"
}
enum Time: String, Codable {
case afternoon = "afternoon"
case NULL = "NULL"
case night = "night"
}
enum Grade: String, Codable {
case A = "A"
case B = "B"
case C = "C"
case D = "D"
case E = "E"
case NULL = "NULL"
}
struct MemberStruct: Codable, Comparable {
var clubName: String
var name: String
var gender: Gender
var memberOwnId: String
var currentStatus: CurrentStatus
var age: Int
var grade: Grade
var time: Time
enum CodingKeys: String, CodingKey {
case memberOwnId = "m_Id"
case name
case gender
case currentStatus
case clubName
case grade
case age
case time
}
init(clubName: String = "", name: String = "", gender: Gender = .NULL, memberOwnId: String = "", currentStatus: CurrentStatus = .NULL, age: Int = 0, grade: Grade = .NULL, time: Time = .NULL) {
self.clubName = clubName
self.name = name
self.gender = gender
self.memberOwnId = memberOwnId
self.currentStatus = currentStatus
self.age = age
self.grade = grade
self.time = time
}
init() {
self.clubName = ""
self.name = ""
self.gender = .NULL
self.memberOwnId = ""
self.currentStatus = .NULL
self.age = 0
self.grade = .NULL
self.time = .NULL
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
clubName = try container.decode(String.self, forKey: .clubName)
name = try container.decode(String.self, forKey: .name)
gender = try container.decode(Gender.self, forKey: .gender)
memberOwnId = try container.decode(String.self, forKey: .memberOwnId)
currentStatus = try container.decode(CurrentStatus.self, forKey: .currentStatus)
age = try container.decode(Int.self, forKey: .age)
grade = try container.decodeIfPresent(Grade.self, forKey: .grade) ?? .NULL
time = try container.decode(Time.self, forKey: .time)
}
static func < (lhs: MemberStruct, rhs: MemberStruct) -> Bool {
return lhs.name < rhs.name
}
static func == (lhs: MemberStruct, rhs: MemberStruct) -> Bool {
return lhs.name == rhs.name
}
func toMembers(context: NSManagedObjectContext) -> Members {
let members = Members(context: context)
members.clubName = self.clubName
members.name = self.name
members.gender = self.gender.rawValue
members.memberOwnId = self.memberOwnId
members.currentStatus = self.currentStatus.rawValue
members.age = String(self.age)
members.grade = self.grade.rawValue
members.time = self.time.rawValue
return members
}
}
이 일반적인 Struct 를 하나로 전부 이용하고 싶었지만,
CoreData 에서는 CoreDataProperties.swift 파일은 Core Data의 속성 확장만을 포함해야 해서 일반적으로 이 파일에 메서드 확장보다는 속성 관련 코드만 넣는다고 한다.
따라서, 별도의 extension으로 정의하는 것이 좋다고 하는 ChatGpt 의 말에 따라 하는 수 없이 별도 분리를 하는 수밖에 없었다.
//
// Members+CoreDataProperties.swift
//
//
// Created by macbookpro on 7/24/24.
//
//
import Foundation
import CoreData
extension Members {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Members> {
return NSFetchRequest<Members>(entityName: "Members")
}
@NSManaged public var clubName: String?
@NSManaged public var name: String?
@NSManaged public var gender: String?
@NSManaged public var memberOwnId: String?
@NSManaged public var currentStatus: String?
@NSManaged public var age: String?
@NSManaged public var grade: String?
@NSManaged public var time: String?
func update(from member: MemberStruct) {
self.clubName = member.clubName
self.name = member.name
self.gender = member.gender.rawValue
self.memberOwnId = member.memberOwnId
self.currentStatus = member.currentStatus.rawValue
self.age = String(member.age)
self.grade = member.grade.rawValue
self.time = member.time.rawValue
}
func toMemberStruct() -> MemberStruct? {
guard
let clubName = self.clubName,
let name = self.name,
let gender = self.gender,
let memberOwnId = self.memberOwnId,
let currentStatus = self.currentStatus,
let ageString = self.age,
let age = Int(ageString),
let grade = self.grade,
let time = self.time
else {
return nil
}
return MemberStruct(
clubName: clubName,
name: name,
gender: Gender(rawValue: gender) ?? .NULL,
memberOwnId: memberOwnId,
currentStatus: CurrentStatus(rawValue: currentStatus) ?? .NULL,
age: age,
grade: Grade(rawValue: grade) ?? .NULL,
time: Time(rawValue: time) ?? .NULL
)
}
override public var description: String {
return """
Member{
clubName: \(String(describing: clubName)),
name: \(String(describing: name)),
gender: \(String(describing: gender)),
memberOwnId: \(String(describing: memberOwnId)),
currentStatus: \(String(describing: currentStatus)),
age: \(String(describing: age)),
grade: \(String(describing: grade)),
time: \(String(describing: time))
}
"""
}
}
위의 코드는 이제 잘못된 코드이다..
저런 부가적인 함수들은 따로 extension 파일을 만들어 정리하도록 해야겠다.
그렇다면 내가 이해한 바로는 ,
코어데이터와 일반적인 Struct 는 각 독립적인 모델로 생각해야 하고 서로 상호호환을 하려면 형변환을 해주어야 한다는 의미로 생각되었당
그래서 우선 코어데이터로 저장하는건 코어데이터 모델을 사용하고 그리고 그 데이터를 가져올땐 Struct 로 형변환 후 사용하는 것이 깔끔한듯 하다
AOS IOS 각각의 장단점이 있는 듯 하다..
'Swift' 카테고리의 다른 글
Swift_ 변수의 종류 (0) | 2025.02.11 |
---|---|
Swift_ intrinsicContentSize / Frame / bounds (0) | 2025.02.08 |
Swift_ CoreData 적용기... (0) | 2024.07.24 |