Reputation: 9832
How does one use an UnsafeMutablePointer<OpaquePointer>
in Swift with some Core Foundation framework? Why have an UnsafeMutablePointer<OpaquePointer>
?
Given, general: some UnsafeMutablePointer<SomeType>
where typealias SomeType = OpaquePointer
Specific Example API
// SOURCE: import ApplicationServices.PrintCore
typealias PMPrinter = OpaquePointer
func PMSessionGetCurrentPrinter(_ printSession: PMPrintSession, _ currentPrinter: UnsafeMutablePointer<PMPrinter>)
func PMPrinterGetPaperList(PMPrinter, UnsafeMutablePointer<Unmanaged<CFArray>?>)
Specific Example Use Case: get list of papers supported by a printer
let printInfo = NSPrintInfo.shared()
let printSession = PMPrintSession(printInfo.pmPrintSession())
var currentPrinterOptional: PMPrinter? = nil
PMSessionGetCurrentPrinter(printSession, ¤tPrinterOptional!)
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 }
What compiles does not run. What seems like (maybe) reasonable syntax does not compile.
The above example gets the following (expected) Runtime "fatal error: unexpectedly found nil while unwrapping an Optional value".
Some select other attempts:
// Compile Error: Address of variable 'currentPrinter' taken before is is initialized
var currentPrinter: PMPrinter
PMSessionGetCurrentPrinter(printSession, ¤tPrinter)
// Compile Error: Nil cannot initialze specified type 'PMPrinter' (aka 'OpaquePointer')
var currentPrinter: PMPrinter = nil
PMSessionGetCurrentPrinter(printSession, ¤tPrinter)
// 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, ¤tPrinterOptional!)
Apple: Core Printing ⇗
Apple: Using Swift with Cocoa and Objective-C ⇗
While the docs have useful information, a workable implementation for UnsafeMutablePointer<PMPrinter>
with typealias as UnsafeMutablePointer<OpaquePointer>
has been elusive.
Upvotes: 5
Views: 1904
Reputation: 539775
PMPrinter
and PMPaper
are defined in the PrintCore framework
as pointer to an "incomplete type"
typedef struct OpaquePMPrinter* PMPrinter;
typedef struct OpaquePMPaper* PMPaper;
Those are imported into Swift as OpaquePointer
, and are a bit
cumbersome to use.
The second argument to PMSessionGetCurrentPrinter()
is a pointer to
a non-optional PMPrinter
variable, and in Swift it must be
initialized before being passed as an inout argument. One possible way
to initialize a null-pointer is to use unsafeBitCast
.
The easiest way to get the PMPaper
objects from the array seems to
be to use CFArrayGetValueAtIndex()
instead of bridging it to a
Swift array. That returns a UnsafeRawPointer
which can be converted
to an OpaquePointer
.
This worked in my test:
let printInfo = NSPrintInfo.shared()
let printSession = PMPrintSession(printInfo.pmPrintSession())
var currentPrinter = unsafeBitCast(0, to: PMPrinter.self)
PMSessionGetCurrentPrinter(printSession, ¤tPrinter);
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)
}
Upvotes: 4