为什么NSPredicateEditor会自动本地化一些Expression字符串?如何禁用?

时间:2017-02-06 08:49:09

标签: macos cocoa nspredicateeditor nspredicateeditorrow nsruleeditor

我发现OS X会自动对某些 NSPredicateEditor / NSPredicateEditorRowTemplate值进行本地化。

在运算符映射中很容易观察到:.equalTo到字符串is

但我只是注意到UTI字符串被映射到该UTI的人类可读版本。

下面,我设置了"public.image"但它显示为"image"

UTI operators in NSPredicateEditor

func setupPredicateEditor() {
    let left = [NSExpression(forKeyPath: "Type")]

    let operators = [NSComparisonPredicate.Operator.equalTo.rawValue as NSNumber]

    let right = [
        NSExpression(forConstantValue: "public.image"),
        NSExpression(forConstantValue: "public.text"),
        NSExpression(forConstantValue: "public.fakeUTI"),
        ];

    let rowTemplate = NSPredicateEditorRowTemplate.init(leftExpressions: left, rightExpressions: right, modifier: .all, operators: operators, options: 0)
    predicateEditor.rowTemplates = [rowTemplate]

    predicateEditor.addRow(self)
}

只有某些有效的UTI以这种方式映射。我不知道运算符和UTI之外的其他格式是否都有自动本地化字符串。

这是一个问题,因为我想要localize my NSPredicateEditor and Row Templates

本地化谓词的过程涉及将键与本地化值匹配。

KEY: "%[left]@ %[is]@ %[right]@"
VAL: "%1$[left_display_string]@ %2$[is]@ %3$[right_display_string]@"

问题是密钥中的值必须与UI 中显示的字符串匹配。不是最初设置为行模板的左右表达式的字符串。

因此,我无法使用密钥中的"public.image"进行本地化。用户界面由于某种原因已经将其本地化为"image"。如果我想本地化行模板,我必须使用字符串"image"。我不知道这个"image"字符串是如何或为何被选中的。

我可以通过测试确定这些字符串,然后编写一个将表达式映射到本地化字符串的表。但是我希望有一个解决方案来禁用这种自动本地化,这样我就不必担心我没有测试过的字符串。

为什么UTI会自动本地化?其他值是否接受相同的治疗?

有没有办法禁用UTI字符串和/或整个谓词编辑器的自动本地化?

3 个答案:

答案 0 :(得分:1)

不是答案,而是一些信息:NSPredicateEditorRowTemplate翻译_displayValueForConstantValue:中的字符串。它使用字典:

{
    "com.apple.application" = application;
    "com.apple.pict" = PICT;
    "com.apple.protected-mpeg-4-audio" = "purchased music";
    "com.apple.rtfd" = RTFD;
    "com.compuserve.gif" = GIF;
    "com.microsoft.bmp" = BMP;
    "public.audio" = music;
    "public.folder" = folder;
    "public.html" = HTML;
    "public.image" = image;
    "public.jpeg" = JPEG;
    "public.jpeg-2000" = "JPEG 2000";
    "public.mp3" = MP3;
    "public.mpeg-4-audio" = "MPEG4 audio";
    "public.png" = PNG;
    "public.rtf" = RTF;
    "public.source-code" = "source code";
    "public.text" = text;
    "public.tiff" = TIFF;
    "public.xml" = XML;
}

BT:

