2016-12-29 2 views
1

У меня есть какое-то событие из C++ письменной библиотеки, которая работает в фоновом потоке:Почему-то переменный становятся NULL в блоке

virtual void OnData(const char* data) 
{ 
    NSLog(@"Here 'data' string is present %s", data); 
    @autoreleasepool { 
     NSString* sData= [NSString stringWithCString:data encoding:NSUTF8StringEncoding]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      NSLog(@"Here _sometimes_ 'data'(%s) is nil (\0). But sData is always present %@", data, sData); 
      [callback OnData:sData]; 
     }); 
    }; 
} 

И иногда у меня есть NULL (я подозреваю, что его мусор на самом деле) в dispatch_async блока в аргументе переменная. Но локальная переменная NSString всегда здесь. Зачем?

P.S. Должен ли я использовать @autoreleasepool в этой ситуации?

+2

Это не C++. – Barmar

+0

Objective-C смешанный с C++ – BugaBuga

ответ

3

У вас нет гарантий относительно срока службы буфера, на который указывал const char *data, к тому моменту, когда выполняется асинхронный блок. data может обмануть указатель этой точкой (и ее следует считать таким). Очень опасно использовать указатели стиля С в любых асинхронных ссылках или вне контекста, который они изначально были созданы.

Вы должны либо использовать управляемые объекты памяти (например, NSData, NSString и т.д.), или, если вы настаиваете на использовании указателей C-стиля и нужно ссылаться на этот указатель в асинхронном блоке, копировать данные в свой собственный буфер, используйте этот буфер, а затем освободите его, когда вы закончите использовать этот буфер в своей асинхронной процедуре. В этом случае у вас есть sData, так что просто не обращайтесь к data после этого момента, и все будет в порядке.


P.S. Позднее вы спросите, следует ли вам использовать @autoreleasepool в этой ситуации.

Короче говоря, в большинстве случаев дополнительный пул авторефератов не требуется. Примечательно, что при использовании Grand Central Dispatch (например, dispatch_async) у него есть собственные пулы автоопределений, поэтому вам не нужно их создавать. И когда ваш основной поток вернется к циклу запуска, опять же, это пул сливается. Короче говоря, вам нужны только созданные вручную пулы автозапуска при создании собственных объектов NSThread.

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

1

Если у вас что-то вроде этого:

void CallOnData() 
{ 
    char *test = malloc(5 * sizeof(char)); 
    strcpy(test, "test"); 
    OnData(test); 
    free(test); 
} 

Вы должны ожидать, чтобы данные были «NULL» в блоке.

И автореферат не требуется, если вы используете ARC, которым вы должны быть.

+0

Почему 'autoreleasepool' не нужен? Его вызвали из нового потока, созданного без 'autoreleasepool'. – BugaBuga

+1

Этот ответ проливает свет на NSThread и autoreleasepool для OSX 10.9, iOS 7 и новее. http://stackoverflow.com/a/30519746/16524 – Fostah