0

У меня есть модель данных базовых данных с двумя сущностями, документ и поля:NSPredicateEditor с отношением Core Data

  • Документ:

    • поле [для многих отношений]
    • имя
    • fieldText
    • fieldDate
    • fieldNumber
    • документ [в один отношения]

Я пытаюсь создать NSPredicateEditor, чтобы позволить кому-то фильтровать документы на основе содержание определенных полей. Я вручную построить редактор предиката как так:

func updatePredicateEditor() { 
    print("updatePredicateEditor") 

    let sortDescriptor = NSSortDescriptor(key: "orderIndex", ascending: true) 
    fieldsArrayController.sortDescriptors = [sortDescriptor] 
    let fields = fieldsArrayController.arrangedObjects as! [Field] 

    var keyPathsStringArray = [NSExpression]() 
    var stringFieldNames = [String]() 
    var keyPathsDateArray = [NSExpression]() 
    var dateFieldNames = [String]() 
    var keyPathsNumberArray = [NSExpression]() 
    var numberFieldNames = [String]() 

    for i in 0..<fields.count { 
     let currentField = fields[i] 

     switch currentField.type! { 
     case "Text": 
      keyPathsStringArray.append(NSExpression(forKeyPath: "fieldText")) 
      stringFieldNames.append(currentField.name!) 
     case "Date": 
      keyPathsDateArray.append(NSExpression(forKeyPath: "fieldDate")) 
      dateFieldNames.append(currentField.name!) 
     case "Number": 
      keyPathsNumberArray.append(NSExpression(forKeyPath: "fieldNumber")) 
      numberFieldNames.append(currentField.name!) 
     default: 
      print("error on field type") 
     } 
    } 

    let stringOperators = [NSNumber(unsignedInteger: NSPredicateOperatorType.ContainsPredicateOperatorType.rawValue), 
          NSNumber(unsignedInteger: NSPredicateOperatorType.EqualToPredicateOperatorType.rawValue), 
          NSNumber(unsignedInteger: NSPredicateOperatorType.NotEqualToPredicateOperatorType.rawValue), 
          NSNumber(unsignedInteger: NSPredicateOperatorType.BeginsWithPredicateOperatorType.rawValue), 
          NSNumber(unsignedInteger: NSPredicateOperatorType.EndsWithPredicateOperatorType.rawValue)] 

    let numberOperators = [NSNumber(unsignedInteger: NSPredicateOperatorType.EqualToPredicateOperatorType.rawValue), 
          NSNumber(unsignedInteger: NSPredicateOperatorType.NotEqualToPredicateOperatorType.rawValue), 
          NSNumber(unsignedInteger: NSPredicateOperatorType.LessThanPredicateOperatorType.rawValue), 
          NSNumber(unsignedInteger: NSPredicateOperatorType.LessThanOrEqualToPredicateOperatorType.rawValue), 
          NSNumber(unsignedInteger: NSPredicateOperatorType.GreaterThanPredicateOperatorType.rawValue), 
          NSNumber(unsignedInteger: NSPredicateOperatorType.GreaterThanOrEqualToPredicateOperatorType.rawValue)] 


    let dateOperators = [NSNumber(unsignedInteger: NSPredicateOperatorType.EqualToPredicateOperatorType.rawValue), 
         NSNumber(unsignedInteger: NSPredicateOperatorType.NotEqualToPredicateOperatorType.rawValue), 
         NSNumber(unsignedInteger: NSPredicateOperatorType.LessThanPredicateOperatorType.rawValue), 
         NSNumber(unsignedInteger: NSPredicateOperatorType.LessThanOrEqualToPredicateOperatorType.rawValue), 
         NSNumber(unsignedInteger: NSPredicateOperatorType.GreaterThanPredicateOperatorType.rawValue), 
         NSNumber(unsignedInteger: NSPredicateOperatorType.GreaterThanOrEqualToPredicateOperatorType.rawValue)] 

    var rowTemplatesTemp = [NSPredicateEditorRowTemplate]() // this is a temp array to hold the different popupbuttons 

    // add a template for Strings 

    let leftExpressionStringButton : NSPopUpButton 

    if keyPathsStringArray.count == 0 { 
     print("There aren't any text fields in NSPredicateEditor") 
    } 
    else { 
     let stringTemplate = NSPredicateEditorRowTemplate(leftExpressions: keyPathsStringArray, 
                         rightExpressionAttributeType: NSAttributeType.StringAttributeType, 
                         modifier: NSComparisonPredicateModifier.DirectPredicateModifier, 
                         operators: stringOperators, 
                         options: (Int(NSComparisonPredicateOptions.CaseInsensitivePredicateOption.rawValue) | 
                          Int(NSComparisonPredicateOptions.DiacriticInsensitivePredicateOption.rawValue))) 

     leftExpressionStringButton = stringTemplate.templateViews[0] as! NSPopUpButton 

     let stringButtonArray = leftExpressionStringButton.itemTitles 

     for i in 0..<stringButtonArray.count { 
      (leftExpressionStringButton.itemAtIndex(i)! as NSMenuItem).title = stringFieldNames[i] // set button menu names 
     } 

     rowTemplatesTemp.append(stringTemplate) 
    } 

    // add another template for Numbers... 

    let leftExpressionNumberButton : NSPopUpButton 

    if keyPathsNumberArray.count == 0 { 
     print("There aren't any number fields in NSPredicateEditor") 
    } 
    else { 
     let numberTemplate = NSPredicateEditorRowTemplate(leftExpressions: keyPathsNumberArray, 
                         rightExpressionAttributeType: NSAttributeType.Integer32AttributeType, 
                         modifier: NSComparisonPredicateModifier.DirectPredicateModifier, 
                         operators: numberOperators, 
                         options: 0) 

     leftExpressionNumberButton = numberTemplate.templateViews[0] as! NSPopUpButton 

     let numberButtonArray = leftExpressionNumberButton.itemTitles 

     for i in 0..<numberButtonArray.count { 
      (leftExpressionNumberButton.itemAtIndex(i)! as NSMenuItem).title = numberFieldNames[i] // set button menu names 
     } 

     rowTemplatesTemp.append(numberTemplate) 
    } 

    // add another template for Dates... 

    let leftExpressionDateButton : NSPopUpButton 

    if keyPathsDateArray.count == 0 { 
     print("There aren't any date fields in NSPredicateEditor") 
    } 
    else { 
     let dateTemplate = NSPredicateEditorRowTemplate(leftExpressions: keyPathsDateArray, 
                 rightExpressionAttributeType: NSAttributeType.DateAttributeType, 
                 modifier: NSComparisonPredicateModifier.DirectPredicateModifier, 
                 operators: dateOperators, 
                 options: 0) 


     leftExpressionDateButton = dateTemplate.templateViews[0] as! NSPopUpButton 

     let dateButtonArray = leftExpressionDateButton.itemTitles 

     for i in 0..<dateButtonArray.count { 
      (leftExpressionDateButton.itemAtIndex(i)! as NSMenuItem).title = dateFieldNames[i] // set button menu names 
     } 

     rowTemplatesTemp.append(dateTemplate) 
    } 

    // create the any, all or none thing... 
    let compoundTypes = [NSNumber.init(unsignedInteger: NSCompoundPredicateType.OrPredicateType.rawValue), 
         NSNumber.init(unsignedInteger: NSCompoundPredicateType.AndPredicateType.rawValue), 
         NSNumber.init(unsignedInteger: NSCompoundPredicateType.NotPredicateType.rawValue)] 

    // add the compoundtypes 
    let compoundTemplate = NSPredicateEditorRowTemplate(compoundTypes: compoundTypes) 
    rowTemplatesTemp.append(compoundTemplate) 

    print("setting row templates \(rowTemplatesTemp)") 

    predicateEditor.rowTemplates = rowTemplatesTemp 

    predicateEditor.addRow(self) 

} 

