7

Mam projekt ObjectiveC++. W kontekście ObjectiveC używam ARC i iPhoneSDK 6. W C++ używam kompilatora C++ 11.Używanie funkcji lambda C++ 11 w ARC ObjectiveC++ - jak zrobić to poprawnie?

Funkcje Lambda w C++ 11 przechwytują zmienne z odniesieniami. Ta koncepcja nie jest tak naprawdę wspierana przez ObjectiveC, a przez "try and error" wymyśliłem następujące rozwiązanie. Czy są jakieś pułapki, o których nie wiem?

Czy istnieje lepsze rozwiązanie tego problemu?

typedef std::function<void()> MyLambdaType; 

... 
// m_myView will not go away. ARC managed. 
UIView * __strong m_myView; 

... 
// In Objective C context I create a lambda function that calls my Objective C object 
UIView &myViewReference = *m_myView; 
MyLambdaType myLambda = [&myViewReference]() { 
    UIView *myViewBlockScope = &myViewReference; 
    // Do something with `myViewBlockScope` 
} 

.. 
// In C++11 context I call this lambda function 
myLambda(); 
+0

Dlaczego nie użyć bloku? – kennytm

+0

Bloki AFAIK to tylko ObjectiveC, lub? Jak przekazać blok do C++? –

+0

Czy 'MyLambdaType myLambda = [m_myView]() {// Czy coś z m_myView}' nie działa? – newacct

Odpowiedz

12

Prosta rzecz do zrobienia byłoby pozwolić przechwytywania lambda zmienna obiekt wskaźnik m_myView (jestem zakładając ze swoim fragmencie, że jest to zmienna lokalna) i używać go normalnie wewnątrz lambda:

MyLambdaType myLambda = [m_myView]() { 
    // Do something with `m_myView` 
} 

Jedynym problemem związanym z zarządzaniem pamięcią jest m_myView. Aby być ogólnie poprawnym, lambda musi zachować m_myView kiedy jest tworzona i zwolnić ją, gdy zostanie zniszczona (podobnie jak bloki, ponieważ lambda może być używana w zakresie, w którym m_myView nie istnieje).

Czytając dokumentację ARC, nie widzę konkretnie tej sytuacji, ale uważam, że powinna ona obsłużyć to poprawnie, ponieważ (1) przechwycone zmienne lambda C++ 11 są przechowywane jako pola anonimowe class, które są inicjowane do przechwyconej wartości, gdy konstrukcja lambda jest skonstruowana, oraz (2) ARC poprawnie obsługuje zatrzymywanie i zwalnianie pól Objective-C obiektów klasy C++ podczas konstruowania i niszczenia. O ile nie mówi się konkretnie o lambdach, które są przeciwne, albo jest błąd kompilatora, nie widzę powodu, dla którego nie powinien on działać.

+4

To zdecydowanie działa. Trudne jest to, że w terminologii lambda C++ 11, 'm_myView' jest przechwytywany" według wartości "tutaj. Jeśli przechwycisz go "przez odniesienie" (tak: '[& m_myView]() {...}') obiekt 'm_myView' jest * NIE * zachowywany przez ARC. Jeśli myślisz o tym, ma to sens (np. Kiedy mówisz C++, aby przechwytywał 'm_myView' przez referencję, C++ przechwytuje referencję * do wskaźnika *, a nie odwołanie do obiektu), ale terminologia może być nieco myląca . – ipmcc

+0

@ipmcc: Tak. Dotyczy to przechwytywania przez odniesienie w C++ 11 lambdas w ogóle. Jeśli przechwytujesz przez odniesienie w C++ 11 lambda, nie możesz użyć tej lambda poza zakresem przechwyconych zmiennych. – newacct

+0

Wygląda na to, że pamięć używana przez m_myView nie jest zwalniana przez ARC. Otrzymuję wiele wywołań zwrotnych co kilka milisekund w moim kodzie i moja pamięć stale się przeskakuje. To samo dotyczy obiektów Objective-C utworzonych w funkcji lambda. One też przeciekają. –

Powiązane problemy