Handling Different Data Types in Core Data
betterhee
2023. 9. 4. 13:06
Transient Attribute
Transient Attribute(임시 속성)을 사용하여 비지속적 값 파생
- 동일한 엔티티에 저장된 하나 이상의 속성에서 파생됨
- 이름에서 알 수 있듯이 저장소에 유지되지 않
- 저장 공간을 아낄 수 있다
예제 코드
// publishMonthID는 publishDate로부터 파생된 임시 속성
@objc public var publishDate: Date? {
get {
willAccessValue(forKey: Name.publishDate)
defer { didAccessValue(forKey: Name.publishDate) }
return primitivePublishDate
}
set {
willChangeValue(forKey: Name.publishDate)
defer { didChangeValue(forKey: Name.publishDate) }
primitivePublishDate = newValue
primitivePublishMonthID = nil // publishDate의 setter 메서드는 primitivePublishMonthID를 무효화합니다. 이를 통해 publishMonthID의 getter 메서드가 현재 publishDate를 기반으로 값을 다시 계산할 수 있습니다.
}
}
@objc public var publishMonthID: String? {
willAccessValue(forKey: Name.publishMonthID)
defer { didAccessValue(forKey: Name.publishMonthID) }
// publishMonthID의 getter 메서드가 현재 publishDate를 기반으로 값을 다시 계산
guard primitivePublishMonthID == nil, let date = primitivePublishDate else {
return primitivePublishMonthID
}
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents([.year, .month], from: date)
if let year = components.year, let month = components.month {
primitivePublishMonthID = "\(year * 1000 + month)"
}
return primitivePublishMonthID
}
// publishMonthID가 publishDate와 연결되고 항상 최신 상태를 유지할 수 있다.
// PublishMonthID가 Swift에서 Key-Value Observing을 사용하는 경우,
// 다음 코드는 publishDate가 변경될 때 observation이 트리거되도록 보장
class func keyPathsForValuesAffectingPublishMonthID() -> Set<String> {
return [Name.publishDate]
}
Derived Attribute
Derived Attribute(파생 속성)을 사용하여 다른 값에서 하나의 값 파생
- 저장 공간보다 성능이 더 중요한 경우 사용
- 사용자가 managed context를 저장할 때만 업데이트 됨
예제 코드
- canonical: 함수는 대소문자와 발음 구별 부호를 구분하지 않는 문자열 값을 반환
- 파생 속성은 사용자가 managed context를 저장할 때만 업데이트 되므로, title 속성을 저장하지 않고 변경하는 경우 canonicalTitle은 변경되지 않음
Predicate Programming Guide - String Comparisons
NSDerivedAttributeDescription | Apple Developer Documentation
extension ViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let predicate: NSPredicate
if let userInput = searchController.searchBar.text, !userInput.isEmpty {
// Searching title with "diacritic insensitive" option gets the same result:
// predicate = NSPredicate(format: "title CONTAINS[cd] %@", userInput)
// However, searching canonicalTitle avoids doing diacritic insensitive comparison every time,
// and hence has better performance.
//
predicate = NSPredicate(format: "canonicalTitle CONTAINS[c] %@", userInput)
} else {
predicate = NSPredicate(value: true)
}
fetchedResultsController.fetchRequest.predicate = predicate
do {
try fetchedResultsController.performFetch()
} catch {
fatalError("###\(#function): Failed to performFetch: \(error)")
}
tableView.reloadData()
}
}
Transformable Attribute
Transformable Attribute(변환 가능한 속성)을 사용하여 비표준 유형의 객체를 저장할 수 있음
예제 코드
- 타입을 Transformable로 설정하고, Data Model Inspector에서 Transformer 및 Custom Class 이름을 지정하여 구성
- 앱이 Core Data Stack을 로드하기 전에 코드로 Transformer을 등록
lazy var persistentContainer: NSPersistentContainer = {
// Register the transformer at the very beginning.
// .colorToDataTransformer is a name defined with an NSValueTransformerName extension.
ValueTransformer.setValueTransformer(ColorToDataTransformer(), forName: .colorToDataTransformer)
let container = NSPersistentContainer(name: "CoreDataAttributes")
container.loadPersistentStores(completionHandler: { (_, error) in
guard let error = error as NSError? else { return }
fatalError("###\(#function): Failed to load persistent stores:\(error)")
})
container.viewContext.automaticallyMergesChangesFromParent = true
SampleData.generateSampleDataIfNeeded(context: container.newBackgroundContext())
return container
}()
Date Type
Decimal Type
let value = UInt64(arc4random_uniform(9999))
book.price = NSDecimalNumber(mantissa: value, exponent: -2, isNegative: false)
cell.price.text = book.price?.description(withLocale: Locale.current) // ex) 98.14