将CFArrayRef强制转换为NSArray时崩溃



这很好:

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手动打印阵列。

最新更新