SwiftData 를 사용하여 Memo 앱을 만든 과정
SwiftData 를 사용하여 Memo 앱을 만들어보았습니다.
SwiftData 는 SwiftUI 와 찰떡 궁합으로 사용할 수 있는 프레임 워크이다. 물론 기존 Core Data 도 애플에서 개발한 프레임워크로 충분히 호환가능하나, 개발 편의성 면에서 차원이 다르게 편해졌다고 볼 수 있다.
음식으로 비유하자면, 기존 Core Data는 마치 팬케이크를 처음부터 만들기 위해 밀가루를 곱게 갈고, 달걀을 풀어 반죽을 만든 다음, 팬에 부어서 하나하나 굽는 과정이라면, SwiftData 는 이미 잘 만들어진 팬케이크를 냉장고에서 꺼내 그릇에 담아 전자렌지에 데워서 먹는 것과 같다.
이번에는 그 SwiftData와 함께 SwiftUI를 이용해서 간단한 메모 앱을 만들어본 과정이다.
SwiftData의 @Model 에는 Color 타입이 호환 되지 않았다.
우선, SwiftData 를 사용하기 위해 class 위에 @Model 을 선언 하였다.
그리고 나서 메모별로 색상을 지정할 수 있는 기능을 넣고 싶어서, Memo 클래스 안에 Color 타입의 프로퍼티를 넣을 계획이었다.
그러나 memo class 의 var color: Color 프로퍼티에서 오류가발생.
No exact matches in call to instance method 'setValue'
ChatGpt 에게 물어보았다.
SwiftData의 @Model에서 Color 프로퍼티를 직접 사용할 수 없습니다. 그 이유는 Color가 Codable 프로토콜을 준수하지 않기 때문입니다. SwiftData에서는 모델의 속성이 Codable을 준수해야 합니다.
이 문제를 해결하기 위해서는 Color 대신 String 또는 Int 값을 사용하여 색상을 표현하고, 필요할 때 Color로 변환하는 방법을 사용해야 했다.
그래서 기존 Memo 모델을 다음과 같이 타입을 String 으로 바꾸고,
var colorHex: String
var color: Color { Color(hex: colorHex) }
필요 시 Color 타입 변환을 위한 extension을 추가하였다.
// Color 확장을 추가하여 16진수 문자열에서 Color 인스턴스를 생성하는 이니셜라이저 추가
extension Color {
init(hex: String) {
let scanner = Scanner(string: hex)
var rgbValue: UInt64 = 0
scanner.scanHexInt64(&rgbValue)
let r = Double((rgbValue & 0xFF0000) >> 16) / 255.0
let g = Double((rgbValue & 0x00FF00) >> 8) / 255.0
let b = Double(rgbValue & 0x0000FF) / 255.0
self.init(red: r, green: g, blue: b)
}
}
extension Color {
func toUIColor() -> UIColor {
// SwiftUI Color를 UIKit UIColor로 변환
return UIColor(self)
}
func rgba() -> (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)? {
// UIColor를 사용하여 RGBa 값을 추출
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
return toUIColor().getRed(&red, green: &green, blue: &blue, alpha: &alpha) ? (red, green, blue, alpha) : nil
}
}
Preview 사용 시, modelContainer 를 지정했음에도 Crash 발생
#Preview {
ContentView()
.modelContainer(for: Memo.self, inMemory: true)
}
preview 에서 메모를 추가하다가 crash 가. 발생했다.
모든 뷰에서 단일 컨테이너를 사용하고 있었기에 (앱의 모든 공간에서 하나의 저장소를 사용하고 있었기에) 다른 컨테이너에 데이터가 저장되는 일은 없었다.
그러나 앱 크러시가 난 이유는, 미리보기에 사용된 컨테이너가 메모리에 있는지 확인해야 했기 때문이다.
modelContainer 에 inMemory: true 를 추가해야 한다.
Reference
SwiftData | Apple Developer Documentation
https://developer.apple.com/xcode/swiftdata/
https://ios-development.tistory.com/1403 https://velog.io/@soc06212/SwiftUI-마음으로-이해하는-SwiftData