How to convert Swift array into CFArray? - objective-c

I'm trying to capture a window list in a Mac OS X app using Swift. The CGWindowListCreateImageFromArray function requires a CFArray. I've tried several things and this is the closest I've got. Or is there a better way to convert the array?
import Cocoa
// Example swift array of CGWindowID's
var windowIDs = [CGWindowID]();
windowIDs.append(1);
windowIDs.append(2);
// Convert to CFArray using CFArrayCreate
let allocator = kCFAllocatorDefault
let numValues = windowIDs.count as CFIndex
let callbacks: UnsafePointer<CFArrayCallBacks> = nil
var values: UnsafeMutablePointer<UnsafePointer<Void>> = nil
/* how do I convert windowIDs to UnsafeMutablePointer<UnsafePointer<Void>> for the values? */
let windowIDsCFArray = CFArrayCreate(allocator, values, numValues, callbacks);
let capture = CGWindowListCreateImageFromArray(CGRectInfinite, windowIDsCFArray, CGWindowImageOption(kCGWindowListOptionOnScreenOnly));

You can initialize your UnsafeMutablePointer with your array so long as you set your CGWindowIDs to CFTypeRef:
var windows: [CFTypeRef] = [1, 2]
var windowsPointer = UnsafeMutablePointer<UnsafePointer<Void>>(windows)
var cfArray = CFArrayCreate(nil, windowsPointer, windows.count, nil)

Converted Ian's answer to Swift 4:
let windows = [CGWindowID(17), CGWindowID(50), CGWindowID(59)]
let pointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: windows.count)
for (index, window) in windows.enumerated() {
pointer[index] = UnsafeRawPointer(bitPattern: UInt(window))
}
let array: CFArray = CFArrayCreate(kCFAllocatorDefault, pointer, windows.count, nil)
let capture = CGImage(windowListFromArrayScreenBounds: CGRect.infinite, windowArray: array, imageOption: [])!
let image: NSImage = NSImage(cgImage: capture, size: NSSize.zero)
Swift.print(image)

Arrays in Swift are bridged to NSArray, given they contain objects, e.g., conform to [AnyObject] type. Since CGWindowID is a UInt32, you need to convert it to NS family, array's map() method is an elegant approach.
var windows: [CGWindowID] = [CGWindowID(1), CGWindowID(2)]
var array: CFArray = windows.map({NSNumber(unsignedInt: $0)}) as CFArray
This, however, doesn't reflect on the actual CGWindowListCreateImageFromArray problem. Here's the working solution for that:
let windows: [CGWindowID] = [CGWindowID(17), CGWindowID(50), CGWindowID(59)]
let pointer: UnsafeMutablePointer<UnsafePointer<Void>> = UnsafeMutablePointer<UnsafePointer<Void>>.alloc(windows.count)
for var i: Int = 0, n = windows.count; i < n; i++ {
pointer[i] = UnsafePointer<Void>(bitPattern: UInt(windows[i]))
}
let array: CFArray = CFArrayCreate(kCFAllocatorDefault, pointer, windows.count, nil)
let capture: CGImage = CGWindowListCreateImageFromArray(CGRectInfinite, array, CGWindowImageOption.Default)!
let image: NSImage = NSImage(CGImage: capture, size: NSZeroSize)
Swift.print(image) // <NSImage 0x7f83a3d16920 Size={1440, 900} Reps=("<NSCGImageSnapshotRep:0x7f83a3d2dea0 cgImage=<CGImage 0x7f83a3d16840>>")>
I'm not great at ObjC, please correct if wrong, but from what I understand by playing with the SonOfGrab example and particular piece of code below is that the final pointer structure contains window ids (UInt32) not inside the memory cell (memory property of UnsafePointer instance), but inside memory address (hashValue property).
const void *windowIDs[2];
windowIDs[0] = 10;
windowIDs[1] = 20;
It's interesting, since values aren't stored in the memory, but inside the address descriptors, with oldest architectures being 32-bit UInt32 values fit perfectly into address pointers. Perhaps back in the days when the memory was a limiting factor this made a lot of sense and was a great approach. Discovering this all night in Swift in 2016 made me suicidal.
What's worse it fails in Xcode 7.2 playground with certain window ids, probably because of the way it handles memory, but works in the actual app.

Related

Three different ways to instantiate Arrays in AssemblyScript

I'm writing a smart contract and want to use Arrays to manipulate data, but looking at the AssemblyScript docs, I'm not sure the best way to proceed.
It seems fine to me to just use:
let testData:string[] = []
but when I consulted the assemblyscript docs, there are three recommended ways to create an Array:
// The Array constructor implicitly sets `.length = 10`, leading to an array of
// ten times `null` not matching the value type `string`. So, this will error:
var arr = new Array<string>(10);
// arr.length == 10 -> ERROR
// To account for this, the .create method has been introduced that initializes
// the backing capacity normally but leaves `.length = 0`. So, this will work:
var arr = Array.create<string>(10);
// arr.length == 0 -> OK
// When pushing to the latter array or subsequently inserting elements into it,
// .length will automatically grow just like one would expect, with the backing
// buffer already properly sized (no resize will occur). So, this is fine:
for (let i = 0; i < 10; ++i) arr[i] = "notnull";
// arr.length == 10 -> OK
When would I want to use one type of instantiation over another? Why wouldn't I just always use the version I presented in the beginning?
Nothing wrong with the array literal approach. It is basically equivalent to
let testData = new Array<string>();
However, sometimes you know what the length of the array should be and in such cases, preallocating the memory using Array.create is more efficient.
UPDATE
With this PR Array.create deprecated and should not be used anymore.
OLD ANSWER
let testData:string[] = []
semantically the same as
let testData = new Array<string>()
AssemblyScript doesn't support preallocated sparse arrays (arrays with holes) for reference elements which not explicitly declared as nullable like:
let data = new Array<string>(10);
data[9] = 1; // will be compile error
Instead you could use:
let data = new Array<string | null>(10);
assert(data.length == 10); // ok
assert(data[0] === null); // ok
or Array.create but in this case your length will be zero. Array.create is actually just reserve capacity for backing buffer.
let data = Array.create<string>(10);
assert(data.length == 0); // true
For plain (non-reference) types you could use usual way without care about nullabe or creating array via Array.create:
let data = new Array<i32>(10);
assert(data.length == 10); // ok
assert(data[0] == 0); // ok

