问题描述
我调用一些返回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()
同样,我们现在可以利用免费的桥接功能CFStringRef
至NSString
和String
:
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 \n
s 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字符串形式获取值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!