iOS Realm Filter objects in a list of a relationship

怎甘沉沦 提交于 2019-12-03 05:24:51

Realm doesn't have any sort of concept of a deep-filtered view, so you can't have a Results<Canteen> which restricts the Lists contained in related objects to vegan meals.

There are several similar things which you can do. You could add inverse relationship properties, and then query Meal objects instead:

class Canteen: Object {
    dynamic var name: String?
    let lines = List<Line>()
}

class Line: Object {
    dynamic var name: String?
    let meals = List<Meal>()
    let canteens = LinkingObjects(fromType: Canteen.self, property: "lines")
}

class Meal: Object {
    dynamic var name: String?
    dynamic var vegan: Bool = false
    let lines = LinkingObjects(fromType: Line.self, property: "meals")
}

let meals = realm.objects(Meal).filter("vegan = true AND ANY lines.canteens.name = %@", selectedCanteenType.rawValue)

(Or rather, you will be able to once Realm 0.102.1 is out; currently this crashes).

If you just need to iterate over the meals but need to do so from the Canteen down, you could do:

let canteens = realm.objects(Canteen).filter("name = %@ AND ANY lines.meals.vegan = true", selectedCanteenType.rawValue)
for canteen in canteens {
    for line in canteen.lines.filter("ANY meals.vegan = true") {
        for meal in line.meals.filter("vegan = true") {
            // do something with your vegan meal
        }
    }
}

This unfortunately has some duplication due to needing to repeat the filter for each level of the references.

Try this:

let predicate = NSPredicate(format: "name == %@", "")
var canteens: [Canteen] = realm.objects(Canteen).filter(predicate).map { can in
    // Iterate through all the Canteens
    let lines: [Line] = can.lines.map { (line: Line) in
        // Iterate through all the lines in each canteene
        // Filter all the Meals that are NOT vegan
        let meals = line.meals.filter { $0.vegan == true }
        line.meals = List<Meal>(meals)
        return line
    }
    can.lines = List<Line>(lines)
    return can
}

Realm allows it to use functions as parameter for the filtering. So this is my solution which im currently using.

The two filter functions:

func vegetarianFilter(_ meal: Meal) -> Bool {

        if showVegetarianOnly {
            if(meal.veg || meal.vegan){
                return true
            }

            return false
        }

        return true
}

func filterEmptyLines(_ line: Line) -> Bool {

       if(line.meals.filter(vegetarianFilter).count > 0){
           return true
       }

       return false
}

The functions filter all meals which are not vegetarian or vegan when the user has selected showVegetarianOnly = true. Also it filters all lines which than have no meal left (nothing is vegetarian or vegan).

Most important functions of the TableView:

    override func numberOfSections(in tableView: UITableView) -> Int {
            return canteenDay?.lines.filter(filterEmptyLines).count ?? 0
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return canteenDay?.lines.filter(filterEmptyLines)[section].meals.filter(vegetarianFilter).count ?? 0
    }

   override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = UITableViewCell()

        let meal = canteenDay!.lines.filter(filterEmptyLines)[indexPath.section].meals.filter(vegetarianFilter)[indexPath.row]

        cell.textLabel?.text = meal.meal

       return cell
    }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!