Crash on starting CFArrayRef in NSArray

This is normal:

CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID); NSLog(@"%@", (__bridge NSArray *)windowList); 

This calls EXC_BAD_ACCESS:

 CFArrayRef windowIDList = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID); NSLog(@"Array %@", (__bridge NSArray*) windowIDList); 
+6
source share
2 answers

Arrays created as NSArray can only contain elements that act as Objective-C objects.

Arrays created as CFArray can contain anything if you pass the corresponding CFArrayCallBacks to CFArrayCreate .

CGWindowListCreate creates a CFArray and populates it with things that don't act as objects, but CGWindowListCreate uses CFArrayCallBacks , which doesn't care about that.

When trying to print this CFArray using the %@ format specifier, NSLog sends an Objective-C -description message to the array. CFArray handles this by sending an Objective-C description message to each of its elements. Unfortunately, its elements are not objects, and therefore it is not possible to send them Objective-C messages. So the accident.

Try this instead:

 CFStringRef description = CFCopyDescription(windowIDList); NSLog(@"Array %@", description); CFRelease(description); 

The CFCopyDescription function uses one of the CFArrayCallBacks functions for each element of the array instead of trying to send an Objective-C message to each of them. The callback knows how to handle an array element, so it works great. I get this output in my test program:

 2011-11-10 18:50:23.888 test[15156:707] <CFArray 0x1001140c0 [0x7fff7fd24ea0]>{type = mutable-small, count = 19, values = ( 0 : <0x7d7> 1 : <0x2d> 2 : <0x20> 3 : <0x21> 4 : <0x1e> 5 : <0x9> 6 : <0x7a8> 7 : <0x2c> 8 : <0x2e> 9 : <0x743> 10 : <0x32> 11 : <0x85> 12 : <0x695> 13 : <0x62a> 14 : <0x62b> 15 : <0xa> 16 : <0x26> 17 : <0x18> 18 : <0x2> )} 
+8
source

From the documentation in NSArray :

NSArray is a "free bridge" with its partner Core Foundation, CFArray Handbook. This means that a Core Foundation type is an interchangeable function or method call with a bridge Foundation object that transfers one type to another. Therefore, in the API where you see the NSArray * parameter, you can pass in CFArrayRef and in the API where you see the CFArrayRef parameter, you can pass an instance of NSArray. This arrangement also applies to your specific NSArray subclasses.

So the problem should be calling two methods. Again, from the documentation, CGWindowListCopyWindowInfo has a return value:

An array of CFDictionaryRef types, each of which contains information about one of the windows of the current user session. If there is no window matching the specified criteria, the function returns an empty array. If you call this function from outside the GUI session or when the window server is not running, this function returns NULL.

and CGWindowListCreate has a return value:

An array of CGWindowID values โ€‹โ€‹corresponding to the desired windows. If there are no windows matching the desired criteria, the function returns an empty array. If you call this function from outside the GUI Security Session or when the window server is not running, this function returns NULL.

When you call NSLog(@"%@",array); , a description message is sent to each object in the array. Floats, BOOLs, and ints do not respond to this message. For example, you will receive an error message

 NSLog(@"Printing 2: %@",2); 

but the error will disappear if you use the int call:

 NSLog(@"Printing 2: %d",2); 

In your case, CGWindowListCreate returns an array of CGWindowID values, and these are 32-bit unsigned integers. Therefore, they will not respond to %@ , but will respond to %u . Therefore, the fix is โ€‹โ€‹to print the array manually using %u .

+1
source

Source: https://habr.com/ru/post/901258/


All Articles