Проблема заключается в том, что NSPredicateEditor не позволяет NSExpressions с NSSubqueryExpressionType, так что я не могу иметь подзапрос как мое левое выражение. Мне нужно NSPredicateEditorRowTemplate включать как имя поля, а также путь атрибута (fieldText, fieldDate или fieldNumber), так что конечный предикат из одной строки будет выглядеть следующим образом:

name == FIELDNAME && fieldText CONTAINS "<entered text>" 

предложения, как сделать это ? Должен ли я подклассифицировать NSPredicateEditorRowTemplate, и если да, то как? Заранее благодарю за любую помощь.

+0

Можете ли вы привести пример конечного предиката с более чем одной строкой? Вы хотите установить предикат редактора? – Willeke

+0

Спасибо. Я не пытаюсь установить предикат редактора. Для нескольких строк предикат будет выглядеть примерно так: (name == FIELDNAME004 && fieldText004 CONTAINS [cd] "") ИЛИ (имя == FIELDNAME005 && fieldText010 CONTAINS [cd] "") –

+0

Вы хотите фильтровать документы или поля? – Willeke

ответ

0

Подкласс NSPredicateEditorRowTemplate и переопределить predicateWithSubpredicates для преобразования предиката "FIELDNAME CONTAINS <entered text>" в предикат "name == FIELDNAME && fieldText CONTAINS <entered text>".

+0

Спасибо! Отличное решение. –

Смежные вопросы