2012-06-08 19 views
7

Ten kod daje mi EXC_BAD_ACCESS, dlaczego?dlaczego ten kod daje EXC_BAD_ACCESS (przy użyciu IMP)

NSMutableDictionary *d = [[NSMutableDictionary alloc] init]; 
IMP imp= [d methodForSelector:@selector(setObject:forKey:) ]; 
imp(d, @selector(setObject:forKey:), @"obj", @"key"); 

Właśnie zaczynam używać IMP, pierwsze próby .. bez powodzenia. Nie wiem, dlaczego dostaję błąd, także .. w przeszłości, kiedy dostałem EXC_BAD_ACCESS, wiadomość została wydrukowana na konsoli, tym razem linia błędu jest podświetlona.

Kilka uwag: ARC jest włączona, XCode 4.3.2, projekt korzysta z Objective-C++ jako de domyślnego języka/kompilatora, ten kod jest na samym początku projektu

Dzięki chłopaki

+0

Nie mogę się reprodukować. Jeśli umieścisz to w nowym projekcie, czy nadal pojawia się błąd? – Chuck

+0

Tak, co znalazłem ... Problemem jest ARC. Spróbuj utworzyć nowy projekt iOS z włączoną opcją ARC. Następnie skopiuj i wklej kod gdzieś (umieściłem go w aplikacji didFinishLaunchingWithOptions :) – subzero

Odpowiedz

20

Musisz poprawnie obsadzić wskaźnik funkcji lub ARC nie wie, co ma robić. IMP jest ogólnym wskaźnikiem funkcji, który przyjmuje identyfikator, selektor i zmienną liczbę innych, niezdefiniowanych argumentów i zwraca identyfikator. Implementacja metody, którą próbujesz wywołać, przyjmuje id, selektor, po którym następują dokładnie dwa parametry id i ma typ void return. Można to naprawić poprzez zmianę do następującego kodu:

NSMutableDictionary* dict = [[NSMutableDictionary alloc] init]; 
void (*imp)(id, SEL, id, id) = (void(*)(id,SEL,id,id))[dict methodForSelector:@selector(setObject:forKey:)]; 
if(imp) imp(dict, @selector(setObject:forKey:), @"obj", @"key"); 

Należy zawsze sprawdzić, czy rzeczywiście ma wskaźnik funkcji z powrotem przed wami dereference nim, jak również awarii. Powyższy kod zadziała nawet w środowisku ARC. Ponadto, nawet jeśli nie używasz ARC, powinieneś zawsze rzucać wskaźniki funkcji do rzeczywistego prototypu zamiast IMP. Nigdy nie powinieneś używać IMP. Innymi miejscami, które mogą powodować poważne problemy, są: metoda zwraca strukturę lub metoda przyjmuje parametry zmiennoprzecinkowe, itd.

Dobry nawyk: zawsze rzucaj wskaźnikami funkcji lub wpisz dla nich literówki, jeśli znajdziesz składnię wskaźnika .

+0

Dzięki Jason. To działało jak urok !. Pytanie: dlaczego spowodowałoby to poważny problem ze strukturami lub metodami z parametrami zmiennoprzecinkowymi ?, gdybyś mógł wskazać mi jakiś dokument, będę szczęśliwszy. Właśnie znalazłem interesujący temat "runtime". – subzero

+1

Ma to związek z konwencjami wywoływania funkcji w C i przekazywaniem parametrów. Ponieważ kompilator nie wie nic o parametrach IMP poza parametrami 'self' i' _cmd', po prostu przesunie inne parametry na stos i oczekuje, że wywoływana funkcja będzie wiedziała, co z nimi zrobić. Jednakże, jeśli wywoływana funkcja oczekuje wartości zmiennoprzecinkowej, prawie na pewno będzie wyglądać w GPR (dla ARM) lub innym rejestrze specyficznym dla Fp, a nie na stosie itp. Podobnie jest w przypadku typów zwracanych, struktury są obsługiwane inaczej niż wskaźniki. –

1

Problem polega na tym, że IMP ma typ zwrotny "id", który ARC będzie próbował zarządzać. Musisz rzucić wskaźnik funkcji, aby uzyskać zwrotny typ pustki (zgodny z metodą, do której dzwonisz):

NSMutableDictionary *d = [[NSMutableDictionary alloc] init]; 
    IMP imp= [d methodForSelector: @selector(setObject:forKey:)]; 
    void (*func)(__strong id,SEL,...) = (void (*)(__strong id, SEL, ...))imp; 
    func(d, @selector(setObject:forKey:), @"obj", @"key"); 
+0

'void (*) (id, SEL, ...)' nie jest właściwym typem wskaźnika funkcji. Jest to "void (*) (id, SEL, id, id)". Chociaż może działać w tym konkretnym przypadku na pewnych architekturach z pewnymi typami ("id"), ogólnie jest niepoprawny. – newacct

+0

To się udało. Dzięki. – Felipe

Powiązane problemy