1

私が現在書いているコードの動作に何か奇妙な点があることに気付き、これが起こる原因となるばかげたことをしていないかどうかを確認するためにここに質問すると思いました。

基本的に、変数をクラス メソッドの戻り値に割り当てると、戻り値への参照を保持する変数ではなく、クラスへの参照が保持されます。以下のコードを参照してください。

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

のメソッド署名を持っている

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

そして戻る

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

ご覧のとおり、いくつかのネットワーク インターフェイスの IP アドレスのリストを収集しているため、無料のブリッジングを使用して CoreFoundation オブジェクトを使用しています。

newAddressesが割り当てられた後newAddresses、LLDB で配列のクラスを確認すると、次のようになります。

(lldb) po [newAddresses クラス]
MyHost

をどのように使用しているかについての私の仮定が間違ってい__bridge_transferますか? 構成するために使用するすべてのオブジェクトipAddressesCFStringRefsです。

編集:メソッド全体を求められたので、ここにあります!

+ (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だから私は解決策を見つけました。それは、何かが起こる前に初期化するのを忘れていることにあります。このコードの書き方では、指定された to を解決できない場合、値を に割り当てませipAddressesん。に値がない場合、キャストされて所有権が転送される初期化されていないポインターを返します。hostRefCFHostStartInfoResolutionipAddresses

これを述べている正式なドキュメントは見つかりませんが、これは未定義の動作になると思います。

誰かがこのコードを参照として使用している場合、リリースした行で一貫性のないクラッシュが発生していることを述べておく必要がありhostRefます。これは、私がこのスレッドのために作成した問題とは関係ありませんが、指摘する価値はあります。

于 2015-06-16T17:35:34.140 に答える