如何在Swift中使用UnsafeMutablePointer<OpaquePointer>?

5

如何在Swift中使用UnsafeMutablePointer<OpaquePointer>并与一些Core Foundation框架配合?为什么需要UnsafeMutablePointer<OpaquePointer>

通常情况下,有一些UnsafeMutablePointer<SomeType>,其中typealias SomeType = OpaquePointer

具体API示例

// SOURCE: import ApplicationServices.PrintCore
typealias PMPrinter = OpaquePointer
func PMSessionGetCurrentPrinter(_ printSession: PMPrintSession, _ currentPrinter: UnsafeMutablePointer<PMPrinter>)
func PMPrinterGetPaperList(PMPrinter, UnsafeMutablePointer<Unmanaged<CFArray>?>)

特定实例使用情况: 获取打印机支持的纸张列表.
let printInfo = NSPrintInfo.shared()
let printSession = PMPrintSession(printInfo.pmPrintSession())
var currentPrinterOptional: PMPrinter? = nil
PMSessionGetCurrentPrinter(printSession, &currentPrinterOptional!)
guard let currentPrinter = currentPrinterOptional else { return }

// Get the array of pre-defined PMPapers this printer supports.
// PMPrinterGetPaperList(PMPrinter, UnsafeMutablePointer<Unmanaged<CFArray>?>)
var paperListUnmanaged: Unmanaged<CFArray>?
PMPrinterGetPaperList(currentPrinter, &paperListUnmanaged)
guard let paperList = paperListUnmanaged?.takeUnretainedValue() as [AnyObject]? else { return }

观察到的错误

编译通过的代码未必能够运行。看起来(也许)合理的语法未必能够编译通过。

上面的例子会产生以下(预期的)运行时错误:"fatal error: unexpectedly found nil while unwrapping an Optional value"

以下是一些尝试:

// Compile Error: Address of variable 'currentPrinter' taken before is is initialized
var currentPrinter: PMPrinter
PMSessionGetCurrentPrinter(printSession, &currentPrinter)

// Compile Error: Nil cannot initialze specified type 'PMPrinter' (aka 'OpaquePointer')
var currentPrinter: PMPrinter = nil
PMSessionGetCurrentPrinter(printSession, &currentPrinter)

// Compile Error: Variable 'currentPrinterPtr' used before being initialized
var currentPrinterPtr: UnsafeMutablePointer<PMPrinter>
PMSessionGetCurrentPrinter(printSession, currentPrinterPtr)

// Compile OK: actually compiles
// Runtime Error: unexpectedly found nil while unwrapping an Optional value
var currentPrinterOptional: PMPrinter? = nil
PMSessionGetCurrentPrinter(printSession, &currentPrinterOptional!)

资源

苹果:核心打印 ⇗
苹果:使用Swift与Cocoa和Objective-C ⇗

虽然文档中有有用的信息,但是对于 typealias 为 UnsafeMutablePointer<OpaquePointer>UnsafeMutablePointer<PMPrinter> 的可行实现一直很难找到。

1个回答

4

PMPrinterPMPaper 在 PrintCore 框架中被定义为指向“不完整类型”的指针。

typedef struct OpaquePMPrinter*         PMPrinter;
typedef struct OpaquePMPaper*           PMPaper;

这些被导入Swift作为OpaquePointer,使用起来有点麻烦。 PMSessionGetCurrentPrinter()的第二个参数是一个指向非可选的PMPrinter变量的指针,在Swift中必须在传递为inout参数之前进行初始化。初始化空指针的一种可能方法是使用unsafeBitCast
从数组中获取PMPaper对象最简单的方法似乎是使用CFArrayGetValueAtIndex()而不是将其转换为Swift数组。这将返回一个UnsafeRawPointer,可以将其转换为OpaquePointer
这在我的测试中起作用:
let printInfo = NSPrintInfo.shared()
let printSession = PMPrintSession(printInfo.pmPrintSession())

var currentPrinter = unsafeBitCast(0, to: PMPrinter.self)
PMSessionGetCurrentPrinter(printSession, &currentPrinter);

var paperListUnmanaged: Unmanaged<CFArray>?
PMPrinterGetPaperList(currentPrinter, &paperListUnmanaged)
guard let paperList = paperListUnmanaged?.takeUnretainedValue() else {
    fatalError()
}
for idx in 0..<CFArrayGetCount(paperList) {
    let paper = PMPaper(CFArrayGetValueAtIndex(paperList, idx))!
    var width = 0.0, height = 0.0
    PMPaperGetWidth(paper, &width)
    PMPaperGetHeight(paper, &height)
    print(width, height)
}

1
您提供的信息对于完成核心打印示例并创建类似于苹果相关技术说明(TN2155&TN2248)的Swift代码示例非常有帮助,这些说明目前仅具有Objective-C代码列表。谢谢。 - l --marc l

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接