본문 바로가기
iOS/트러블 슈팅

[iOS] CoreData에서 특정 Entity 내부에 있는 Entity의 특정값을 가져오고 싶을 때(NSPredicate)

by MINT09 2023. 12. 20.

코어데이터를 사용하는 방법을 연습하다가 생긴 일이다. 먼저 entity로는 UserMO와 JokeMO 두개가 있다.

User와 Joke는 Model도 있다.

여기서 보면 알 수 있듯이 User는 Joke 배열을 가지고 있다. 때문에 특정한 User의 특정 카테고리를 갖는 Joke만 선별하고 싶은 과정에서 문제가 있었다.

func fetchWithPredicate(currentUser: User, currentCategory: Category) -> [Joke] {
    var jokes = [Joke]()
    let fetchRequest: NSFetchRequest<UserMO> = UserMO.fetchRequest()
    let idPredicate = NSPredicate(format: "id = %@", currentUser.id as CVarArg)
    fetchRequest.predicate = idPredicate
        
    if let result = try? appDelegate.container.viewContext.fetch(fetchRequest) {
        let jokesData = object.jokes as! Set<JokeMO>
        result.forEach { jokeData in
            let data = Joke(id: jokeData.id!, content: jokeData.content!, category: Category(rawValue: Int(jokeData.category))!)
            jokes.append(data)
            if data.category == currentCategory {
                jokes.append(data)
            }
        }
    }
        
    return jokes
}

처음에는 이러한 코드를 작성했다. 일단 NSPredicate를 사용해 user의 id로 특정한 userMO를 가져오고 그렇게 가져온 userMO를 fetch해서 user의 모든 데이터를 가져온다. 그 후 안의 내용은 모두 fetch 되어 있는 상태니 NSSet로 가져와진 jokes 데이터를 타입캐스팅하고 그 안에서 currentCategory와 맞는 Joke만 배열에 추가해서 return 한다.

근데 이렇게 하면 일단 모든 정보를 가져와서 if문으로 걸러주기에 굳이 알 필요 없는 데이터까지 전부 가져온다는 생각이 들었다. 그래서 찾은 방법이 이것이다.

func fetchWithPredicate(currentUser: User, currentCategory: Category) -> [Joke] {
    var jokes = [Joke]()
    let fetchRequest: NSFetchRequest<JokeMO> = JokeMO.fetchRequest()
    let idPredicate = NSPredicate(format: "user.id = %@ AND category = %x", currentUser.id as CVarArg, Int16(currentCategory.rawValue))
    fetchRequest.predicate = idPredicate
        
    if let result = try? appDelegate.container.viewContext.fetch(fetchRequest) {
        result.forEach { jokeData in
            let data = Joke(id: jokeData.id!, content: jokeData.content!, category: Category(rawValue: Int(jokeData.category))!)
            jokes.append(data)
        }
    }
        
    return jokes
}

relation을 통해 Joke역시 User에 대한 정보를 가지고 있다. 본인을 들고 있는 User에 대해서! 그래서 처음부터 JokeMO에서 NSPredicate로 거름망처럼 조건을 주었다. user.id를 통해 User의 id로 거르고, 그 안에서 category로 거른다. 그 후 fetch한 데이터를 새로운 Joke타입으로 만들어서 배열에 추가해 반환하면 끝!

코어데이터의 개념에 대해서 더 파봐야겠다는 생각을 했다. predicate를 잘 쓰면 아주 적은 비용으로 원하는 데이터만 가져올 수 있다!