[Swift] Core Data (3) : NSFetchRequest, NSPredicate, NSSortDescriptor

Oni·2023년 9월 15일
0

TIL

목록 보기
46/47
post-thumbnail

Core Data에서 데이터를 필터링하기 위해서는 NSFetchRequest에 대해 조금 더 살펴볼 필요가 있다.


NSFetchRequest

Core Data에서 데이터를 검색하는데 사용되는 객체이며, 데이터베이스에서 원하는 엔터티의 레코드를 쿼리하기 위해 필요한 정보를 포함한다.
쉽게 말하면 내가 저장한 데이터를 전체 다 가져올 지, 몇개만 뽑아서 가져올 지, 가져와서 뭘 할 지 오더를 내리는 객체라고 이해하면 된다.

Entities 지정

NSFetchRequest를 생성할 때 검색하려고 하는 엔터티를 지정해야 한다.
엔터티를 지정하는 방법은 여러가지가 있는데 코드의 가독성을 고려하여 작성한다.

// (1)
let request = NSFetchRequest<Entity>(entityName: "Entity")

// (2)
let request: NSFetchRequest<Entity> = Entity.fetchRequest()

// (3)
let request = Entity.fetchRequest()

3가지 방법 모두 NSFetchRequest를 생성하는 방법이다.

  • (1) 직접 생성
    • NSFetchRequest를 직접 생성하고 엔터티의 이름을 지정하여 검색 요청을 정의
    • entityName 매개변수에는 검색할 엔터티의 이름을 String으로 전달
    • 엔터티 이름을 하드 코딩하는 방식으로 해당 방법은 지양
  • (2) 자동 생성
    • Core Data에서 자동으로 생성한 Swift 클래스의 fetchRequest() 메서드를 사용하는 방식
    • 엔터티 이름 하드 코딩할 필요없이 검색 요청 정의 가능
    • NSFetchRequest<Entity>라는 정확한 타입 정보를 가지고 있음
  • (3) 자동 생성 단축형
    • 2번의 방법과 동일하며, 타입 정보를 생략
    • 코드의 가독성을 높이고 간결한 방식
    • 엔터티 타입을 정확하게 추론

조건 설정

NSPredicate를 사용하여 데이터를 필터링 할 수 있다.
필터링은 연산자, 표현식 등 포맷을 지정하여 구현할 수 있다.

비교 연산자

==, !=, <, >, <=, >= 등의 비교 연산자를 통해 값을 비교한다.

NSPredicate(format: "age == 25") // 일치하는 항목 검색
NSPredicate(format: "name != 'Mike'") // 일치하지 않는 항목 검색
NSPredicate(format: "height > 160") // 큰 항목 검색

논리 연산자

AND, OR, NOT 등의 논리 연산자를 사용하여 여러 조건을 결합한다.

SPredicate(format: "age > 25 AND height > 160")
NSPredicate(format: "name == 'Jenny' OR name == 'Rose'")
NSPredicate(format: "NOT isComplete")

문자열 비교

LIKE, BEGINSWITH, CONTAINS, ENDSWITH 등을 사용하여 문자열을 비교할 수 있다.

// name이 J로 시작하는 항목 검색
NSPredicate(format: "name BEGINSWITH 'J'")

// 대소문자 구분없이 email에 ''이 포함된 항목 검색
NSPredicate(format: "email CONTAINS[c] 'example.com'")

배열 & 집합

IN 연산자를 사용하여 배열 또는 집합에서 값을 검색할 수 있다.

let favoriteColors = ["Red", "Blue", "Green"]

// color가 favoriteColors 배열에 포함된 항목 검색
NSPredicate(format: "color IN %@", favoriteColors) // %@ -> 컴마 뒤에 오는 객체

NULL

nil 값 또는 존재하지 않는 값(NSNull())을 검색할 때 nil, NIL을 사용한다.

NSPredicate(format: "middleName == nil")
NSPredicate(format: "middleName == NIL")

포맷 문자열

  • %@: 객체를 나타내며, 문자열, 숫자, 불리언 값을 나타낼 때 사용함
  • %K: 키 경로를 나타내며, 엔터티의 속성 이름 또는 관계의 키 경로를 사용할 때 유용함
  • %d, %f, %@: 정수, 부동 소수점, 문자열 값을 나타내며, %@는 모든 타입의 값을 받을 수 있음
  • %C: 문자(char) 값을 나타냄

정렬 설정

NSSortDescriptor를 사용하여 정렬 기준을 지정할 수 있다.

오름차순

let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)

내림차순

let sortDescriptor = NSSortDescriptor(key: "age", ascending: false)

복합정렬

여러 속성을 조합하여 복합 정렬이 가능하다.

let sortDescriptor1 = NSSortDescriptor(key: "continent", ascending: true)
let sortDescriptor2 = NSSortDescriptor(key: "country", ascending: true)
let compoundSortDescriptor = [sortDescriptor1, sortDescriptor2]

Custom 정렬

비교 함수 또는 클로저를 사용하여 정렬을 커스텀할 수 있다.
예를 들어, 날짜를 기준으로 정렬하되, 특정 날짜 이후의 항목은 먼저 나오도록 할 수 있다.

// 각 날짜를 dateAfter와 비교
let sortDescriptor = NSSortDescriptor(key: "date", ascending: true, comparator: { (date1, date2) -> ComparisonResult in
    
    // date1이 dateAfter보다 큰 경우
    if date1.compare(dateAfter) == .orderedDescending {
    	// date1을 dateAfter 이후로 정렬
        return .orderedAscending
    // date2가 dateAfter보다 큰 경우
    } else if date2.compare(dateAfter) == .orderedDescending {
    	// date2를 dateAfter 이후로 정렬
        return .orderedDescending
    } else {
        return date1.compare(date2)
    }
})

상기 코드는 사용자 정의 비교 로직을 사용하여 날짜를 정렬하며, dateAfter 날짜 이후에 오는 항목들은 앞으로, 이전에 오는 항목들은 뒤로 정렬된다.

Localized 문자열 정렬

문자열을 로케일에 맞게 정렬할 수 있다.

let sortDescriptor = NSSortDescriptor(key: "localizedTitle", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
  • key: "localizedTitle"
    • 정렬할 속성을 지정
    • "localizedTitle" 속성을 기준으로 데이터를 정렬
    • "localizedTitle"은 문자열 형태의 데이터를 가정함
  • ascending: true
    • ascending 매개변수는 정렬 순서를 결정(true는 오름차순)
    • 즉, "A"부터 "Z"까지 오름차순으로 정렬됨
  • selector: #selector(NSString.localizedCaseInsensitiveCompare(_:))
    • selector 매개변수는 비교자(comparator)를 지정함
    • 이 비교자는 문자열을 로케일에 맞게 비교하며 대소문자를 무시
    • NSString.localizedCaseInsensitiveCompare(_:)는 Foundation 프레임워크에 있는 문자열 비교 메서드로, 문자열을 로케일에 따라 비교하고 대소문자를 무시하여 정확한 로케일 및 대소문자 무시 비교를 수행함

그럼 이제 지금 만들고 있는 어플에 필터링을 적용해보자!

profile
하지만 나는 끝까지 살아남을 거야!

0개의 댓글