JXA及其内置的ObjC桥接器通过Foundation
对象自动公开$
框架中的枚举和常量; e.g:
$.NSUTF8StringEncoding // -> 4
但是,在自动导入的低级API中也有一些有用的CFString
常量,即kUTType*
中用于定义常用UTI的常量CoreServices
常量}值,例如kUTTypeHTML
用于UTI "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?
我还没有找到一种方法来获取返回内容的字符串:
ObjC.unwrap($.kUTTypeHTML)
不起作用,ObjC.unwrap($.kUTTypeHTML[0])
(也不.deepUnwrap()
)也不起作用。
我想知道:
ObjC.bindFunction()
来定义可以解决问题的CFString*()
函数的绑定,例如CFStringGetCString()
或CFStringGetCStringPtr()
,但这并不明显告诉我如何翻译ObjC签名。答案 0 :(得分:2)
虽然我不明白所有含义,但以下似乎有效:
$.CFStringGetCStringPtr($.kUTTypeHTML, 0) // -> 'public.html'
# Alternative, with explicit UTF-8 encoding specification
$.CFStringGetCStringPtr($.kUTTypeHTML, $.kCFStringEncodingUTF8) // ditto
kUTType*
常量定义为CFStringRef
,CFStringGetCStringPtr
以指定的编码返回CFString
对象的内部C字符串, if 可以提取"with no memory allocations and no copying, in constant time" - 或NULL
。
使用内置常量,似乎总是返回一个C字符串(而不是NULL
),它通过映射到JXA数据类型的C数据类型直接在JavaScript中使用:< / p>
$.CFStringGetCStringPtr($.kUTTypeHTML, 0) === 'public.html' // true
对于背景信息(从OSX 10.11.1开始),请继续阅读。
JXA本身并不识别CFString
个对象,即使它们可以“免费桥接”到NSString
,这是JXA 识别的类型。
您可以通过执行CFString
验证JXA是否不知道NSString
和$.NSString.stringWithString($.kUTTypeHTML).js
的等效性,应该返回输入字符串的副本,但却以-[__NSDictionaryM length]: unrecognized selector sent to instance
失败。
不承认CFString
是我们的出发点:$.kUTTypeHTML
的类型为CFString[Ref]
,但JXA不返回 JS 字符串表示形式,仅[object Ref]
。
注意:以下内容部分是推测性的 - 请告诉我,如果我错了。
不识别CFString
会产生另一个副作用,即调用接受泛型类型的CF*()
函数时(或接受免费桥接的{Cocoa方法} {{1 JXA不知道的类型):
在这种情况下,如果参数类型与调用函数的参数类型不完全匹配,则JXA显然隐式包装 CF*
实例中的输入对象,其唯一条目具有键CFDictionary
,其关联值包含原始对象。 [1]
据推测,这就是上述type
调用失败的原因:它正在传递$.NSString.stringWithString()
包装而不是CFDictionary
实例。
另一个例子是CFString
函数,它需要一个CFGetTypeID()
参数:即任何 CFTypeRef
类型。
由于JXA不知道将CF*
参数作为CFStringRef
参数原样传递是可以的,它会错误地执行上述包装,并有效地传递{{1}而实例代替:
CFTypeRef
这是houthakker {/ 3}}中遇到的his solution attempt。{/}
对于给定的CFDictionary
功能,您可以绕过默认行为,方法是使用$.CFGetTypeID($.kUTTypeHTML) // -> !! 18 (CFDictionary), NOT 7 (CFString)
重新定义感兴趣的功能:
CF*
现在,ObjC.bindFunction()
正确返回// Redefine CFGetTypeID() to accept any type as-is:
ObjC.bindFunction('CFGetTypeID', ['unsigned long', [ 'void *']])
($.CFGetTypeID($.kUTTypeHTML)
)。
注意:重新定义的7
返回JS CFString
实例,而原始实例返回基础数字的{em>字符串表示($.CFGetTypeID()
值)。
通常情况下,如果您想非正式地了解给定Number
个实例的具体类型,请使用CFTypeID
,例如:
CF*
注意:CFShow()
不返回任何内容,而是直接打印到 stderr ,因此您无法捕获JS中的输出。
您可以使用$.CFShow($.kUTTypeHTML) // -> '{\n type = "{__CFString=}";\n}'
重新定义CFShow()
,以便不显示包装词典。
对于本机识别的CF *类型 - 映射到JS基元的类型 - 您将直接看到特定类型(例如,CFShow
用于ObjC.bindFunction('CFShow', ['void', [ 'void *' ]])
);对于未知 - 因此包装 - 实例,您将看到如上所述的包装结构 - 继续阅读。
[1] 在传递未知类型时,运行以下内容为您提供 由JXA生成的包装器对象 :
CFBoolean
同样,使用false
和// 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)
的已知与JXA等效,
NSDictionary
返回CFDictionary
,即具有属性ObjC.deepUnwrap($.NSDictionary.dictionaryWithDictionary( $.kUTTypeHTML ))
的JS对象,其值为此时 - 在ObjC-bridge调用往返之后 - 仅仅字符串表示可能是原始{"type":"{__CFString=}"}
实例的内容。
houthakker's solution attempt还包含一个方便的代码片段,用于获取type
实例的 name 类型字符串。
如果我们将它重构为一个函数并应用CFString
的必要重新定义,我们得到以下内容,但是:
CF*
而不是CFGetTypeID()
。 如果有人解释为什么需要黑客攻击以及随机角色来自哪里,请告诉我。这些问题可能与内存管理有关,因为CFString,
和CFString
都会返回调用者必须释放的对象,而我不知道是否/如何/何时JXA那样做。
CFCopyTypeIDDescription()
答案 1 :(得分:2)
您可以通过首先重新绑定CFMakeCollectable函数将CF类型强制转换为NS类型,以便它可以使用&#39; void *&#39;并返回&#39; id&#39;,然后使用该函数执行强制:
ObjC.bindFunction('CFMakeCollectable', [ 'id', [ 'void *' ] ]);
var cfString = $.CFStringCreateWithCString(0, "foo", 0); // => [object Ref]
var nsString = $.CFMakeCollectable(cfString); // => $("foo")
为了在代码中更容易使用,您可以在Ref原型上定义.toNS()函数:
Ref.prototype.toNS = function () { return $.CFMakeCollectable(this); }
以下是如何将此新函数与CFString常量一起使用:
ObjC.import('CoreServices')
$.kUTTypeHTML.toNS() // => $("public.html")
答案 2 :(得分:1)
$ .kUTTypeHTML似乎返回一个CFDictionary(见下文),因此您应该在以下位置找到可用的方法:
编辑:事实证明,JXA-ObjC-CF交互中的一些打字复杂性意味着下面的片段不是学习CF对象参考类型的可靠或普遍适用的方法。 (参见下面的讨论)。
https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFDictionaryRef/
ObjC.import('CoreServices')
var data = $.CFStringCreateExternalRepresentation(
null,
$.CFCopyTypeIDDescription(
$.CFGetTypeID($.kUTTypeHTML)
),
'UTF-8',
0
); // CFDataRef
cPtr = $.CFDataGetBytePtr(data);
// --> "CFDictionary"