How can I use Swift to call an objective-C method that expects an argument of type (int *)? - objective-c

An existing objective-C method has the following signature:
-(BOOL)barcodeSetScanBeep:(BOOL)enabled volume:(int)volume beepData:(int *)data length:(int)length error:(NSError **)error;
Note that beepData: expects (int *).
This method can be used from objective-C by passing in a C array:
int beepData[] = {1200,100};
How can I call the same method from Swift? My best attempt, let beepData: [Int] = [1200, 100], doesn't compile.

int is a C 32-bit integer and mapped to Swift as Int32.
A int * parameter is mapped to Swift as UnsafeMutablePointer<Int32>,
and you can pass a variable array as "inout parameter" with &.
So it should roughly look like this:
var beepData : [ Int32 ] = [ 1200, 100 ]
var error : NSError?
if !DTDevices.sharedDevice().barcodeSetScanBeep(true, volume: Int32(100),
beepData: &beepData, length: Int32(beepData.count),
error: &error) {
println(error!)
}
Swift defines also a type alias
/// The C 'int' type.
typealias CInt = Int32
so you could replace Int32 by CInt in above code if you want to emphasize that
you are working with C integers.
For more information, see "Interacting with C APIs" in the "Using Swift with Cocoa and Objective-C" documentation.

Related

ObjC -> Swift Conversion Error: For-in loop requires '[AnyHashable : Any]?' to conform to 'Sequence'; did you mean to unwrap optional?

I am struggling with converting this for loop from ObjC to Swift
Obj C Code
NSMutableDictionary *varnameDict;
for(NSString *varName in [varnameDict allKeys]) { ... }
Converting to Swift 5
var varNameDict: [AnyHashable : Any]?
for varName in varnameDict{...}
The error I get at for in loop line is:
For-in loop requires '[AnyHashable : Any]?' to conform to 'Sequence'; did you mean to unwrap optional?
I have also tried the following:
for varName in varnameDict?.keys ?? [] {...}
I get the following error:
Cannot convert value of type 'Dictionary<AnyHashable, Any>.Keys?' to expected argument type 'Optional<_>'
I don't have an extensive background here. I would appreciate any help or direction.

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

Objc-C header definition:
- (int)printPDFAtPath:(NSString *)pdfPath pages:(NSUInteger [])indexes length:(NSUInteger)length copy:(int)nCopy;
Sample objc-C code to use this function:
NSUInteger pageIndexes[] = {0};
printResult = [self.ptp printPDFAtPath:selectedPDFFilePath pages:pageIndexes length:length copy:self.numberOfPaper];
Swift expects:
func printPDF(atPath pdfPath: String!, pages indexes: UnsafeMutablePointer<UInt>!, length: UInt, copy nCopy: Int32) -> Int32
How do I represent NSUInteger pageIndexes[] = {0}; in Swift as a UnsafeMutablePointer<UInt>?
You can simply pass a Swift [UInt] array as in-out argument with &, this passes the address of the array element storage to the (Objective-)C function:
var pageIndexes: [UInt] = [1, 2, 3]
ptp.printPDF(atPath: "path", pages: &pageIndexes, length: UInt(pageIndexes.count), copy: 1)
For more information, see
Using Imported C Functions in Swift,
Interacting with C Pointers.

Obtaining a list of class names with objc_getClassList in JavaScript for Automation

By using ObjC.bindFunction in JXA, we can obtain an integer result from objc_getClassList.
Does anyone understand the types and bridging issues well enough to find a route to getting a list of class name strings returned by objc_getClassList into the JavaScript for Automation JSContext ?
(The code below returns only an [Object Ref] string)
(() => {
'use strict';
ObjC.import('stdlib');
ObjC.bindFunction('CFMakeCollectable', [ 'id', [ 'void *' ] ]);
ObjC.bindFunction('objc_getClassList', ['int', ['void *', 'int']]);
var classes = Ref();
const intClasses = $.objc_getClassList(null, 0);
$.objc_getClassList(classes, intClasses);
$.CFMakeCollectable(classes);
return [intClasses, classes];
//-> [11411, [object Ref]]
})();
The objc_getClassList function is expecting us to provide it with a buffer of memory to copy the class list into. Normally, JXA would treat the return type of malloc as a C array of unsigned chars, but using bindFunction we can cast malloc's return type to a C array of pointers, and make objc_getClassList's first argument match that type. Then, it's just a matter of indexing into the buffer (of type Ref) and passing that value into class_getName.
ObjC.bindFunction('objc_getClassList', ['int', ['void**', 'int']])
ObjC.bindFunction('malloc', ['void**', ['int']])
ObjC.bindFunction('class_getName', ['char *', ['void*']])
const numClasses = $.objc_getClassList(undefined, 0)
const classes = $.malloc(8*numClasses)
$.objc_getClassList(classes, numClasses)
for (i=0; i<numClasses; i++) {
console.log("classes[" + i + "]: " + $.class_getName(classes[i]))
}

