如何将Swift数组转换为CFArray?

时间:2015-03-09 16:28:15

标签: objective-c macos swift

我试图使用Swift在Mac OS X应用中捕获一个窗口列表。 CGWindowListCreateImageFromArray函数需要CFArray。我尝试了几件事,这是我最接近的事情。或者有更好的方法来转换数组吗?

import Cocoa

// Example swift array of CGWindowID's
var windowIDs = [CGWindowID]();
windowIDs.append(1);
windowIDs.append(2);

// Convert to CFArray using CFArrayCreate
let allocator = kCFAllocatorDefault
let numValues = windowIDs.count as CFIndex
let callbacks: UnsafePointer<CFArrayCallBacks> = nil
var values: UnsafeMutablePointer<UnsafePointer<Void>> = nil

/* how do I convert windowIDs to UnsafeMutablePointer<UnsafePointer<Void>> for the values? */

let windowIDsCFArray = CFArrayCreate(allocator, values,  numValues, callbacks);

let capture = CGWindowListCreateImageFromArray(CGRectInfinite, windowIDsCFArray, CGWindowImageOption(kCGWindowListOptionOnScreenOnly));

3 个答案:

答案 0 :(得分:5)

只要您将UnsafeMutablePointer设置为CGWindowID,就可以使用您的数组初始化CFTypeRef

var windows: [CFTypeRef] = [1, 2]
var windowsPointer = UnsafeMutablePointer<UnsafePointer<Void>>(windows)
var cfArray = CFArrayCreate(nil, windowsPointer, windows.count, nil)

答案 1 :(得分:0)

Swift中的数组被桥接到NSArray,因为它们包含对象,例如符合[AnyObject]类型。由于CGWindowIDUInt32,您需要将其转换为NS系列,数组&#39; map()方法是一种优雅的方法。

var windows: [CGWindowID] = [CGWindowID(1), CGWindowID(2)]
var array: CFArray = windows.map({NSNumber(unsignedInt: $0)}) as CFArray

然而,这并未反映实际的CGWindowListCreateImageFromArray问题。以下是该工作解决方案:

let windows: [CGWindowID] = [CGWindowID(17), CGWindowID(50), CGWindowID(59)]
let pointer: UnsafeMutablePointer<UnsafePointer<Void>> = UnsafeMutablePointer<UnsafePointer<Void>>.alloc(windows.count)

for var i: Int = 0, n = windows.count; i < n; i++ {
    pointer[i] = UnsafePointer<Void>(bitPattern: UInt(windows[i]))
}

let array: CFArray = CFArrayCreate(kCFAllocatorDefault, pointer, windows.count, nil)
let capture: CGImage = CGWindowListCreateImageFromArray(CGRectInfinite, array, CGWindowImageOption.Default)!
let image: NSImage = NSImage(CGImage: capture, size: NSZeroSize)

Swift.print(image) // <NSImage 0x7f83a3d16920 Size={1440, 900} Reps=("<NSCGImageSnapshotRep:0x7f83a3d2dea0 cgImage=<CGImage 0x7f83a3d16840>>")>

我在ObjC上并不擅长,如果错误请更正,但是通过玩SonOfGrab示例和下面的特定代码,我理解的是最终指针结构包含窗口ID(UInt32 )不在内存单元格(UnsafePointer实例的memory属性)内,而是在内存地址(hashValue属性)内。

const void *windowIDs[2]; 
windowIDs[0] = 10; 
windowIDs[1] = 20; 

很有意思,因为值不是存储在内存中,而是存储在地址描述符中,最老的体系结构是32位UInt32值完全适合地址指针。也许回到记忆是一个限制因素的时代,这很有意义,并且是一个很好的方法。 2016年在斯威夫特发现这一整夜让我自杀。

更糟糕的是,它在Xcode 7.2游乐场中因某些窗口ID而失败,可能是因为它处理内存的方式,但在实际应用程序中有效。

答案 2 :(得分:0)

Ian's answer转换为Swift 4:

let windows = [CGWindowID(17), CGWindowID(50), CGWindowID(59)]
let pointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: windows.count)
for (index, window) in windows.enumerated() {
    pointer[index] = UnsafeRawPointer(bitPattern: UInt(window))
}
let array: CFArray = CFArrayCreate(kCFAllocatorDefault, pointer, windows.count, nil)

let capture = CGImage(windowListFromArrayScreenBounds: CGRect.infinite, windowArray: array, imageOption: [])!
let image: NSImage = NSImage(cgImage: capture, size: NSSize.zero)

Swift.print(image)