Getting UnsafeBufferPointer from ObjC

In my ObjC-Swift bridging I currently use
- (double*)vector {
return (double*)self.ndArray->vector();
}
- (long) size {
return self.ndArray->size();
}
to create an array in Swift like
let p = vector.vector()
let s = vector.size()
let a = Array<Double>(UnsafeBufferPointer(start: p, count: s))
Would it be possible to get this directly from ObjC like
let a = Array<Double>(vector.readyPackedPointer())
?
A C pointer does not contain any information about the size of the pointed-to memory region, so you'll always have to pass both pointer and count
from (Objective-)C to Swift. You could pass a struct containing both
pointer and count to save a function call.

Accessing a pointer in Swift/Obj-c to Swift Conversion with pointers

Im trying to do the following in Swift:
CFArrayRef attachmentsArray = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, 0);
if (CFArrayGetCount(attachmentsArray)) {
CFBooleanRef notSync;
CFDictionaryRef dict = CFArrayGetValueAtIndex(attachmentsArray, 0);
BOOL keyExists = CFDictionaryGetValueIfPresent(dict,
kCMSampleAttachmentKey_NotSync,
(const void **)&notSync);
I have:
if CFArrayGetCount(attachmentsArray) != 0 {
let dict = CFArrayGetValueAtIndex(attachmentsArray, 0)
However, dict is a UnsafePointer instead of a dictionary like it should be. When I printed attachmentsArray I got
Optional({ DependsOnOthers = 0; })
I tried casting it to a CFDictionaryRef but it would fail in runtime.
How do I succeed in doing the above Obj-C code in Swift?
However, dict is a UnsafePointer instead of a dictionary like it should be.
No, not "like it should be". Look at the declaration:
func CFArrayGetValueAtIndex(theArray: CFArray!, _ idx: CFIndex)
-> UnsafePointer<Void>
It returns an UnsafePointer-to-void because that is what it is supposed to do. (In Objective-C it returns a const void *.)

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)

How to return a C-array from method in Objective-C?

I have a function that returns a variable and I want to know how to return an array the issue is it isn't an NSArray it is just an average C array like this...
-(b2Fixture*) addFixturesToBody:(b2Body*)body forShapeName:(NSString*)shape
{
BodyDef *so = [shapeObjects objectForKey:shape];
assert(so);
FixtureDef *fix = so->fixtures;
int count = -1;
b2Fixture *Fixi[4];
while(fix)
{
count++;
NSLog(#"count = %d",count);
Fixi[count]= body->CreateFixture(&fix->fixture);
if (Fixi[count]!=0) {
NSLog(#"Fixi %d is not 0",count);
}
if (body->CreateFixture(&fix->fixture)!=0) {
NSLog(#"body %d is not 0",count);
}
fix = fix->next;
}
return *Fixi;
}
If you see some variable types you don't know it's because I'm using cocos2d framework to make a game but I'm returning a variable of b2Fixture... This code compiles however only saves the value of the first block of the array "fixi[0]" not the whole array like I want to pass
anyhelp :) thankyou
You can't return a local array. You'll need to do some kind of dynamic allocation or pull a trick like having the array inside a structure.
Here is a link to an in-depth article that should help you out.
In general returning C arrays by value is a bad idea, as arrays can be very large. Objective-C arrays are by-reference types - they are dynamically allocated and a reference, which is small, is what is passed around. You can dynamically allocate C arrays as well, using one of the malloc family for allocation and free for deallocation.
You can pass C structures around by value, and this is common, as in general structures tend to be small (or smallish anyway).
Now in your case you are using a small array, it has just 4 elements. If you consider passing these 4 values around by value is reasonable and a good fit for your design then you can do so simply by embedding the C array in a C structure:
typedef struct
{
b2Fixture *elements[4];
} b2FixtureArray;
...
-(b2FixtureArray) addFixturesToBody:(b2Body*)body forShapeName:(NSString*)shape
{
BodyDef *so = [shapeObjects objectForKey:shape];
assert(so);
FixtureDef *fix = so->fixtures;
int count = -1;
b2FixtureArray Fixi;
while(fix)
{
count++;
NSLog(#"count = %d", count);
Fixi.elements[count]= body->CreateFixture(&fix->fixture);
if (Fixi.elements[count] != 0)
{
NSLog(#"Fixi %d is not 0",count);
}
if (body->CreateFixture(&fix->fixture) != 0)
{
NSLog(#"body %d is not 0", count);
}
fix = fix->next;
}
return Fixi;
}
...
// sample call outline
b2FixtureArray result = [self addFixturesToBody...]
Whether this standard C "trick" for passing arrays by value is appropriate for your case you'll have to decide.
Note: If b2fixture is an Objective-C object make sure you understand the memory management implications of having a C array of objects references depending on the memory management model (MRC, ARC, GC) you are using.
If you need to design function or method that has to return a fixed or limited size array, one possibility is to pass a pointer to the result array to the function or method as a parameter. Then the caller can take care of allocating space, or just use a local or instance variable array. You might want the called function to sanity check that the array parameter isn't NULL before using the array.