2013-02-13 10 views
27

Potrzebuję porady na temat __bridge -ing w iOS.Gdzie i jak __bridge

Mam nadzieję, że SSCCE poniżej wyjaśni problem lepiej niż ja w słowach, ale muszę wiedzieć, w jaki sposób mogę przekonwertować void* do NSMutableArray*; która powinna być zmieniona na __bridge (patrz komentarz w kodzie).

Czytając o różnych mostów, wywnioskowałem, że muszę __bridge_transfer ale potem otrzymać EXC_BAD_ACCESS na addObject:

Docelowo chciałbym mieć tablicę z CGPoints w CGPath po CGPathApply został nazwany .

#import <Foundation/Foundation.h> 

void _processPathElement(void* info, const CGPathElement* element) 
{ 
    NSMutableArray *array = (/* WHAT BRIDGE HERE */ NSMutableArray*) info; 
    switch (element->type) 
    { 
     case kCGPathElementMoveToPoint: 
     case kCGPathElementAddLineToPoint: 
     { 
      CGPoint point = element->points[0]; 
      [array addObject:[NSValue valueWithCGPoint:point]]; 
      break; 
     } 
     default: 
      break; 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    @autoreleasepool 
    { 
     //Create path 
     CGMutablePathRef path = CGPathCreateMutable(); 
     CGPathMoveToPoint( path, NULL, 0, 0); 
     CGPathAddLineToPoint(path, NULL, 1, 0); 
     CGPathAddLineToPoint(path, NULL, 1, 1); 
     CGPathAddLineToPoint(path, NULL, 0, 1); 
     CGPathCloseSubpath(path); 

     NSMutableArray *pathPoints = [NSMutableArray array]; 
     CGPathApply(path, &pathPoints, _processPathElement); 

     NSLog(@"Points:%@", pathPoints); 
    } 
} 

1: SSCCE

+0

nie rozumiem. Po prostu użyłem '__bridge' zgodnie z sugestią Xcode. Twój program się kompiluje. – esh

+3

Lub szukasz tego, '__bridge' przenosi wskaźnik pomiędzy Objective-C i Core Foundation bez przeniesienia własności. '__bridge_retained' lub' CFBridgingRetain' rzuca wskaźnik Objective-C na wskaźnik Core Foundation, a także przenosi na Ciebie własność. Jesteś odpowiedzialny za wywołanie CFRelease lub powiązanej funkcji w celu zrzeczenia się prawa własności do obiektu. '__bridge_transfer' lub' CFBridgingRelease' przesuwa wskaźnik nie-Objective-C do Objective-C, a także przenosi własność na ARC. ARC odpowiada za rezygnację z własności obiektu. – esh

+0

@ BlackFlam3 (1 komentarz) Nie jest to tylko przypadek pobrania kodu do kompilacji. Potrzebuję odpowiedniej pamięci, aby mieć dostęp do 'pathPoints' dla' NSLog' –

Odpowiedz

47

T on dokumentację na temat użycia słowa kluczowego mostu can be found here. W szczególności chcę podkreślić §3.2.4:

(__bridge T) op rzuca operand przeznaczenia typu T. Jeśli T jest wskaźnik Wygodne do przechowywania typ obiektu, a następnie op musi mieć non-Wygodne do przechowywania typ wskaźnika. Jeśli T jest typem wskaźnika, który nie może być zachowany, to op musi mieć typ wskaźnika obiektu, który można zachować. W przeciwnym razie obsada jest źle sformułowana. Nie ma przeniesienia własności, a ARC nie wstawia operacji zatrzymania.

(__bridge_retained T) op rzuca operand, który musi mieć typ wskaźnika obiektu do zatrzymania, do typu docelowego, który musi być typem wskaźnika, który nie może być zachowany. ARC zachowuje wartość, z zastrzeżeniem zwykłych optymalizacji lokalnych wartości, a odbiorca jest odpowiedzialny za zrównoważenie tego +1.

rzuca operand, który musi mieć typ wskaźnika, który nie może być zachowany, do typu miejsca docelowego, który musi być typem wskaźnika obiektu do retainowania. ARC zwolni wartość na końcu otaczającego wyrażenia pełnego, z zastrzeżeniem zwykłych optymalizacji lokalnych wartości.

Wskaźnik jesteś były przekazywane w (void*) jest non Wygodne do przechowywania typ wskaźnika, natomiast swoją NSMutableArray jest Wygodne do przechowywania typ wskaźnika. To od razu wyklucza __bridge_retained. Pytanie brzmi: __bridge lub __bridge_transfer?

__bridge_transfer jest zwykle używany, gdy chcesz wskaźnik Objective-C z metody, która zwraca obiekt CF, który został zachowany. Na przykład CFStringCreateWithFormat zwróci zatrzymane CFString, ale jeśli chcesz NSString z niego, musisz __bridge_transfer między nimi. To spowoduje, że ARC zwolni obiekt, który CF zachował w razie potrzeby. Na przykład: NSString* str = (__bridge_transfer NSString*) CFStringCreateWithFormat(...);

Twój kod nie robi tego, nie musisz mieszać się w prawach własności.Twoja główna metoda polega na kontrolowaniu zarządzania pamięcią i jest po prostu przekazywaniem referencji do wywoływanej przez nią metody (choć pośrednio, ale wszystko to mieści się w zakresie głównym). Jako takie, użyłbyś __bridge.

Ale czekaj, kiedy używam __bridge, mój kod dostaje błędy dostępu do pamięci !?

Ah, to jest problem z kodem, który napisałeś, i nie jest związany z całą dyskusją pomostową. Musisz przekazać void* do CGApply Path, dla swojej funkcji przetwarzania _processPathElement. To, co przechodzisz, to NSMutableArray**.

Po przejściu na wersję NSMutableArray*, faktycznie rzucasz NSMutableArray**. To spowoduje niesławny EXC_BAD_ACCESS. Musisz przekazać sam wskaźnik, a nie wskaźnik do wskaźnika. Ale, CGPathApply(path, pathPoints, _processPathElement) nie działa, nie można przekazać NSMutableArray* jako void*. To, czego potrzebujesz (ironicznie), to most. Z tych samych powodów, jak wcześniej, wszystko, czego potrzebujesz, to __bridge. Zobacz poniżej kodu, z prawidłowymi mostów w miejscu i działa zgodnie z oczekiwaniami:

#import <UIKit/UIKit.h> 
#import <Foundation/Foundation.h> 

void _processPathElement(void* info, const CGPathElement* element) 
{ 
    NSMutableArray *array = (__bridge NSMutableArray*) info; 
    switch (element->type) 
    { 
     case kCGPathElementMoveToPoint: 
     case kCGPathElementAddLineToPoint: 
     { 
      CGPoint point = element->points[0]; 
      [array addObject:[NSValue valueWithCGPoint:point]]; 
      break; 
     } 
     default: 
      break; 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    @autoreleasepool 
    { 
     //Create path 
     CGMutablePathRef path = CGPathCreateMutable(); 
     CGPathMoveToPoint( path, NULL, 0, 0); 
     CGPathAddLineToPoint(path, NULL, 1, 0); 
     CGPathAddLineToPoint(path, NULL, 1, 1); 
     CGPathAddLineToPoint(path, NULL, 0, 1); 
     CGPathCloseSubpath(path); 

     NSMutableArray *pathPoints = [[NSMutableArray alloc] init]; 
     CGPathApply(path, (__bridge void*)pathPoints, _processPathElement); 

     NSLog(@"Points:%@", pathPoints); 
    } 
} 

ten wypisze:

Points:(
    "NSPoint: {0, 0}", 
    "NSPoint: {1, 0}", 
    "NSPoint: {1, 1}", 
    "NSPoint: {0, 1}" 
) 
+0

Dziękuję. =] Wyobrażam sobie, że piszesz to, ponieważ znalazłem i opublikowałem (ten sam) wniosek. Twoja odpowiedź dostarcza jednak o wiele więcej informacji i potwierdza, że ​​natknąłem się na prawidłowe rozwiązanie. –

+0

Należy pamiętać, że używanie wariantów 'CFBridg *' jest często bardziej przejrzyste (w każdym razie dla niektórych z nas). – bbum

1

Nie jestem właściwie pewien, dlaczego to działa, ale znalazłem rozwiązanie będzie:

NSMutableArray *array = (__bridge NSMutableArray*) info; 

//AND 

CGPathApply(path, (__bridge void*)pathPoints, _processPathElement); 

Jeśli ktoś może wyjaśnić, dlaczego to działa i potwierdź, że nie ma (/ są) żadnych wycieków pamięci Byłbym wdzięczny

+1

Brakowało mi tego podczas wpisywania odpowiedzi (SO nie powiadomił mnie o nowych odpowiedziach). Zobacz uzasadnienie tego. – WDUK

Powiązane problemy