Ios 集合元素的桥强制转换

Ios 集合元素的桥强制转换,ios,objective-c,Ios,Objective C,我使用的是一个供应商API,它返回一个CFDictionaryRef,可以包含多种CF对象类型,调用方需要将其发布。我想将它转换成一个NSDictionary,以便更轻松地使用它,并希望确保我理解我在转换方面正确地处理了元素 在我看来,免费桥接类型(例如,CFString、CFNumber)只是由NSDictionary处理的,我可以像一直使用Obj-C类型一样获得NS类型(我猜有一个桥接正在进行) 对于非免费桥接类型(例如CFHost),看起来我可以将-valueForKey:的结果桥接到CF

我使用的是一个供应商API,它返回一个CFDictionaryRef,可以包含多种CF对象类型,调用方需要将其发布。我想将它转换成一个NSDictionary,以便更轻松地使用它,并希望确保我理解我在转换方面正确地处理了元素

在我看来,免费桥接类型(例如,CFString、CFNumber)只是由NSDictionary处理的,我可以像一直使用Obj-C类型一样获得NS类型(我猜有一个桥接正在进行)

对于非免费桥接类型(例如CFHost),看起来我可以将-valueForKey:的结果桥接到CF类型中并从那里开始,尽管我不确定是否需要释放该值

下面是一些示例代码,说明了这个问题。这是处理事情的正确方法吗

// Caller is responsible for releasing returned value
//
+ (CFDictionaryRef)someCFCreateFunctionFromVendor
{
    CFMutableDictionaryRef cfdict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(cfdict, CFSTR("string1"), CFSTR("value"));
    int i = 42;
    CFDictionarySetValue(cfdict, CFSTR("int1"), CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &i));

    CFHostRef host = CFHostCreateWithName(kCFAllocatorDefault, CFSTR("myhost"));
    CFDictionarySetValue(cfdict, CFSTR("host1"), host);
    return cfdict;
}

+ (void)myMethod
{
    NSDictionary *dict = CFBridgingRelease([self someCFCreateFunctionFromVendor]);
    for (NSString *key in [dict allKeys]) {
        id value = [dict valueForKey:key];
        NSLog(@"%@ class: %@", key, [value class]);

        if ([value isKindOfClass:[NSString class]]) {
            NSString *str = (NSString *)value;
            NSLog(@"%@ is an NSString with value %@", key, str);
        } else if ([value isKindOfClass:[NSNumber class]]) {
            NSNumber *num = (NSNumber *)value;
            NSLog(@"%@ is an NSNumber with value %@", key, num);
        } else if ([value isKindOfClass:[NSHost class]]) {
            NSLog(@"%@ is an NSHost", key); // never hit because no toll-free bridge to NSHost
        } else {
            NSLog(@"%@ is an unexpected class", key);
        }

        // Sample handling of non-toll-free bridged type
        if ([key isEqualToString:@"host1"]) {
            CFHostRef host = (__bridge CFHostRef)value;
            NSArray *names = (__bridge NSArray *)(CFHostGetNames(host, false));
            NSLog(@"host1 names: %@", names);
            // I don't think I need to CFRelease(host) because ARC is still handling value
        }
    }
}
输出

string1 class: __NSCFConstantString
string1 is an NSString with value strvalue 
int1 class: __NSCFNumber
int1 is an NSNumber with value 42
host1 class: __NSCFType
host1 is an unexpected class
host1 names: ( myhost )

讽刺的是,你的代码中唯一的错误是在核心基础上,非弧的东西。您的
+someCFCreateFunctionFromVendor
方法调用
CFNumberCreate()
CFHostCreateWithName()
,这两个函数都是创建函数,但在将对象添加到字典后不会调用对象。应该这样。否则,这就是一个漏洞。顺便说一下,静态分析器会捕捉到这一点。(对于
CFNumber
,这意味着您必须将创建内容拆分为单独的一行,以便在将对象添加到字典后可以引用该对象。)


您不能在
+myMethod
中释放宿主对象,因为该代码没有获得它的所有权。这与电弧无关。你不会在MRR(手动保留/释放)代码中发布它。

好的catch,以及一个完美的例子,说明为什么我要打包我们在基础类中使用的API的一部分,这样团队中的其他人就不需要处理CFType。谢谢