조회where절에서 표기법 주의~NSPredicate 주의~[RealmSwift]

6630 단어 SwiftRealm조회tech

문제.


final class Page: Object {
    @Persisted(primaryKey: true) var id = UUID().uuidString
    
    @Persisted var title: String
    @Persisted var isMarked = false
솔리드 정의가 있는 경우
let pageList = List<Page>(...)
let searchText = "banana"

let results = pageList.where {
    $0.isMarked
    && $0.title.contains(searchText, options: .caseInsensitive)
}
이런 검색어를 쓰면 실행 중 오류가 발생하여 욕을 먹는다.

해결책

where절에서 Bool형 변수를 사용할 때 boolValue를 사용하지 말고 boolValue == true로 기술한다.
즉, 위의 예에서
pageList.where {
    $0.isMarked == true // ここ
    && $0.title.contains(searchText, options: .caseInsensitive)
}
이 맞습니다.

까닭


각양각색의 실험을 통해 나는 이런 일을 알게 되었다.
  • where 섹션에 지정된 쿼리를 나타내는 클론이 실행되지 않음
  • 조회는 내부에서 NSPredicate의 문법으로 전환되고 NSPredicate로 검증을 수행한다.
  • 우선 where절의 정의를 살펴보자.
    func `where`(_ isIncluded: ((Query<Element>) -> Query<Bool>)) -> Results<Element>
    
    알고 있는 바와 같이 쿼리의 클론 유형은 ((Element) -> Bool)이 아니라 ((Query<Element>) -> Query<Bool>))입니다.이 일로 보아 흉계가 있는 것 같다.
    다음은 첫 번째로 소개한 오류 조회를 실행할 때의 오류 정보를 살펴보겠습니다.
    Unable to parse the format string \"(isMarked && (title CONTAINS[c] %@))\"
    
    내용이'해석불가NSPredicate의 포맷 문자열'이기 때문에 NSPredicate에서 나온 예외죠.그러나 쓴 코드에는 그런 것이 사용되지 않았다.따라서 조회의 복제는 어떤 방식으로 NSPredicate로 번역하는 것이 타당하다고 본다.조회의 컬렉션은 각 요소를 확인할 때마다 수행하는 것이 아니라 같은 의미NSPredicate로 전환한 뒤 수행하는 것이다.Query@dynamicMemberLookup 속성이 있기 때문에 안전하게 조회를 쓸 수 있습니다.조회에 적힌 $0.title는 실제로Page 대상의 title 속성이 없습니다.$0.isMarked == true$0.isMarked 두 가지 유형은 모두 일치성을 가지기 때문에 후자처럼 잘못된 문법도 컴파일할 수 있다.따라서 NSPredicate 전달된 표현이 문법으로서 정확하지 않아 실행할 때 오류가 발생할 수 있다.


    즉 컴파일러가 조회의 유형 안전을 보장했지만 문법의 타당성은 아직 보장되지 않았다는 것이다.이상의 일에 주의하면서 검색어를 쓰세요.

    참고 문장


    https://qiita.com/yusuga/items/8fd531ebd8f5e72bb97b

    컨디션

  • realm-swift v10.25.0
  • Xcode 13.3
  • macOS 12.3
  • iOS 15.4
  • 좋은 웹페이지 즐겨찾기