这很好:
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
NSLog(@"%@", (__bridge NSArray *)windowList);
这导致EXC_BAD_ACCESS:
CFArrayRef windowIDList = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
NSLog(@"Array %@", (__bridge NSArray*) windowIDList);
创建为NSArray
的数组只能包含类似Objective-C对象的元素。
如果将适当的CFArrayCallBacks
传递给CFArrayCreate
,则创建为CFArray
的数组可以包含任何内容。
CGWindowListCreate
正在创建一个CFArray
,并用行为不像对象的东西填充它,但CGWindowListCreate
使用的是不关心这一点的CFArrayCallbacks
。
当您尝试使用%@
格式说明符打印此CFArray
时,NSLog
会向数组发送一条Objective-C -description
消息。CFArray
通过向其每个元素发送Objective-C description
消息来处理此问题。不幸的是,它的元素不是对象,因此不可能向它们发送Objective-C消息。因此崩溃。
试试这个:
CFStringRef description = CFCopyDescription(windowIDList);
NSLog(@"Array %@", description);
CFRelease(description);
CFCopyDescription
函数在数组的每个元素上使用一个CFArrayCallbacks
函数,而不是试图向每个元素发送Objective-C消息。回调知道如何处理数组元素,所以它工作得很好。我在测试程序中得到这个输出:
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>
)}
来自NSArray
:上的文档
NSArray与核心基金会的同行"免费桥接",CFArray参考。这意味着核心基础类型在函数或方法调用中与桥接Foundation对象,从而将一种类型强制转换为另一种类型。因此,在API中,当您看到NSArray*参数时,您可以传入一个CFArrayRef,并传入一个API,在那里您可以看到一个CFArray参数,可以传入NSArray实例。这种安排应用于NSArray的具体子类。
所以问题一定出在被调用的两个方法上。同样,从文档中,CGWindowListCopyWindowInfo
具有返回值:
CFDictionaryRef类型的数组,每个类型都包含信息关于当前用户会话中的一个窗口。如果没有与所需条件匹配的窗口,函数返回一个空大堆如果您从GUI安全性之外调用此函数会话或没有运行windows服务器时,此函数返回NULL。
并且CCD_ 19具有返回值:
与所需窗口相对应的CGWindowID值的数组。如果没有符合所需条件的窗口,函数返回一个空数组。如果从外部调用此函数GUI安全会话,或者当没有窗口服务器运行时函数返回NULL。
当您调用NSLog(@"%@",array);
时,消息description
会发送到数组中的每个对象。Floats、BOOL和int不会对此消息作出响应。例如,会出现错误
NSLog(@"Printing 2: %@",2);
但是如果您使用int
调用,错误就会消失
NSLog(@"Printing 2: %d",2);
对于您的情况,CGWindowListCreate
返回一个CGWindowID
值的数组,这些值是32位无符号整数。因此,它们不响应%@
,但将响应%u
。因此,解决方法是使用%u
手动打印阵列。