How to use UnsafeMutablePointer<OpaquePointer> in Swift?

l --marc l

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, &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 }

Observed Errors

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, &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!)

Resources

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.

Martin R

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, &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)
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How to Initialize OpaquePointer in Swift

How to use UnsafeMutablePointer in Swift 3?

How to use UnsafeMutablePointer<T?> in swift 3

How to create UnsafeMutablePointer<UnsafeMutablePointer> in swift

How to create UnsafeMutablePointer<CGPoint> Object in swift

How to cast self to UnsafeMutablePointer<Void> type in swift

How to dealloc UnsafeMutablePointer referenced from Swift struct

how to loop through elements of array of <UnsafeMutablePointer> in Swift

Swift UnsafeMutablePointer & UnsafeMutablePointer<UnsafePointer<SomeType>>

How to get length of a UnsafeMutablePointer<Object> written to a OpenSSL BIO in Swift?

How to cast UnsafeMutableRawPointer! to UnsafeMutablePointer<Float> in Swift 3.0 or newer?

How to do pointer arithmetic on UnsafeMutablePointer and get String in Swift 3

How to convert String to UnsafeMutablePointer<UInt8> ? Swift 3

UnsafeMutablePointer<CFTypeRef> in Swift 3

UnsafeMutablePointer to expected argument type UnsafeMutablePointer<_> in Swift 3

How to create a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>

Error in UnsafeMutablePointer in swift3

Swift 2 - UnsafeMutablePointer<Void> to object

Using UnsafeMutablePointer and CFRunLoopObserverContext in swift 2

Cast a Swift struct to UnsafeMutablePointer<Void>

What is UnsafeMutablePointer<Unmanaged<CMSampleBuffer>?> in Swift?

UnsafeMutablePointer<Bytef> swift3

Swift: Cannot convert value of type 'UnsafeMutablePointer' to expected argument type 'UnsafeMutablePointer'

How to represent Objc-C NSUInteger[] = {0,1,2} in Swift as UnsafeMutablePointer<UInt>?

How to convert a type of "any" in kind "UnsafeMutablePointer<Int16>" in a swift 3

In Swift 3.1, UnsafeMutablePointer.initialize(from:) is deprecated

Swift convert Data to UnsafeMutablePointer<Int8>

Cast a swift dictionary ( [String:AnyObject] ) to a UnsafeMutablePointer

Convert UnsafeMutableRawPointer to UnsafeMutablePointer<T> in swift 3