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

Posted

技术标签:

【中文标题】如何在 Swift 中使用 UnsafeMutablePointer<OpaquePointer>?【英文标题】:How to use UnsafeMutablePointer<OpaquePointer> in Swift? 【发布时间】:2017-07-03 21:11:50 【问题描述】:

如何在 Swift 中使用 UnsafeMutablePointer&lt;OpaquePointer&gt; 和一些 Core Foundation 框架?为什么要有UnsafeMutablePointer&lt;OpaquePointer&gt;

给定,一般:一些UnsafeMutablePointer&lt;SomeType&gt; 其中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 

观察到的错误

编译的东西不会运行。看起来(也许)合理的语法无法编译。

上面的示例得到以下(预期的)运行时“致命错误:在展开可选值时意外发现 nil”

一些选择其他尝试:

// 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!)

资源

Apple: Core Printing ⇗Apple: Using Swift with Cocoa and Objective-C ⇗

虽然文档提供了有用的信息,但类型别名为 UnsafeMutablePointer&lt;OpaquePointer&gt;UnsafeMutablePointer&lt;PMPrinter&gt; 的可行实现一直难以捉摸。

【问题讨论】:

【参考方案1】:

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

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

这些以OpaquePointer 的形式导入 Swift,并且有点 使用起来很麻烦。

PMSessionGetCurrentPrinter() 的第二个参数是指向 一个 非可选 PMPrinter 变量,在 Swift 中它必须是 在作为 inout 参数传递之前初始化。一种可能的方式 初始化空指针是使用unsafeBitCast

从数组中获取PMPaper 对象的最简单方法似乎是 是使用CFArrayGetValueAtIndex() 而不是将它桥接到一个 斯威夫特数组。这将返回一个 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)

【讨论】:

您提供的信息有助于完成 Core Printing Example 并创建类似于 Apple 相关技术说明(TN2155 和 TN2248)的 Swift 代码示例,目前只有 Objective-C 代码列表。谢谢。

以上是关于如何在 Swift 中使用 UnsafeMutablePointer<OpaquePointer>?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 kotlin native 中使用 swift 库?

如何在 Swift 中使用 Apple 地图 - 你必须使用 C 还是 Swift 可以?

如何在 Swift 中使用 MKPolylineView

如何在 Swift 中使用`syslog`

如何在 swift 项目中使用 TPKeyboardAvoiding?

如何在 Playground 中使用 Swift 包管理器