2011-10-29 21 views
129

Jak mogę przekazać Block do Function/Method?Obiekt blokujący Objective-C jako parametr

Próbowałem - (void)someFunc:(__Block)someBlock bezskutecznie.

tj. Co to jest typ dla Block?

+6

odniesienie, że mogę używać więcej niż Zależy mi się przyznać: http: // goshdarnblocksyntax. com/ – oltman

+0

http://fuckingblocksyntax.com/ :) – aryaxt

Odpowiedz

236

Typ bloku różni się w zależności od jego argumentów i typu zwracanego. W ogólnym przypadku typy bloków są deklarowane w ten sam sposób, co funkcje typów wskaźników, ale zastępowanie * za pomocą . Jednym ze sposobów przekazania bloku do metody jest:

- (void)iterateWidgets:(void (^)(id, int))iteratorBlock; 

Ale jak widać, jest brudny. Zamiast tego można użyć typedef aby typy bloków czystsze:

typedef void (^ IteratorBlock)(id, int); 

a następnie przekazać ten blok do metody tak:

- (void)iterateWidgets:(IteratorBlock)iteratorBlock; 
+0

Dlaczego przekazujesz id jako argument? Czy nie można na przykład łatwo przekazać numeru NSNumber? Jak to wyglądałoby? – bas

+7

Z pewnością można przekazać mocno napisany argument, taki jak 'NSNumber *' lub 'std :: string & 'lub cokolwiek innego, co można przekazać jako argument funkcji. To tylko przykład. (Dla bloku, który jest równoważny z wyjątkiem zastąpienia 'id' przez' NSNumber', 'typedef' będzie' typedef void (^ IteratorWithNumberBlock) (NSNumber *, int); '.) –

+0

To pokazuje deklarację metody. Jednym z problemów z blokami jest to, że "bałaganiarski" styl deklaracji nie czyni jasnym i łatwym zapisanie faktycznego wywołania metody z rzeczywistym argumentem bloku. – uchuugaka

49

To może być pomocne:

- (void)someFunc:(void(^)(void))someBlock; 
+0

brakuje ci nawiasu – newacct

+0

Ten działał dla mnie, podczas gdy poprzedni nie. Btw dzięki mate, to było naprawdę pomocne! – tanou

6

Można również ustawić blok jako prosta własności, czy to dotyczy Ciebie:

@property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString); 

upewnić się, że nieruchomość jest blok „kopia”!

i oczywiście można również używać typedef:

typedef void (^SimpleBlock)(id); 

@property (nonatomic, copy) SimpleBlock someActionHandler; 
22

Można zrobić tak, przechodząc blok jako parametr bloku:

//creating a block named "completion" that will take no arguments and will return void 
void(^completion)() = ^() { 
    NSLog(@"bbb"); 
}; 

//creating a block namd "block" that will take a block as argument and will return void 
void(^block)(void(^completion)()) = ^(void(^completion)()) { 
    NSLog(@"aaa"); 
    completion(); 
}; 

//invoking block "block" with block "completion" as argument 
block(completion); 
+2

ta odpowiedź naprawdę mogłaby zrobić z pewnym wyjaśnieniem ... – katzenhut

+0

Hm, po prostu przekazujesz drugi blok jako parametr do pierwszego. To wszystko. –

+2

tak, ja też mogłem być jaśniejszy. Zasugerowałem edycję wyjaśniającą, co mam na myśli. – katzenhut

7

jeden sposób, aby przekazać blok przy użyciu funkcji с w przykład poniżej. Stworzyłem funkcje do wykonywania wszystkiego w tle i w głównej kolejce.

plik blocks.h

void performInBackground(void(^block)(void)); 
void performOnMainQueue(void(^block)(void)); 

plik blocks.m

#import "blocks.h" 

void performInBackground(void(^block)(void)) { 
    if (nil == block) { 
     return; 
    } 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block); 
} 

void performOnMainQueue(void(^block)(void)) { 
    if (nil == block) { 
     return; 
    } 

    dispatch_async(dispatch_get_main_queue(), block); 
} 

niż import blocks.h gdy jest to konieczne i powołać go:

- (void)loadInBackground { 

    performInBackground(^{ 

     NSLog(@"Loading something in background"); 
     //loading code 

     performOnMainQueue(^{ 
      //completion hadler code on main queue 
     }); 
    }); 
} 
2

Mimo odpowiedzi udzielonych na ten temat wątku, naprawdę starałem się napisać funkcję, która wzięłaby Blok jako funkcję - i z parametrem. W końcu mam rozwiązanie, które wymyśliłem.

Chciałem napisać ogólną funkcję, loadJSONthread, która zajmie URL usługi sieciowej JSON, załaduję niektóre dane JSON z tego adresu URL w wątku tła, a następnie zwrócę NSArray * wyników z powrotem do funkcji wywołującej.

