1

我注意到我目前正在编写的代码的行为有些奇怪,我想我会在这里询问我是否正在做一些会导致这种情况发生的愚蠢的事情。

基本上,当我将一个变量分配给我的类方法的返回值时,它不是持有对返回值的引用的变量,而是持有对类的引用。请看下面的代码:

NSArray * newAddresses = [MyHost addressesForHostname: @"google.com"];

其中有一个方法签名

+ (NSArray *) addressesForHostname: (NSString *)hostname

并返回

return (__bridge_transfer NSArray *) ipAddresses; // ipAddresses is a CFMutableArrayRef

如您所见,我正在使用免费桥接来使用 CoreFoundation 对象,因为我正在收集一些网络接口的 IP 地址列表。

分配到之后newAddresses,我查看newAddressesLLDB 中数组的类并得到:

(lldb) po [newAddresses 类]
MyHost

我对我如何使用的假设有误__bridge_transfer吗?所有用来组成的物体ipAddresses都是CFStringRefs

编辑:我被要求提供整个方法,所以就在这里!

+ (NSArray *) addressesForHostname: (NSString *)hostname {

    CFMutableArrayRef ipAddresses;

    DLog(@"Getting addresses for host name %@", hostname);

    CFHostRef hostRef = CFHostCreateWithName(kCFAllocatorDefault, (__bridge CFStringRef)(hostname));
    CFStreamError error;

    BOOL didResolve = CFHostStartInfoResolution(hostRef, kCFHostNames, &error); // synchronously get the host.

    if (didResolve) {

        CFArrayRef responseObjects = CFHostGetAddressing(hostRef, NULL);
        long numberOfResponses = CFArrayGetCount(responseObjects);
        ipAddresses = CFArrayCreateMutable(kCFAllocatorDefault, numberOfResponses, &kCFTypeArrayCallBacks);

        for ( int i = 0 ; i < numberOfResponses; ++i ) {

            char * ipAddress;
            CFDataRef responseObject = CFArrayGetValueAtIndex(responseObjects, i);
            struct sockaddr * currentAddress = (struct sockaddr *) CFDataGetBytePtr(responseObject); // Unwrap the CFData wrapper aound the sockaddr struct

            switch (currentAddress->sa_family) {

                case AF_INET: { // Internetworking AKA IPV4

                    DLog(@"Extracting IPV4 address");
                    struct sockaddr_in * socketAddress = (struct sockaddr_in *) currentAddress;

                    ipAddress = malloc(sizeof(INET_ADDRSTRLEN));
                    inet_ntop(AF_INET,
                              &(socketAddress->sin_addr),
                              ipAddress,
                              INET_ADDRSTRLEN);

                    CFStringRef ipAddressString = CFStringCreateWithCString(kCFAllocatorDefault, ipAddress, kCFStringEncodingASCII);
                    CFArrayInsertValueAtIndex(ipAddresses, i, ipAddressString);

                    free(ipAddress);
                    break;

                }

                case AF_INET6: { // IPV6

                    DLog(@"Extracting IPV6 address");
                    struct sockaddr_in6 * socketAddress = (struct sockaddr_in6 *) currentAddress;

                    ipAddress = malloc(sizeof(INET6_ADDRSTRLEN));
                    inet_ntop(AF_INET6,
                              &(socketAddress->sin6_addr),
                              ipAddress,
                              INET6_ADDRSTRLEN);

                    CFStringRef ipAddressString = CFStringCreateWithCString(kCFAllocatorDefault, ipAddress, kCFStringEncodingASCII);
                    CFArrayInsertValueAtIndex(ipAddresses, i, ipAddressString);

                    free(ipAddress);
                    break;
                }

                default:
                    DLog(@"Unsupported addressing protocol encountered. Gracefully ignoring and continuing.");
                    break;
            }


        }

        CFRelease(responseObjects);

    }

    CFRelease(hostRef);

    return (__bridge_transfer NSArray *) ipAddresses;
}
4

1 回答 1

0

所以我找到了解决方案,它在于我忘记ipAddresses = nil在任何事情发生之前进行初始化。这段代码的编写方式,ipAddresses如果无法解析hostRef给定的CFHostStartInfoResolution. 中没有值ipAddresses,它返回一个未初始化的指针,该指针被强制转换并转移其所有权。

我找不到说明这一点的正式文档,但我相信这将是未定义的行为。

我应该声明,如果有人使用此代码作为参考,我在 release 的行上遇到了不一致的崩溃hostRef。这与我为此线程创建的问题无关,但值得指出。

于 2015-06-16T17:35:34.140 回答