AppKit`-[NSPredicateEditorRowTemplate _displayValueForConstantValue:] + 913
AppKit`-[NSPredicateEditorRowTemplate _viewFromExpressions:] + 589
AppKit`-[NSPredicateEditorRowTemplate initWithLeftExpressions:rightExpressions:modifier:operators:options:] + 205

编辑:

_displayValueForKeyPath:使用此词典:

{
    kMDItemContentCreationDate = Created;
    kMDItemContentModificationDate = "Last modified";
    kMDItemContentTypeTree = "File type";
    kMDItemDisplayName = "File display name";
    kMDItemFSContentChangeDate = "Change date";
    kMDItemFSCreationDate = "Creation date";
    kMDItemFSName = "File name";
    kMDItemFSOwnerGroupID = "Owner group id";
    kMDItemFSOwnerUserID = "Owner user ID";
    kMDItemFSSize = "File size";
    kMDItemLastUsedDate = "Last opened";
    kMDItemPath = "File path";
}

_displayValueForPredicateOperator:_displayValueForCompoundPredicateType:将枚举翻译为字符串。

这应该记录在案,但不是。我在_displayValueForConstantValue:上放了一个断点,我看着发生了什么。字典是硬编码的,在其他版本的macOS中可能有所不同。

答案 1 :(得分:0)

扩展Willeke的好答案:

将符号断点添加到以下私有方法中以查看映射。

  • _displayValueForKeyPath:
  • _displayValueForConstantValue:
  • _displayValueForCompoundPredicateType:
  • _displayValueForPredicateOperator:

中断时,将断点放在包含objc_msgSend的行上,然后在此处再次中断。

然后输入po $rax以打印映射表。

在下面两种情况下,它不使用字典,但是在命中断点时可以看到字符串。

_displayValueForKeyPath:

{
    kMDItemContentCreationDate = Created;
    kMDItemContentModificationDate = "Last modified";
    kMDItemContentTypeTree = "File type";
    kMDItemDisplayName = "File display name";
    kMDItemFSContentChangeDate = "Change date";
    kMDItemFSCreationDate = "Creation date";
    kMDItemFSName = "File name";
    kMDItemFSOwnerGroupID = "Owner group id";
    kMDItemFSOwnerUserID = "Owner user ID";
    kMDItemFSSize = "File size";
    kMDItemLastUsedDate = "Last opened";
    kMDItemPath = "File path";
}

_displayValueForConstantValue:

{
    "com.apple.application" = application;
    "com.apple.pict" = PICT;
    "com.apple.protected-mpeg-4-audio" = "purchased music";
    "com.apple.rtfd" = RTFD;
    "com.compuserve.gif" = GIF;
    "com.microsoft.bmp" = BMP;
    "public.audio" = music;
    "public.folder" = folder;
    "public.html" = HTML;
    "public.image" = image;
    "public.jpeg" = JPEG;
    "public.jpeg-2000" = "JPEG 2000";
    "public.mp3" = MP3;
    "public.mpeg-4-audio" = "MPEG4 audio";
    "public.png" = PNG;
    "public.rtf" = RTF;
    "public.source-code" = "source code";
    "public.text" = text;
    "public.tiff" = TIFF;
    "public.xml" = XML;
}

_displayValueForCompoundPredicateType:

0x7fff32a7342c <+20>: leaq   0x5ca25255(%rip), %rax    ; @"Any"
0x7fff32a73434 <+28>: leaq   0x5c9c8dad(%rip), %rax    ; @"None"
0x7fff32a7343c <+36>: leaq   0x5ca00ac5(%rip), %rax    ; @"All"
0x7fff32a73456 <+62>: leaq   0x5ca2524b(%rip), %rdx    ; @"(unknown compound type %ld)"

_displayValueForPredicateOperator:

0x7fff32a7331b <+42>:  leaq   0x5ca251c6(%rip), %rax    ; @"is less than"
0x7fff32a73332 <+65>:  leaq   0x5ca251cf(%rip), %rax    ; @"is less than or equal to"
0x7fff32a7334a <+89>:  leaq   0x5ca252f7(%rip), %rax    ; @"between"
0x7fff32a73356 <+101>: leaq   0x5ca251cb(%rip), %rax    ; @"is greater than"
0x7fff32a73362 <+113>: leaq   0x5ca251df(%rip), %rax    ; @"is greater than or equal to"
0x7fff32a7336b <+122>: leaq   0x5ca251f6(%rip), %rax    ; @"is"
0x7fff32a73374 <+131>: leaq   0x5ca2520d(%rip), %rax    ; @"is not"
0x7fff32a7337d <+140>: leaq   0x5ca25224(%rip), %rax    ; @"matches"
0x7fff32a73386 <+149>: leaq   0x5ca2523b(%rip), %rax    ; @"is like"
0x7fff32a7338f <+158>: leaq   0x5ca25252(%rip), %rax    ; @"begins with"
0x7fff32a73398 <+167>: leaq   0x5ca25269(%rip), %rax    ; @"ends with"
0x7fff32a733a1 <+176>: leaq   0x5ca01300(%rip), %rax    ; @"in"
0x7fff32a733aa <+185>: leaq   0x5ca25277(%rip), %rax    ; @"contains"
0x7fff32a733d4 <+227>: leaq   0x5ca2528d(%rip), %rdx    ; @"(unknown predicate operator %ld)"

答案 2 :(得分:0)

您可以直接调用私有API方法来使用系统的映射。

在Swift中,这需要一个桥接头:

#import <AppKit/AppKit.h>

@interface NSPredicateEditorRowTemplate ()

- (NSString *)_displayValueForKeyPath:(CFStringRef)keyPath;
- (NSString *)_displayValueForConstantValue:(CFStringRef)constantValue;
- (NSString *)_displayValueForCompoundPredicateType:(NSCompoundPredicateType)compoundPredicateType;
- (NSString *)_displayValueForPredicateOperator:(NSPredicateOperatorType)predicateOperator;

@end

然后可以像下面这样调用这些私有方法:

let keyPath = rowTemplate._displayValue(forKeyPath: kMDItemFSSize) // "File size"
let constantValue = rowTemplate._displayValue(forConstantValue: "com.apple.application" as CFString) // "application"
let compoundPredicateType = rowTemplate._displayValue(for: .or) // "Any"

以上三个方法均有效,但是我目前遇到_displayValueForPredicateOperator:EXC_BAD_ACCESS崩溃或返回错误的字符串翻译的问题。