Lista składni deklaracji blokowej

277

Składnia bloku w celu C (i rzeczywiście C, jak przypuszczam) jest notorycznie niestosowna. Przekazywanie bloków jako argumentów wygląda inaczej niż deklarowanie bloków jako ivars, które wyglądają inaczej niż typedefblokowanie bloków.

Czy istnieje wyczerpująca lista składni deklaracji blokowej, którą mógłbym mieć pod ręką w celu szybkiego zapoznania się z nią?

Patrick Perini
źródło
9
Co jest złego w „Deklarowaniu i tworzeniu bloków” w Przewodniku tematów programowania bloków?
jscs
proste objaśnienie korzystania z właściwości bloku: stackoverflow.com/a/20760583/294884
Fattie

Odpowiedzi:

696

Lista składni deklaracji blokowych

Niech przez cały czas

  • return_typebyć typem obiektu / prymitywu / etc. chcesz wrócić (zwykle void)
  • blockName być nazwą zmiennej tworzonego bloku
  • var_typebyć obiektem typu / prymitywne / itp. chcesz przekazać jako argument (pozostaw puste dla żadnych parametrów)
  • varName być nazwą zmiennej podanego parametru

I pamiętaj, że możesz utworzyć dowolną liczbę parametrów.

Bloki jako zmienne

Prawdopodobnie najczęstszy z deklaracji.

return_type (^blockName)(var_type) = ^return_type (var_type varName)
{
    // ...
};

Bloki jako właściwości

Podobnie jak deklarowanie bloków jako zmiennych, jednak subtelnie różne.

@property (copy) return_type (^blockName) (var_type);

Bloki jako parametry

Zauważ, że różni się to od „Bloków jako argumentów”; w tym przypadku deklarujesz metodę, która chce argumentu blokowego.

- (void)yourMethod:(return_type (^)(var_type))blockName;

Bloki jako argumenty

Zauważ, że różni się to od „Bloków jako parametrów”; w tym przypadku wywołujesz metodę, która chce argumentu blokowego z anonimowym blokiem. Jeśli zadeklarowałeś już zmienną blokową, wystarczy podać nazwę zmiennej jako argument.

[someObject doSomethingWithBlock: ^return_type (var_type varName)
{
    //...
}];

Blok anonimowy

Jest to funkcjonalnie blok anonimowy, jednak składnia przypisywania bloków do zmiennych polega po prostu na ustawieniu zmiennej równej blokowi anonimowemu.

^return_type (var_type varName)
{
    //...
};

typedef Blok

Pozwala to ustawić krótką nazwę, do której można się odwoływać, tak jak każdą inną nazwę klasy podczas deklarowania bloków.

typedef return_type (^blockName)(var_type);

Aby później użyć blockNamezamiast standardowej składni deklaracji bloku, po prostu zamień.

Blok wbudowany

Jest to prawdopodobnie mniej użyteczne wykorzystanie bloków, ale może jednak mieć swoje miejsce. Blok wbudowany to blok anonimowy wywoływany natychmiast po utworzeniu wystąpienia.

^return_type (var_type varName)
{
    //...
}(var);

Bloki wbudowane są przede wszystkim przydatne do przesunięcia zakresu i są w przybliżeniu równoważne prostym fragmentom kodu rozdzielanym nawiasami klamrowymi.

{
   //...
}

Bloki rekurencyjne

Umożliwia to samodzielne wywołanie bloku, tworząc pętlę, z której można korzystać podczas wywołań zwrotnych i połączeń GCD. Ta metoda tworzenia instancji jest wolna od cykli zatrzymania w ARC.

__block return_type (^blockName)(var_type) = [^return_type (var_type varName)
{
    if (returnCondition)
    {
        blockName = nil;
        return;
    }

    // ...
} copy];
blockName(varValue);

Powracające bloki

Metoda może zwrócić blok,

- (return_type(^)(var_type))methodName
{
    // ...
}

jak również funkcja, choć trochę dziwnie.

return_type (^FunctionName())(var_type)
{
    // ...
}

Dodatki

Jeśli coś przeoczyłem, daj mi znać w komentarzach, a ja je zbadam / dodam.

Aha, i w Swift ...

blockName = (varName: var_type) -> (return_type)

To prawie jak funkcja językowa.