Zasadniczo chciałem ukryć całą złożoność wątku tła w ogólnej funkcji wielokrotnego użytku.

Oto jak Nazwałbym tę funkcję:

NSString* WebServiceURL = @"http://www.inorthwind.com/Service1.svc/getAllCustomers"; 

[JSONHelper loadJSONthread:WebServiceURL onLoadedData:^(NSArray *results) { 

    // Finished loading the JSON data 
    NSLog(@"Loaded %lu rows.", (unsigned long)results.count); 

    // Iterate through our array of Company records, and create/update the records in our SQLite database 
    for (NSDictionary *oneCompany in results) 
    { 
     // Do something with this Company record (eg store it in our SQLite database) 
    } 

} ]; 

... i to jest nieco zmagałem się: jak to deklarują, i jak się go wywołać funkcję Zablokuj raz dane było załadowany, i przekazać Block NSArray * zapisów załadowany:

+(void)loadJSONthread:(NSString*)urlString onLoadedData:(void (^)(NSArray*))onLoadedData 
{ 
    __block NSArray* results = nil; 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_async(queue, ^{ 

     // Call an external function to load the JSON data 
     NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:urlString]; 
     results = [dictionary objectForKey:@"Results"]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 

      // This code gets run on the main thread when the JSON has loaded 
      onLoadedData(results); 

     }); 
    }); 
} 

Ten StackOverflow pytanie dotyczy sposobu wywoływania funkcji, przekazując jako parametr bloku, więc ja uprościć powyższy kod i nie obejmowały loadJSONDataFromURL funkcjonować.

Ale, jeśli jesteś zainteresowany, można znaleźć kopię tego JSON funkcji załadunku na tym blogu: http://mikesknowledgebase.azurewebsites.net/pages/Services/WebServices-Page6.htm

Nadzieja pomaga to kilka innych deweloperów XCode! (Nie zapomnij zagłosować maksymalnie na to pytanie i moja odpowiedź, jeśli to robi!)

+1

To poważnie jedna z najlepszych sztuczek, jakie widziałem w ios i blokach. Uwielbiam to człowiek !!!! – portforwardpodcast

1

Napisałem completionBlock dla klasy, która będzie zwracać wartości kości po ich wstrząśnięty:

  1. zdefiniować typedef z returnType (.h powyżej @interface zgłoszenie)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue); 
    
  2. Definiowanie @property dla bloku (.h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling; 
    
  3. Zdefiniować metodę z finishBlock (.h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock; 
    
  4. Insert poprzedni określoną metodą w .m pliku i zobowiązać finishBlock do @property zdefiniowane przed

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{ 
        self.completeDiceRolling = finishBlock; 
    } 
    
  5. Aby wywołać completionBlock wprost predefiniowane variableType do tego (Nie zapomnij sprawdzić, czy completionBlock istnieje)

    if(self.completeDiceRolling){ 
        self.completeDiceRolling(self.dieValue); 
    } 
    
3

zawsze zapominają o składni bloków. To zawsze przychodzi mi do głowy, kiedy muszę zadeklarować blok.Mam nadzieję, że ktoś pomaga :)

http://fuckingblocksyntax.com

37

Najprostszym wyjaśnieniem tej kwestii jest następujące szablony:

1. Blok jako parametr metody

Szablon

- (void)aMethodWithBlock:(returnType (^)(parameters))blockName { 
     // your code 
} 

Przykład

-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{ 
     // your code 
} 

Inne zastosowania przypadkach:

2. Blok jako właściwość

Szablon

@property (nonatomic, copy) returnType (^blockName)(parameters); 

Przykład

@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error); 

3. Blok jako sposób argumentu

Szablon

[anObject aMethodWithBlock: ^returnType (parameters) { 
    // your code 
}]; 

Przykład

[self saveWithCompletionBlock:^(NSArray *array, NSError *error) { 
    // your code 
}]; 

4. Blok w zmiennej lokalnej

Szablon

returnType (^blockName)(parameters) = ^returnType(parameters) { 
    // your code 
}; 

Przykład

void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){ 
    // your code 
}; 

5.Blok jako typedef

Szablon

typedef returnType (^typeName)(parameters); 

typeName blockName = ^(parameters) { 
    // your code 
} 

Przykład

typedef void(^completionBlock)(NSArray *array, NSError *error); 

completionBlock didComplete = ^(NSArray *array, NSError *error){ 
    // your code 
}; 
+1

Świetna odpowiedź dzięki bardzo. –

+0

Świetna odpowiedź man.Far lepiej niż akceptowane one.Thanks. – abhi1992

+0

Tak praktyczne i jasne, co sprawia, że ​​ta odpowiedź jest najlepsza, moim zdaniem. – developermike