NSPredicateEditor & NSExpression - Может ли отображение отличаться от значения для предиката?

У меня есть редактор предикатов, который шаблон был сгенерирован с помощью следующего:

    NSArray * test = [NSArray arrayWithObjects:
                      [NSExpression expressionForKeyPath: @"Abc"],
                      [NSExpression expressionForKeyPath: @"Def"],
                      nil];


    NSPredicateEditorRowTemplate * template = [[NSPredicateEditorRowTemplate alloc] initWithLeftExpressions: test
                                   rightExpressionAttributeType: NSStringAttributeType
                                                       modifier: NSDirectPredicateModifier
                                                      operators: [NSArray arrayWithObject:
                                                                 [NSNumber numberWithUnsignedInteger:NSContainsPredicateOperatorType]]
                                                        options:(NSCaseInsensitivePredicateOption|NSDiacriticInsensitivePredicateOption)];

Так что, если я заполню редактор предикатов следующим образом:Редактор предикатов

Когда я выхожу из сгенерированного предиката, я получаю:

Abc CONTAINS[cd] "abc" OR Def CONTAINS[cd] "def"

Что мне интересно, так это то, что я могу каким-то образом показать, как шаблон редактора предикатов будет отличаться от значения, установленного в сгенерированном предикате.

EX: я хочу, чтобы выходной предикат имел:

Field1 CONTAINS[cd] "abc" OR Field2 CONTAINS[cd] "def"

Даже если редактор все еще отображает abc а также def как поля. Это возможно?

4 ответа

Решение

Да, ты можешь это сделать.

Вы хотите, чтобы массив левых выражений был фактическим keyPaths в конечном предикате. В твоем случае, "Field1" а также "Field2",

Что касается того, чтобы во всплывающем окне появлялось другое значение, то здесь возникает умопомрачительная концепция:

Вы собираетесь локализовать свой редактор предикатов на английский.

Есть два способа сделать это.

  1. С файлом.strings
  2. С NSDictionary

С файлом.strings

В своем источнике вы бы включили в комментарий следующее:

// NSLocalizedStringFromTable(@"%[Field1,Field2]@ %[contains]@ %@", @"PredicateEditor", @"")

Когда ты бежишь genstrings в вашем исходном коде это сгенерирует PredicateEditor.strings файл со следующими записями:

"%[Field1]@ %[contains]@ %@" = "%[Field1]@ %[contains]@ %@";
"%[Field2]@ %[contains]@ %@" = "%[Field2]@ %[contains]@ %@";

Вы бы изменили значения на:

"%[Field1]@ %[contains]@ %@" = "%[Abc]@ %[contains]@ %@";
"%[Field2]@ %[contains]@ %@" = "%[Def]@ %[contains]@ %@";

Затем, когда вы создаете свой NSPredicateEditor, вы бы установили formattingStringsFileName собственность на "PredicateEditor", а редактор позаботится обо всем остальном.

С NSDictionary

Это будет следовать тем же фундаментальным концепциям, что и опция.strings, за исключением того, что вы по существу сделаете:

NSDictionary *formatting = @{
  @"%[Field1]@ %[contains]@ %@" : @"%[Abc]@ %[contains]@ %@",
  @"%[Field2]@ %[contains]@ %@" : @"%[Def]@ %[contains]@ %@"
}
[myPredicateEditor setFormattingDictionary:formatting];

Это все, что вам нужно сделать.

Я писал об этом давным-давно, и там есть больше информации, которая может оказаться полезной.

В основном вы хотите изменить заголовок пунктов меню в вашей всплывающей кнопке. Это все, что вам нужно сделать. Это не должно влиять на основной предикат, который вы получите. Если вы создали его в конструкторе интерфейсов, легко получить доступ к пунктам меню шаблона и установить их заголовок. Но так как вы сделали это в коде, вам придется исправить это в коде.

Вот как вы можете это сделать. В моем классе шаблона строки я хотел изменить ширину моих полей NSTextFields. Поэтому в своем классе шаблонов строк я их ищу и изменяю следующим образом...

