CoreData

NSFetchRequest with NSPredicate

JoonSwift 2022. 4. 12. 11:53

NSPredicate?

Fetch 작업이나, in-memory filtering 작업을  할 때, 검색에 대한 제약 사항을 논리적인 조건들(Logical conditions)로 정의할 수 있는 class입니다. 

그 중 대표적인 용도가 CoreData의 NSFetchRequest를 할 때, NSPredicate의 조건에 충족하는 객체들만을 필터링하여 받아올 수 있습니다. 

NSFetchRequest의 predicate 프로퍼티

그래서 NSFetchRequest의 공식 문서에 가보면, predicate라는 프로퍼티가 있는것을 확인할 수 있습니다.

The predicate instance constrains the selection of objects the NSFetchRequest instance is to fetch.

NSFetchRequest 인스턴스가 fetch할 때 선택할 객체들에 대한 제약사항을 명시해주는 역할을 한다고 나와있습니다. 

 

Predicate Format String Syntax

그럼 이 NSPredicate는 어떤 형태로 제약사항을 주는지 직접 코드로 작성하며 알아보도록 하겠습니다.

@objcMembers class Volunteer: NSObject {
  let name: String
  let age: Int
  let score: Double
  
  init(name: String, age: Int, score: Double) {
    self.name = name
    self.age = age
    self.score = score
  }
}

let kim = Volunteer(name: "Kim", age: 27, score: 90.5)
let park = Volunteer(name: "Park", age: 25, score: 85.3)
let james = Volunteer(name: "James", age: 30, score: 97.8)
let lee = Volunteer(name: "Lee", age: 31, score: 78.9)

let volunteers = [kim, park, james, lee] as NSArray

NSObject를 상속받는 Volunteer라는 클래스를 만들고, 인스턴스 4개를 만들어 volunteers라는 NSArray를 생성해주었습니다.

 

이제 NSArray의 filtered 메서드를 활용하여 NSPredicate 를 만들어 volunteers 내부의 값을 필터링 해보겠습니다. 

dump(volunteers.filtered(using: NSPredicate(
  format: "name = 'Kim'")
))

우선 첫번째 format은 "name = 'Kim'" 입니다. name이 Kim인 것만 필터링 하는 것이고, = 또는 == 을 사용할 수 있습니다.


dump(volunteers.filtered(using: NSPredicate(
  format: "age < 30")
))

다음은 "age < 30" 즉, age가 30미만인 값들만 가져오는 format입니다.


dump(volunteers.filtered(using: NSPredicate(
  format: "score BETWEEN {90, 100}")
))

이번에는 "score BETWEEN {90, 100}" 입니다. score의 값이 90~100 사이인 값들을 가져올 수 있습니다. 사용하다보니 이런 방식이 SQL과 정말 비슷하다는 생각이 듭니다. 


%@ and %K

format에 %@와 %K를 잘 활용하여 사용할 수 있는데, %@와 %K에 대해서 알아보겠습니다. 

  • %@ : 변수 argument로, 주로 string, number, date와 같은 object 값으로 대체할 수 있습니다. 
  • %K : 변수 argument로 keypath와 대체할 수 있습니다. 

C언어의 printf(%d, 100); 할때 %d 와 비슷한 역할인것 같습니다. 

dump(volunteers.filtered(using: NSPredicate(
  format: "%K = %@",
  "name", "Kim")
))

이런식으로 사용하여, name이 Kim인 것을 찾아낼 수 있고, 

dump(volunteers.filtered(using: NSPredicate(
  format: "%K CONTAINS %@",
  "name", "K")
))

CONTAINS를 활용하여 name에 K가 들어가는 것도 찾아낼 수 있습니다. 

 

또한 실제 Raywenderlich.com의 CoreData를 공부하는 중에

let request: NSFetchRequest<BowTie> = BowTie.fetchRequest()
request.predicate = NSPredicate(
  format: "%K = %@",
  argumentArray: [#keyPath(BowTie.searchKey), selectedValue]
)

BowTie의 searchKey와 selectedValue가 같은 값에 대한 fetch를 진행하기 위해 NSPredicate를 사용할 수 있었습니다.

 

참고

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html#//apple_ref/doc/uid/TP40001795-CJBDBHCB

 

Predicate Format String Syntax

SELF Represents the object being evaluated. Comma-separated literal array For example, { 'comma', 'separated', 'literal', 'array' }. Standard integer and fixed-point notations For example, 1, 27, 2.71828, 19.75. 0x Prefix used to denote a hexadecimal digit

developer.apple.com

- 더 많은 Operator들을 확인할 수 있고, 더 자세한 정보들이 위 공식문서에 있습니다!

 

https://developer.apple.com/documentation/foundation/nspredicate

 

Apple Developer Documentation

 

developer.apple.com