Predicate
Spotlight, CoreData에서 검색조건을 나타낼 때 사용되는 Predicate는
기술의 종류, DB의 종류에 상관없이 검색조건 지정이 가능하다는 장점이 있다.
구현 자체에서 대소문자를 구분하진 않지만 키워드는 대문자로, 그 외엔 lowerCamelCase로 작성하는 것이 보통이다.
predicate를 사용하면 데이터 전체를 context에 전달하는 게 아닌
predicate의 조건에 맞는 데이터만 context에 전달하기 때문에 속도 향상을 기대할 수 있다.
PredicateViewController.swift
fetch()
- employee의 데이터를 이름순으로 정렬해 list 배열에 저장
- TableView 새로고침
searchBarSearchButtonClicked()
- 선택한 segment에 따라 해당하는 메서드 호출
- SearchBar의 Text를 파라미터로 전달
searchBarCancelButtonClicked()
- SearchBar 초기화
- 전체 데이터 표시
PredicateViewController.swift > fetch()
func fetch(predicate: NSPredicate? = nil) {
let request = NSFetchRequest<NSManagedObject>(entityName: "Employee")
request.predicate = predicate
let sortByName = NSSortDescriptor(key: "name", ascending: true)
request.sortDescriptors = [sortByName]
do {
list = try DataManager.shared.mainContext.fetch(request)
listTableView.reloadData()
} catch {
fatalError(error.localizedDescription)
}
}
segment에 해당되는 메서드들이 전달한 predicate를 사용해 fetch를 진행하기 때문에
파라미터로 전달받은 predicate를 request의 predicate 속성으로 전달한다.
PredicateViewController.swift > SearchByName()
func searchByName(_ keyword: String?) {
guard let keyword = keyword else { return }
let predicate = NSPredicate(format: "name CONTAINS[c] $@", keyword)
fetch(predicate: predicate)
}
NSPredicate(format:arguments:)
fetch로 전달할 predicate는 NSPredicate 클래스의 생성자를 사용한다.
첫 번째 파라미터에 조건으로 사용될 Predicate Format 문자열을 전달하고,
두 번째 파라미터에 가변 인자를 전달한다.
name CONTAINS %@
해당 Format 문자열은 name 데이터에서 keyword로 전달된 문자열이 존재하는지를 검색한다.
앞서 언급했듯 Predicate 문자열 자체는 대소문자를 구별하진 않지만 검색 자체에는 대소문자를 구별한다.
name CONTAINS[c] %@
따라서 Keyword의 뒤에 배열로 옵션을 지정함으로써 대소문자의 구별을 무시할 수 있다.
PredicateViewController.swift > SearchByMinimumAge()
func searchByMinimumAge(_ keyword: String?) {
guard let keyword = keyword, let age = Int(keyword) else { return }
let predicate = NSPredicate(format: "%K >= %d", #keyPath(EmployeeEntity.age), age)
fetch(predicate: predicate)
}
%K >= %d
%K는 파라미터로 전달된 Attr의 이름을 사용할 것을 의미한다.
앞 서 사용했던 %@는 문자열이나 참조 형식의 값을 사용할 것을 의미하기 때문에 둘은 명확히 구분해야 한다.
%d 혹은 %i는 숫자를 의미한다.
<=은 Swift의 비교 연산자와 동일하다.
지금처럼 두 개 이상의 가변 인자를 사용하는 경우 ',' 구분해 순서대로 전달한다.
따라서 #KeyPath(EmployeeEntity.age)는 %K에 age는 %d에 해당한다.
파라미터로 전달된 나이 이상의 직원을 출력하는 조건이 완성된다.
PredicateViewController.swift > SearchBySalaryRange()
func searchBySalaryRange(_ keyword: String?) {
guard let keyword = keyword else { return }
let comps = keyword.components(separatedBy: "-")
guard comps.count == 2, let min = Int(comps[0]), let max = Int(comps[1]) else { return }
let predicate = NSPredicate(format: "%K BETWEEN {%d, %d}", #keyPath(EmployeeEntity.salary), min, max)
fetch(predicate: predicate)
}
%K BETWEEN {%d, %d}
BETWEEN 키워드는 범위를 검색한다.
범위의 설정은 '{ }'로 묶어 순서대로 최소, 최대를 의미한다.
Text Field에 입력되는 값은 '-'을 기준으로 왼쪽이 최솟값, 오른쪽이 최댓값을 의미한다.
PredicateViewController.swift > SearchByDeptName()
func searchByDeptName(_ keyword: String?) {
guard let keyword = keyword else { return }
let predicate = NSPredicate(format: "%K BEGINSWITH[c] %@", #keyPath(EmployeeEntity.department.name), keyword)
fetch(predicate: predicate)
}
%K BEGINSWITH[c] %@
BEGINSWITH 키워드는 전달받은 문자열로 시작하는 문자열이 있는지를 검색한다.
마찬가지로 대소문자를 구별하기 때문에 이를 무시할 수 있도록 Case Insensitive 옵션을 사용할 수 있다.
대소문자를 구별하지 않고 부서명을 검색하고 있으며,
BEGINSWITH의 특성에 맞게 문자열의 시작 부분을 비교하고 있는 것을 확인할 수 있다.
'학습 노트 > iOS (2021)' 카테고리의 다른 글
192. Expression (0) | 2022.03.30 |
---|---|
191. Predicate Syntax (0) | 2022.03.24 |
187 ~ 189. Fetch Request (0) | 2022.02.25 |
187. Entity Hierarchy, Relationships (0) | 2022.02.18 |
186. Managed Object and Managed Object Context (0) | 2022.02.12 |