Cóż, ponieważ byłoby to bardzo przydatne. Nie musiałbym wiedzieć, co to jest, dopóki mam odpowiednią składnię i zachowuje się jak obiekt NSO.
gurghet
5
Jeśli nie wiesz, co to jest, skąd wiesz, że byłoby to bardzo przydatne?
Stephen Canon
5
Nie powinieneś ich używać, jeśli nie wiesz, czym one są :)
Richard J. Ross III
5
@Moshe oto kilka powodów, które przychodzą mi na myśl. Bloki są łatwiejsze do wdrożenia niż pełna klasa delegata, bloki są lekkie i masz dostęp do zmiennych, które są w kontekście tego bloku. Wywołania zwrotne zdarzeń można skutecznie wykonywać za pomocą bloków (cocos2d używa ich prawie wyłącznie).
Richard J. Ross III
2
Nie do końca powiązane, ale ponieważ niektóre komentarze narzekają na „brzydką” składnię bloków, oto świetny artykuł, który wywodzi składnię z pierwszych zasad: nilsou.com/blog/2013/08/21/objective-c-blocks-syntax
Z xCode 4.4 lub nowszym nie musisz syntezować. Dzięki temu będzie jeszcze bardziej zwięzły. Apple Doc
Eric
wow, nie wiedziałem tego, dzięki! ... Chociaż często to robię@synthesize myProp = _myProp
Robert,
7
@Robert: Znowu masz szczęście, ponieważ bez @synthesizeustawiania domyślnego jest to, co robisz @synthesize name = _name;stackoverflow.com/a/12119360/1052616
Eric,
1
@CharlieMonroe - Tak, prawdopodobnie masz rację, ale czy nie potrzebujesz implementacji dealloc, aby zerować lub zwolnić właściwość bloku bez ARC? (minęło trochę czasu, odkąd użyłem non-ARC)
Robert
1
@imcaptor: Tak, może powodować wycieki pamięci, jeśli nie zwolnisz go w dealloc - tak jak w przypadku każdej innej zmiennej.
Charlie Monroe,
210
Oto przykład, w jaki sposób możesz wykonać takie zadanie:
#import <Foundation/Foundation.h>typedefint(^IntBlock)();@interface myobj :NSObject{IntBlock compare;}@property(readwrite, copy)IntBlock compare;@end@implementation myobj
@synthesize compare;-(void)dealloc
{// need to release the block since the property was declared copy. (for heap// allocated blocks this prevents a potential leak, for compiler-optimized // stack blocks it is a no-op)// Note that for ARC, this is unnecessary, as with all properties, the memory management is handled for you.[compare release];[super dealloc];}@endint main (){@autoreleasepool{
myobj *ob =[[myobj alloc] init];
ob.compare =^{return rand();};NSLog(@"%i", ob.compare());// if not ARC[ob release];}return0;}
Teraz jedyną rzeczą, która musiałaby się zmienić, gdybyś musiał zmienić typ porównania, byłaby typedef int (^IntBlock)(). Jeśli musisz przekazać do niego dwa obiekty, zmień to na: typedef int (^IntBlock)(id, id)i zmień blok na:
^(id obj1, id obj2){return rand();};
Mam nadzieję, że to pomoże.
EDYCJA 12 marca 2012:
W przypadku ARC nie są wymagane żadne konkretne zmiany, ponieważ ARC będzie zarządzać blokami, o ile są one zdefiniowane jako kopiowanie. Nie musisz również ustawiać właściwości na zero w swoim destruktorze.
// Here is a block as a property://// Someone passes you a block. You "hold on to it",// while you do other stuff. Later, you use the block.//// The property 'doStuff' will hold the incoming block.@property(copy)void(^doStuff)(void);// Here's a method in your class.// When someone CALLS this method, they PASS IN a block of code,// which they want to be performed after the method is finished.-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater;// We will hold on to that block of code in "doStuff".
Oto twój plik .m:
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater
{// Regarding the incoming block of code, save it for later:
self.doStuff = pleaseDoMeLater;// Now do other processing, which could follow various paths,// involve delays, and so on. Then after everything:[self _alldone];}-(void)_alldone
{NSLog(@"Processing finished, running the completion block.");// Here's how to run the block:if( self.doStuff != nil )
self.doStuff();}
Uważaj na nieaktualny przykładowy kod.
W nowoczesnych systemach (2014+) rób to, co pokazano tutaj. To takie proste.
Może powinieneś również powiedzieć, że teraz (2016) można używać strongzamiast copy?
Nik Kov
Czy możesz wyjaśnić, dlaczego właściwość nie powinna być nonatomicodmienna od najlepszych praktyk w większości innych przypadków korzystania z właściwości?
Dla potomności / kompletności… Oto dwa PEŁNE przykłady wdrożenia tego absurdalnie wszechstronnego „sposobu robienia rzeczy”. @ Odpowiedź Roberta jest błogo zwięzła i poprawna, ale tutaj chcę również pokazać sposoby „zdefiniowania” bloków.
@interfaceReusableClass:NSObject@property(nonatomic,copy)CALayer*(^layerFromArray)(NSArray*);@end@implementationResusableClassstaticNSStringconst* privateScope =@"Touch my monkey.";-(CALayer*(^)(NSArray*)) layerFromArray {return^CALayer*(NSArray*array){CALayer*returnLayer =CALayer.layer
for(id thing in array){[returnLayer doSomethingCrazy];[returnLayer setValue:privateScope
forKey:@"anticsAndShenanigans"];}returnlist;};}@end
Głupi? Tak. Przydatny?Do diabła Oto inny, „bardziej atomowy” sposób ustawiania właściwości .. i klasa, która jest absurdalnie przydatna…
To ilustruje ustawianie właściwości bloku za pomocą akcesorium (choć wewnątrz init, co jest dyskusyjnie dicey praktyką ..) w porównaniu z mechanizmem „nieatomowego” „gettera” z pierwszego przykładu. W obu przypadkach… implementacje „zakodowane na stałe” zawsze można nadpisać, na przykład .. a lá ..
Również ... jeśli chcesz dodać właściwość bloku do kategorii ... powiedz, że chcesz użyć bloku zamiast jakiejś oldskulowej „akcji” celu / akcji ... Możesz po prostu użyć powiązanych wartości do, cóż ... skojarzyć bloki.
typedefvoid(^NSControlActionBlock)(NSControl*);@interfaceNSControl(ActionBlocks)@property(copy)NSControlActionBlock actionBlock;@end@implementationNSControl(ActionBlocks)-(NSControlActionBlock) actionBlock {// use the "getter" method's selector to store/retrieve the block!return objc_getAssociatedObject(self, _cmd);}-(void) setActionBlock:(NSControlActionBlock)ab {
objc_setAssociatedObject(// save (copy) the block associatively, as categories can't synthesize Ivars.
self,@selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
self.target = self;// set self as target (where you call the block)
self.action =@selector(doItYourself);// this is where it's called.}-(void) doItYourself {if(self.actionBlock && self.target == self) self.actionBlock(self);}@end
Teraz, kiedy naciśniesz przycisk, nie musisz ustawiać IBActiondramatu. Po prostu powiąż pracę, którą należy wykonać przy tworzeniu ...
Ten wzór można zastosować OVER i OVER do API Cocoa. Właściwości mechanicznych przynieść odpowiednie fragmenty kodu bliżej siebie , eliminować zawiłe paradygmaty delegowania , i wykorzystać moc obiektów poza tym po prostu działając jako głupi „kontenerów”.
Alex, świetny powiązany przykład. Wiesz, zastanawiam się nad tym, co nieatomowe. Myśli?
Fattie
2
Bardzo rzadko „atomowy” byłby właściwym rozwiązaniem dla nieruchomości. Byłoby bardzo dziwne, aby ustawić właściwość bloku w jednym wątku i czytać go w innym wątku w tym samym czasie lub ustawić właściwość bloku jednocześnie z wielu wątków. Koszt „atomowy” vs. „nieatomowy” nie daje żadnych realnych korzyści.
gnasher729
8
Oczywiście możesz użyć bloków jako właściwości. Ale upewnij się, że są zadeklarowane jako @property (kopia) . Na przykład:
W MRC bloki przechwytujące zmienne kontekstowe są przydzielane na stosie ; zostaną zwolnione, gdy rama stosu zostanie zniszczona. Jeśli zostaną skopiowane, nowy blok zostanie przydzielony na stosie , który można wykonać później po wyskakowaniu ramki stosu.
To nie ma być „dobra odpowiedź”, ponieważ w tym pytaniu zadaje się wyraźnie Objective-C. Gdy Apple przedstawił Swift na WWDC14, chciałbym podzielić się różnymi sposobami używania bloków (lub zamknięć) w Swift.
Cześć, Szybki
Masz wiele sposobów na przekazanie bloku odpowiadającego funkcji w Swift.
Znalazłem trzy.
Aby to zrozumieć, sugeruję przetestowanie na placu zabaw tego małego fragmentu kodu.
func test(function:String->String)->String{return function("test")}
func funcStyle(s:String)->String{return"FUNC__"+ s +"__FUNC"}
let resultFunc = test(funcStyle)
let blockStyle:(String)->String={s in return"BLOCK__"+ s +"__BLOCK"}
let resultBlock = test(blockStyle)
let resultAnon = test({(s:String)->String in return"ANON_"+ s +"__ANON"})
println(resultFunc)
println(resultBlock)
println(resultAnon)
Szybki, zoptymalizowany do zamknięć
Ponieważ Swift jest zoptymalizowany pod kątem rozwoju asynchronicznego, Apple pracował więcej na zamknięciach. Po pierwsze, można wnioskować o podpisie funkcji, więc nie trzeba go przepisywać.
Dostęp do parametrów według numerów
let resultShortAnon = test({return"ANON_"+ $0 +"__ANON"})
Wnioskowanie z nazwami
let resultShortAnon2 = test({myParam in return"ANON_"+ myParam +"__ANON"})
Zamknięcie końcowe
Ten szczególny przypadek działa tylko wtedy, gdy blok jest ostatnim argumentem, nazywa się to końcowym zamknięciem
Oto przykład (połączony z wywnioskowanym podpisem, aby pokazać moc Swift)
let resultTrailingClosure = test {return"TRAILCLOS_"+ $0 +"__TRAILCLOS"}
Wreszcie:
Wykorzystując całą tę moc, chciałbym połączyć końcowe zamykanie i wnioskowanie o typie (z nazewnictwem dla czytelności)
PFFacebookUtils.logInWithPermissions(permissions){
user, error in
if(!user){
println("Uh oh. The user cancelled the Facebook login.")}elseif(user.isNew){
println("User signed up and logged in through Facebook!")}else{
println("User logged in through Facebook!")}}
Uzupełnienie odpowiedzi udzielonej przez @Francescu.
Dodanie dodatkowych parametrów:
func test(function:String->String, param1:String, param2:String)->String{return function("test"+param1 + param2)}
func funcStyle(s:String)->String{return"FUNC__"+ s +"__FUNC"}
let resultFunc = test(funcStyle,"parameter 1","parameter 2")
let blockStyle:(String)->String={s in return"BLOCK__"+ s +"__BLOCK"}
let resultBlock = test(blockStyle,"parameter 1","parameter 2")
let resultAnon = test({(s:String)->String in return"ANON_"+ s +"__ANON"},"parameter 1","parameter 2")
println(resultFunc)
println(resultBlock)
println(resultAnon)
Odpowiedzi:
Jeśli zamierzasz powtarzać ten sam blok w kilku miejscach, użyj def
źródło
@synthesize myProp = _myProp
@synthesize
ustawiania domyślnego jest to, co robisz@synthesize name = _name;
stackoverflow.com/a/12119360/1052616Oto przykład, w jaki sposób możesz wykonać takie zadanie:
Teraz jedyną rzeczą, która musiałaby się zmienić, gdybyś musiał zmienić typ porównania, byłaby
typedef int (^IntBlock)()
. Jeśli musisz przekazać do niego dwa obiekty, zmień to na:typedef int (^IntBlock)(id, id)
i zmień blok na:Mam nadzieję, że to pomoże.
EDYCJA 12 marca 2012:
W przypadku ARC nie są wymagane żadne konkretne zmiany, ponieważ ARC będzie zarządzać blokami, o ile są one zdefiniowane jako kopiowanie. Nie musisz również ustawiać właściwości na zero w swoim destruktorze.
Więcej informacji można znaleźć w tym dokumencie: http://clang.llvm.org/docs/AutomaticReferenceCounting.html
źródło
W przypadku Swift wystarczy użyć zamknięć: przykład.
W celu C:
@property (copy) void
To takie proste.
Oto aktualna dokumentacja Apple, która dokładnie określa, czego użyć:
Dokument Apple
W twoim pliku .h:
Oto twój plik .m:
Uważaj na nieaktualny przykładowy kod.
W nowoczesnych systemach (2014+) rób to, co pokazano tutaj. To takie proste.
źródło
strong
zamiastcopy
?nonatomic
odmienna od najlepszych praktyk w większości innych przypadków korzystania z właściwości?Dla potomności / kompletności… Oto dwa PEŁNE przykłady wdrożenia tego absurdalnie wszechstronnego „sposobu robienia rzeczy”. @ Odpowiedź Roberta jest błogo zwięzła i poprawna, ale tutaj chcę również pokazać sposoby „zdefiniowania” bloków.
Głupi? Tak. Przydatny?Do diabła Oto inny, „bardziej atomowy” sposób ustawiania właściwości .. i klasa, która jest absurdalnie przydatna…
To ilustruje ustawianie właściwości bloku za pomocą akcesorium (choć wewnątrz init, co jest dyskusyjnie dicey praktyką ..) w porównaniu z mechanizmem „nieatomowego” „gettera” z pierwszego przykładu. W obu przypadkach… implementacje „zakodowane na stałe” zawsze można nadpisać, na przykład .. a lá ..
Również ... jeśli chcesz dodać właściwość bloku do kategorii ... powiedz, że chcesz użyć bloku zamiast jakiejś oldskulowej „akcji” celu / akcji ... Możesz po prostu użyć powiązanych wartości do, cóż ... skojarzyć bloki.
Teraz, kiedy naciśniesz przycisk, nie musisz ustawiać
IBAction
dramatu. Po prostu powiąż pracę, którą należy wykonać przy tworzeniu ...Ten wzór można zastosować OVER i OVER do API Cocoa. Właściwości mechanicznych przynieść odpowiednie fragmenty kodu bliżej siebie , eliminować zawiłe paradygmaty delegowania , i wykorzystać moc obiektów poza tym po prostu działając jako głupi „kontenerów”.
źródło
Oczywiście możesz użyć bloków jako właściwości. Ale upewnij się, że są zadeklarowane jako @property (kopia) . Na przykład:
W MRC bloki przechwytujące zmienne kontekstowe są przydzielane na stosie ; zostaną zwolnione, gdy rama stosu zostanie zniszczona. Jeśli zostaną skopiowane, nowy blok zostanie przydzielony na stosie , który można wykonać później po wyskakowaniu ramki stosu.
źródło
Disclamer
To nie ma być „dobra odpowiedź”, ponieważ w tym pytaniu zadaje się wyraźnie Objective-C. Gdy Apple przedstawił Swift na WWDC14, chciałbym podzielić się różnymi sposobami używania bloków (lub zamknięć) w Swift.
Cześć, Szybki
Masz wiele sposobów na przekazanie bloku odpowiadającego funkcji w Swift.
Znalazłem trzy.
Aby to zrozumieć, sugeruję przetestowanie na placu zabaw tego małego fragmentu kodu.
Szybki, zoptymalizowany do zamknięć
Ponieważ Swift jest zoptymalizowany pod kątem rozwoju asynchronicznego, Apple pracował więcej na zamknięciach. Po pierwsze, można wnioskować o podpisie funkcji, więc nie trzeba go przepisywać.
Dostęp do parametrów według numerów
Wnioskowanie z nazwami
Zamknięcie końcowe
Ten szczególny przypadek działa tylko wtedy, gdy blok jest ostatnim argumentem, nazywa się to końcowym zamknięciem
Oto przykład (połączony z wywnioskowanym podpisem, aby pokazać moc Swift)
Wreszcie:
Wykorzystując całą tę moc, chciałbym połączyć końcowe zamykanie i wnioskowanie o typie (z nazewnictwem dla czytelności)
źródło
Cześć, Szybki
Uzupełnienie odpowiedzi udzielonej przez @Francescu.
Dodanie dodatkowych parametrów:
źródło
Możesz postępować zgodnie z poniższym formatem i możesz użyć
testingObjectiveCBlock
właściwości w klasie.Aby uzyskać więcej informacji, zajrzyj tutaj
źródło