In Swift how do I configure a AutoreleasingUnsafeMutablePointer?

For an iOS app I am converting some Objective-C code to Swift.
The Objective-C code uses a method with this signature:
+ (nullable NSArray<MTKMesh*>*)newMeshesFromAsset:(nonnull MDLAsset *)asset
device:(nonnull id<MTLDevice>)device
sourceMeshes:(NSArray<MDLMesh*>* __nullable * __nullable)sourceMeshes
error:(NSError * __nullable * __nullable)error;
Here is how it is called:
NSArray<MTKMesh *> *mtkMeshes;
NSArray<MDLMesh *> *mdlMeshes;
mtkMeshes = [MTKMesh newMeshesFromAsset:asset
device:_device
sourceMeshes:&mdlMeshes
error:&error];
I am trying to convert this to Swift and I think I am doing it wrong because the method call always fails.
The Swift version of the above method:
open class func newMeshes(from asset: MDLAsset, device: MTLDevice, sourceMeshes: AutoreleasingUnsafeMutablePointer<NSArray?>?) throws -> [MTKMesh]
How I use it:
do {
var myPointer: AutoreleasingUnsafeMutablePointer<NSArray?>? = nil
myPointer = AutoreleasingUnsafeMutablePointer<NSArray?>.init(&modelIOMeshList)
metalMeshList = try MTKMesh.newMeshes(from:asset, device:device, sourceMeshes: myPointer)
} catch {
fatalError("Error: Can not create Metal mesh from Model I/O asset")
}
The method is supposed to populate the two array. It does not do that. What have I missed here?
To a parameter of type
AutoreleasingUnsafeMutablePointer<NSArray?>?
you can pass the address of a NSArray? variable with &, so this should work:
var sourceMeshes: NSArray?
metalMeshList = try MTKMesh.newMeshes(from:asset, device:device,
sourceMeshes: &sourceMeshes)

Using C style unsigned char array and bitwise operators in Swift

I'm working on changing some Objective-C Code over to Swift, and I cannot figure out for the life of me how to take care of unsigned char arrays and bitwise operations in this specific instance of code.
Specifically, I'm working on converting the following Objective-C code (which deals with CoreBluetooth) to Swift:
unsigned char advertisementBytes[21] = {0};
[self.proximityUUID getUUIDBytes:(unsigned char *)&advertisementBytes];
advertisementBytes[16] = (unsigned char)(self.major >> 8);
advertisementBytes[17] = (unsigned char)(self.major & 255);
I've tried the following in Swift:
var advertisementBytes: CMutablePointer<CUnsignedChar>
self.proximityUUID.getUUIDBytes(advertisementBytes)
advertisementBytes[16] = (CUnsignedChar)(self.major >> 8)
The problems I'm running into are that getUUIDBytes in Swift seems to only take a CMutablePointer<CUnsignedChar> object as an argument, rather than an array of CUnsignedChars, so I have no idea how to do the later bitwise operations on advertisementBytes, as it seems it would need to be an unsignedChar array to do so.
Additionally, CMutablePointer<CUnsignedChar[21]> throws an error saying that fixed length arrays are not supported in CMutablePointers in Swift.
Could anyone please advise on potential work-arounds or solutions? Many thanks.
Have a look at Interacting with C APIs
Mostly this
C Mutable Pointers
When a function is declared as taking a CMutablePointer
argument, it can accept any of the following:
nil, which is passed as a null pointer
A CMutablePointer value
An in-out expression whose operand is a stored lvalue of type Type,
which is passed as the address of the lvalue
An in-out Type[] value,
which is passed as a pointer to the start of the array, and
lifetime-extended for the duration of the call
If you have declared a
function like this one:
SWIFT
func takesAMutablePointer(x: CMutablePointer<Float>) { /*...*/ } You
can call it in any of the following ways:
SWIFT
var x: Float = 0.0
var p: CMutablePointer<Float> = nil
var a: Float[] = [1.0, 2.0, 3.0]
takesAMutablePointer(nil)
takesAMutablePointer(p)
takesAMutablePointer(&x)
takesAMutablePointer(&a)
So you code becomes
var advertisementBytes = CUnsignedChar[]()
self.proximityUUID.getUUIDBytes(&advertisementBytes)
advertisementBytes[16] = CUnsignedChar(self.major >> 8)