Patrick Perini
źródło
1
@pcperini Świetna lista! A jak używać definicji bloku wpisanego w deklaracji zmiennej (1. pozycja na liście)? BlockType ^blockVar = Anonymous BlockBłąd logiczny pokazuje błąd składni, również bez ^ :(
esp 20'13
14
W jakiś sposób mój mózg nie jest w stanie zapamiętać tej różnorodnej składni deklaracji blokowych. Prawdopodobnie patrzę na tę odpowiedź raz w tygodniu. Żałuję, że nie mogę dać ci za to 10 głosów poparcia.
Ben Baron
36
Potrzebujemy galerii sław StackOverflow, aby uzyskać odpowiedzi na tego typu pytania.
bejonbee
1
Przekształciłem to w Markdown do użytku z przeglądarką do drukowania. Poręczny! gist.github.com/swizzlr/6268955
Swizzlr
20
Myślę, że potrzebuję tego jako tatuażu.
Isaac Overacker
83

Osobiście lubię korzystać z tej strony ( http://fuckingblocksyntax.com ). Nazwa jest łatwiejsza do zapamiętania niż sama składnia bloku:

http://fuckingblocksyntax.com

a jeśli nie możesz załadować adresów URL ze złymi słowami, możesz użyć tego dublowania: http://goshdarnblocksyntax.com

strona fuckingblocksyntax

psy
źródło
1
idealna nazwa strony internetowej ..: D
Vineeth
39

Typedef:

typedef void (^block)(NSString *arg);

Inline:

void (^block)(NSString *) = ^(NSString *param) {
  // do something....
};

Metoda:

- (void)method:(void (^)(NSString *param))handler
Erik Aigner
źródło
Ta odpowiedź pokazuje, że nie jest to wcale takie skomplikowane ... tylko 3 różne składnie do miksowania i dopasowywania.
Joseph Chen
4
Przyjęta odpowiedź jest tylko kopią tej odpowiedzi z niepotrzebnym wzdęciem.
Erik Aigner,
16

Biblioteka fragmentów kodu Xcode 4 zawiera szablony bloków typedefs i bloków wstawianych jako zmiennych. Są one również dostępne poprzez automatyczne uzupełnianie ( typedefblocki inlineblock).

W przypadku bloków jako argumentów metod, zaleciłbym zadeklarowanie a, typedefa następnie użycie tego. Znacznie ułatwia to odczytanie kodu.

omz
źródło
11

Napisałem funkcję completeBlock dla klasy, która zwróci wartości kości po ich wstrząśnięciu:

  1. Zdefiniuj typedef za pomocą returnType ( .hpowyżej @interfacedeklaracji)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
  2. Zdefiniuj a @propertydla bloku ( .h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
  3. Zdefiniuj metodę za pomocą finishBlock( .h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
  4. Wkładka poprzedniej metody zdefiniowanej w .mpliku i zobowiązać się finishBlockdo @propertyzdefiniowanych wcześniej

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
  5. Aby uruchomić completionBlockprzekazanie predefiniowanej zmiennejType (nie zapomnij sprawdzić, czy completionBlockistnieje)

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }
Alex Cio
źródło
7
typedef void (^OkBtnBlock)(id data);
typedef void (^CancelBtnBlock)();

@property (nonatomic, strong) OkBtnBlock okBtnBlock;
@property (nonatomic, strong) CancelBtnBlock cancelBtnBlock;

+ (void)foo:(OkBtnBlock)okBtn andCancel:(CancelBtnBlock)btnCancel;
benhi
źródło
Dobrze byłoby opisać cały proces krok po kroku, bloki są trudne do zrozumienia, jeśli jesteś nowy w iOS ...
Alex Cio
3

Jeśli musisz wrócić do Xcode 4.2, możesz również @syntezować blok zadeklarowany jako właściwość, tak jak w przypadku właściwości nieblokowanej. Nie pozwól, by składnia bloku cię rzuciła.

Jeśli twoja właściwość bloku to:

@property (copy) return_type (^blockName) (var_type);

Twój @synthesize to:

@property blockName;

Twoje zdrowie.

Alex Zavatone
źródło
Cześć, czy mógłbyś sprawdzić ponownie. Właśnie próbowałem za Tobą podążać .. @property blockNamenie działa. Myślę, że tak powinno być @synthesize blockName;? (do syntezy bloku)
jeet.chanchawat
Ups ... poczekaj, aż już (pośrednio) wspomniałeś, że nie będzie działać z xcode 7.
jeet.chanchawat 16.01.16