本文介绍了Swift:CFArray:以UTF字符串形式获取值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我调用一些返回CFStringRef值的CFArray的函数.我需要从中获取utf字符串.由于我不想让我的代码过于复杂,因此我做了以下事情:

let initString = "\(TISCreateInputSourceList(nil, false).takeUnretainedValue())"

然后我将结果字符串除以\n来获得Swift字符串数组.但是,当函数开始返回非ASCII字符串时,便开始出现问题.我开始收到类似"\ U2345 \ U2344"的字符串.

然后我尝试使用CFArray并对其进行迭代以获取值,并可能将它们转换为String,但是我无法从中获取值:

值始终为空.

如何获取实际值?

解决方案

这里有一些问题.首先,TISCreateInputSourceList()名称中包含创建",这意味着它返回保留的(+1)对象,您必须使用takeRetainedValue()取值,不是takeUnretainedValue(),否则代码将泄漏内存:

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue()

您现在可以使用CFArray...方法从数组中获取值,但将其转换为NSArray(免费电话桥接")要容易得多:

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue() as NSArray

这不是CFStringRef值的数组,而是一个TISInputSource对象.您可以将NSArray转换为Swift数组:

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue()
                    as NSArray as! [TISInputSource]

强制转换as!在这里是可以接受的,因为该函数是已记录以返回输入源数组.

现在,您可以简单地遍历数组的元素:

for src in srcs  {
    // do something with `src` (which is a `TISInputSource`)
}

使用TISGetInputSourceProperty()函数检索输入源的属性,例如:

let ptr = TISGetInputSourceProperty(src, kTISPropertyInputSourceID)

这将返回一个"void指针"(UnsafeMutablePointer<Void>),该指针必须转换为对象适当类型的指针(对于kTISPropertyInputSourceID属性).不幸的是,这有点复杂(比较如何将自身转换为UnsafeMutablePointer< Void>类型迅速):

let val = Unmanaged<CFString>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()

同样,我们现在可以利用免费的桥接功能CFStringRefNSStringString:

let val = Unmanaged<CFString>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()
                    as String

将它们放在一起:

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue()
                as NSArray as! [TISInputSource]
for src in srcs  {
    let ptr = TISGetInputSourceProperty(src, kTISPropertyInputSourceID)
    let val = Unmanaged<CFString>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()
                as String
    print(val)
}

I call some functions that return a CFArray of CFStringRef values. I need to get utf strings from them. As I didn't want to make my code too complicated, I did the following:

let initString = "\(TISCreateInputSourceList(nil, false).takeUnretainedValue())"

And then I just split the resulting string by \ns to get an array of Swift strings. However, when the function started returning non-ascii strings, trouble started. I started getting strings like "\U2345\U2344".

Then i tried to take the CFArray and iterate over it getting the values and possibly converting them to Strings, but I can't get the values from it:

        let ar = TISCreateInputSourceList(nil, true).takeUnretainedValue()
        for i in 0...CFArrayGetCount(ar) - 1 {
            print(">> ( CFArrayGetValueAtIndex(ar, i).memory )")
        }

The values are always empty.

How can i get the actual values?

解决方案

There are some issues here. First, TISCreateInputSourceList()has "Create" in its name which means that it returns a (+1) retainedobject and you have to take the value with takeRetainedValue(),not takeUnretainedValue(), otherwise the code will leak memory:

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue()

You could now use the CFArray... methods to get values from the array,but it is much easier to convert it to a NSArray (which is "toll-free bridged"):

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue() as NSArray

This is not an array of CFStringRef values but an array ofTISInputSource objects. You can convert the NSArray to a Swift array:

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue()
                    as NSArray as! [TISInputSource]

The forced cast as! is acceptable here because the function isdocumented to return an array of input sources.

Now you can simply iterate over the elements of the array:

for src in srcs  {
    // do something with `src` (which is a `TISInputSource`)
}

The properties of an input source are retrieved with the TISGetInputSourceProperty() function, for example:

let ptr = TISGetInputSourceProperty(src, kTISPropertyInputSourceID)

This returns a "void pointer" (UnsafeMutablePointer<Void>) which has to be converted to an objectpointer of the appropriate type (which is CFStringRef for thekTISPropertyInputSourceID property). Unfortunately, this is a bitcomplicated (compare How to cast self to UnsafeMutablePointer<Void> type in swift):

let val = Unmanaged<CFString>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()

Again we can take advantage of toll-free bridging, now fromCFStringRef to NSString and String:

let val = Unmanaged<CFString>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()
                    as String

Putting it all together:

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue()
                as NSArray as! [TISInputSource]
for src in srcs  {
    let ptr = TISGetInputSourceProperty(src, kTISPropertyInputSourceID)
    let val = Unmanaged<CFString>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()
                as String
    print(val)
}

这篇关于Swift:CFArray:以UTF字符串形式获取值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-30 04:02