- (void)awakeFromNib {
    NSArray* views = [self templateViews];
    for (id view in views) {
        if ([[view class] isEqual:[NSTextField class]]) {
            NSRect tfFrame = [view frame];
            tfFrame.size.width = 600;
            [view setFrame:tfFrame];
        }
    }
}

Вы можете видеть, что я получаю templateViews и ищу NSTextFields... и затем изменяю их. Вы могли бы сделать что-то подобное, ища кнопки NSPopupButtons. Как только вы нашли один, проверьте названия пунктов меню и найдите те, которые названы "abc" и "def", и измените их названия на "Field1" и "Field2" соответственно.

Да, все дело в локализации, благодаря тому, что объекты являются пунктами меню. И к ним так легко относиться.

Все, что вам нужно сделать, это...

  • локализуйте ваше приложение.
  • Затем введите файл.strings и измените значение на то, что вы хотите отображать, или... используйте инструменты для управления / перевода локализованных приложений.

Вот пример изменения вещей непосредственно в файле.strings: Изменение заключается в том, чтобы ist и booktitle в Buchtitel

/* Class = "NSMenuItem"; title = "is"; ObjectID = "G1c-st-GEK"; */
"G1c-st-GEK.title" = "ist";

/* Class = "NSMenuItem"; title = "booktitle"; ObjectID = "nQh-54-5Nx"; */
"nQh-54-5Nx.title" = "Buchtitel";

Примечание. Лучший способ найти строку для изменения - поиск ObjectID. Это может быть найдено для каждого MenuItem инспектором идентификации UIB:

Вместо того, чтобы использовать NSLocalizedString с литералами опций в определенном формате и genstrings для генерации строк локализации кажется проще / понятнее создать финальные строки файла локализации.strings самостоятельно.

Из этого поста в блоге мы можем использовать Private API _generateFormattingDictionaryStringsFile чтобы получить строки форматирования из самого NSPredicateEditor:

extension NSPredicateEditor {

    func formattingDictionaryStrings() -> String? {
        var strings: String? = nil

        if let formattingDictionaryData = self.perform(Selector("_generateFormattingDictionaryStringsFile"))?.takeRetainedValue() as? Data {
            strings = String(data: formattingDictionaryData, encoding: .utf16)
        }

        return strings
    }

}

Это генерирует все перестановки, пропуская необходимость genstrings, Затем вы заменяете токены справа от = с вашими отображаемыми пользователем строками.

"%[ABC]@ %[is]@ %[123]@" = "%1$[ABC]@ %2$[is]@ %3$[123]@";
"%[ABC]@ %[is]@ %[456]@" = "%1$[ABC]@ %2$[is]@ %3$[456]@";
"%[ABC]@ %[is]@ %[789]@" = "%1$[ABC]@ %2$[is]@ %3$[789]@";
"%[ABC]@ %[contains]@ %[123]@" = "%1$[ABC]@ %2$[contains]@ %3$[123]@";
"%[ABC]@ %[contains]@ %[456]@" = "%1$[ABC]@ %2$[contains]@ %3$[456]@";
"%[ABC]@ %[contains]@ %[789]@" = "%1$[ABC]@ %2$[contains]@ %3$[789]@";

Более того, вы можете создать код, который создает каждый NSPredicateEditorRowTemplate принять в качестве входных данных как ключевой путь, используемый внутри предиката, так и локализованную строку для этой опции.

Ваш метод может генерировать строки выше, но с правильной локализацией, уже вставленной.

ПРИМЕЧАНИЕ: вызов этого _generateFormattingDictionaryStringsFile метод частного API, кажется, вызывает случайные сбои в NSPredicateEditor:

этот класс не соответствует значению ключа для ключа rowType,

Поэтому обязательно запускайте его один раз, когда это необходимо, но не оставляйте его активным, когда вы обычно запускаете или тестируете свое приложение.

Другие вопросы по тегам