1

Я заметил что-то странное в поведении кода, который я сейчас пишу, и думал, что я попрошу здесь посмотреть, не делаю ли я что-то глупое, что могло бы вызвать это произойдет.Присвоение из метода класса связывает класс вместо его возвращаемого значения

В принципе, когда я назначаю переменную возвращаемому значению моего метода класса, вместо переменной, содержащей ссылку на возвращаемое значение, она содержит ссылку на класс. Смотрите код ниже:

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

который имеет метод подпись

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

И возвращает

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

Как вы можете видеть, я использую бесплатные мостики использовать CoreFoundation объекты, поскольку я собираю список IP-адресов для некоторых сетевых интерфейсов.

После newAddresses был назначен, я смотрю на класс newAddresses массива в LLDB и получите:

(lldb) Ро [newAddresses класс]
MyHost

Am I ошибаюсь в моих предположениях о том, как я использую __bridge_transfer? Все используемые объекты составляют ipAddresses: CFStringRefs.

EDIT: Меня попросили использовать весь метод, так что вот оно!

+ (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; 
} 
+1

Можете ли вы показать декларацию 'ipAddresses' внутри метода или еще лучше, опубликовать весь этот метод? Похоже, что это не массив (CFMutableArrayRef). Возможно, это где-то случайно переназначается. –

+0

Хорошая идея Бен. Я пошел вперед и сделал это. Вы увидите, что я не переназначаю 'ipAddresses' после того, как я его создаю, я просто мутирую его с помощью' CFArrayInsertValueAtIndex'. Когда я смотрю на массив на обратной линии в 'addressForHostname', он выглядит правильно. Это заставляет меня думать, что «__bridge_transfer» является виновником, но я не слишком опытен с помощью бесплатного моста. –

ответ

0

Таким образом, я нашел решение, и оно лежит в меня забыть инициализировать ipAddresses = nil, прежде чем что-нибудь случится. Способ записи этого кода не будет присваивать значение ipAddresses, если он не может разрешить hostRef, указанный CFHostStartInfoResolution. Без значения в ipAddresses он возвращает неинициализированный указатель, который получает литье и передается в собственность.

Я не могу найти официальную документацию, в которой говорится об этом, но я считаю, что это было бы неопределенным поведением.

Я должен указать, что если кто-то использует этот код в качестве ссылки, я испытываю несогласованные сбои на линии, где я освобождаю hostRef. Это не связано с проблемой, которую я создал для этого потока, но стоит отметить.

Смежные вопросы