mkl*_*nt0 4 objective-c core-services javascript-automation
JXA具有内置的 ObjC 桥接器,Foundation可通过对象自动从框架公开枚举和常量$;例如:
$.NSUTF8StringEncoding // -> 4
Run Code Online (Sandbox Code Playgroud)
但是,较低级别 API 中也有一些CFString不会自动导入的有用常量,即定义常用UTIkUTType*值的常量,例如UTI 。CoreServiceskUTTypeHTML"public.html"
虽然您可以使用 导入它们ObjC.import('CoreServices'),但它们的字符串值无法(轻松)访问,大概是因为它的类型是CFString[Ref]:
ObjC.import('CoreServices') // import kUTType* constants; ObjC.import('Cocoa') works too
$.kUTTypeHTML // returns an [object Ref] instance - how do you get its string value?
Run Code Online (Sandbox Code Playgroud)
我还没有找到一种方法来获取返回内容的核心
字符串ObjC.unwrap($.kUTTypeHTML):不起作用,也不起作用ObjC.unwrap($.kUTTypeHTML[0])(也.deepUnwrap())。
我想知道:
ObjC.bindFunction()定义可以解决问题的函数的绑定CFString*(),例如 toCFStringGetCString()或CFStringGetCStringPtr(),但对我来说如何翻译 ObjC 签名并不明显。虽然我不理解所有含义,但以下似乎有效:
$.CFStringGetCStringPtr($.kUTTypeHTML, 0) // -> 'public.html'
# Alternative, with explicit UTF-8 encoding specification
$.CFStringGetCStringPtr($.kUTTypeHTML, $.kCFStringEncodingUTF8) // ditto
Run Code Online (Sandbox Code Playgroud)
常量kUTType*定义为CFStringRef,并且如果可以“在常量时间内没有内存分配和复制”提取对象的内部 C 字符串,则以指定的编码返回该对象的内部 C 字符串,否则CFStringGetCStringPtr返回。CFStringNULL
使用内置常量,似乎NULL总是返回 C 字符串(而不是 ),它 - 凭借 C 数据类型映射到 JXA 数据类型 - 可直接在 JavaScript 中使用:
$.CFStringGetCStringPtr($.kUTTypeHTML, 0) === 'public.html' // true
Run Code Online (Sandbox Code Playgroud)
有关背景信息(自 OSX 10.11.1 起),请继续阅读。
JXA 本身并不识别CFString对象,尽管它们可以“免费桥接”到JXA确实NSString识别的类型。
您可以通过执行来验证 JXA 不知道CFString和 的等价性,这应该返回输入字符串的副本,但会失败并显示。NSString$.NSString.stringWithString($.kUTTypeHTML).js-[__NSDictionaryM length]: unrecognized selector sent to instance
不认识CFString是我们的出发点:$.kUTTypeHTML是 类型CFString[Ref],但 JXA 不返回它的JS[object Ref]字符串表示,只返回。
注意:以下内容部分是推测性的 - 如果我错了,请告诉我。
不识别CFString还有另一个副作用,即当调用CF*()接受泛型CF*类型的函数(或接受JXA 不知道的免费桥接类型的 Cocoa 方法)时:
在这种情况下,如果参数类型与调用的参数类型不完全匹配函数的参数类型,JXA 显然隐式地将输入对象包装CFDictionary在一个实例中,该实例的唯一条目具有 key type,关联值包含原始对象。[1]
据推测,这就是上述$.NSString.stringWithString()调用失败的原因:它传递的是CFDictionary包装器而不是CFString实例。
另一个恰当的例子是CFGetTypeID()函数,它需要一个CFTypeRef参数:即任何 CF*类型。
由于 JXA 不知道可以按原样传递CFStringRef参数作为CFTypeRef参数,因此它错误地执行了上述包装,并有效地传递了一个CFDictionary实例:
$.CFGetTypeID($.kUTTypeHTML) // -> !! 18 (CFDictionary), NOT 7 (CFString)
Run Code Online (Sandbox Code Playgroud)
对于给定的CF*函数,您可以通过使用重新定义感兴趣的函数来绕过默认行为:ObjC.bindFunction()
// Redefine CFGetTypeID() to accept any type as-is:
ObjC.bindFunction('CFGetTypeID', ['unsigned long', [ 'void *']])
Run Code Online (Sandbox Code Playgroud)
现在,$.CFGetTypeID($.kUTTypeHTML)正确返回7( CFString)。
注意:重新定义$.CFGetTypeID()返回一个 JSNumber实例,而原始返回底层数字(值)的字符串CFTypeID表示形式。
一般来说,如果您想非正式地了解给定CF*实例的特定类型,请使用CFShow(),例如:
$.CFShow($.kUTTypeHTML) // -> '{\n type = "{__CFString=}";\n}'
Run Code Online (Sandbox Code Playgroud)
注意:CFShow()不返回任何内容,而是直接打印到stderr,因此无法捕获 JS 中的输出。
您可以重新定义CFShowwithObjC.bindFunction('CFShow', ['void', [ 'void *' ]])以免显示包装字典。
对于本机识别的 CF* 类型(映射到 JS 原语的类型),您将直接看到特定类型(例如CFBooleanfor false);对于未知的 - 因此被包装的 - 实例,您将看到如上所述的包装器结构 - 继续阅读以了解更多信息。
[1]运行以下命令可以让您了解JXA在传递未知类型时生成的包装器对象:
// Note: CFShow() prints a description of the type of its argument
// directly to stderr.
$.CFShow($.kUTTypeHTML) // -> '{\n type = "{__CFString=}";\n}'
// Alternative that *returns* the description as a JS string:
$.CFStringGetCStringPtr($.CFCopyDescription($.kUTTypeHTML), 0) // -> (see above)
Run Code Online (Sandbox Code Playgroud)
类似地,使用已知的 JXA 等效项NSDictionary和CFDictionary,
ObjC.deepUnwrap($.NSDictionary.dictionaryWithDictionary( $.kUTTypeHTML ))
Run Code Online (Sandbox Code Playgroud)
返回{"type":"{__CFString=}"},即一个具有属性的 JS 对象type,其值在此时 - 在 ObjC 桥调用往返之后 -可能是原始实例的纯粹字符串CFString表示形式。
houthakker 的解决方案尝试还包含一个方便的代码片段,用于以字符串形式获取实例的类型名称。CF*
如果我们将其重构为一个函数并应用必要的重新定义CFGetTypeID(),我们会得到以下结果:
CFString,不是CFString。如果有人能解释为什么需要破解以及随机字符从何而来,请告诉我。这些问题可能与内存管理相关,因为CFCopyTypeIDDescription()和返回调用者CFStringCreateExternalRepresentation()必须释放的对象,并且我不知道 JXA 是否/如何/何时执行此操作。
$.CFStringGetCStringPtr($.kUTTypeHTML, 0) // -> 'public.html'
# Alternative, with explicit UTF-8 encoding specification
$.CFStringGetCStringPtr($.kUTTypeHTML, $.kCFStringEncodingUTF8) // ditto
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1000 次 |
| 最近记录: |