将CFArrayRef强制转换为NSArray时崩溃

时间:2011-11-10 23:01:49

标签: objective-c xcode cocoa quartz-graphics

这很好:

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

这会导致EXC_BAD_ACCESS:

CFArrayRef windowIDList = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
NSLog(@"Array %@", (__bridge NSArray*) windowIDList);

2 个答案:

答案 0 :(得分:8)

创建为NSArray的数组只能包含与Objective-C对象相似的元素。

如果您将相应的CFArray传递给CFArrayCallBacks,则CFArrayCreate创建的数组可以包含任何内容。

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>
)}

答案 1 :(得分:1)

来自NSArray上的documentation

  

NSArray与其核心基金会对应的“免费桥接”,   CFArray参考。这意味着Core Foundation类型是什么   可以在函数或方法调用中与bridged互换   基础对象,提供将一种类型转换为另一种类型。   因此,在您看到NSArray *参数的API中,您可以   传入CFArrayRef,并在API中看到CFArrayRef   参数,您可以传入NSArray实例。这种安排也   适用于NSArray的具体子类。

所以问题必须是调用两个方法。同样,从文档中,CGWindowListCopyWindowInfo具有返回值:

  

CFDictionaryRef类型的数组,每个类型都包含信息   关于当前用户会话中的一个窗口。如果没有   窗口匹配所需的标准,该函数返回一个空   阵列。如果从GUI安全性之外调用此函数   会话或没有窗口服务器正在运行时,此函数返回   NULL。

CGWindowListCreate有返回值:

  

与所需窗口对应的CGWindowID值数组。如果   没有符合所需标准的窗口,该功能   返回一个空数组。如果你从a外面调用这个函数   GUI安全会话或没有窗口服务器运行时,这个   函数返回NULL。

当您致电NSLog(@"%@",array);时,消息description将发送到阵列中的每个对象。 Floats,BOOL和int不响应此消息。例如,您将收到

的错误
NSLog(@"Printing 2: %@",2);

但如果您使用int电话,则错误会消失:

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

对于您的情况,CGWindowListCreate返回CGWindowID个值的数组,这些是32位无符号整数。因此,他们不回复%@,但会回复%u。因此,修复方法是使用%u手动打印数组。