6

mam tylko do odczytu właściwości isFinished w moim pliku interfejs:Przypisanie do Ivar w bloku poprzez słabym wskaźnikiem

typedef void (^MyFinishedBlock)(BOOL success, NSError *e); 

@interface TMSyncBase : NSObject { 
    BOOL isFinished_; 
} 

@property (nonatomic, readonly) BOOL isFinished; 

i chcę ustawić go YES w bloku w pewnym momencie później, bez tworzenia zachować cykl do self:

- (void)doSomethingWithFinishedBlock:(MyFinishedBlock)theFinishedBlock { 
    __weak MyClass *weakSelf = self; 
    MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
     [weakSelf willChangeValueForKey:@"isFinished"]; 
     weakSelf -> isFinished_ = YES; 
     [weakSelf didChangeValueForKey:@"isFinished"]; 
     theFinishedBlock(success, e); 
    }; 

    self.finishedBlock = finishedBlockWrapper; // finishedBlock is a class ext. property 
} 

jestem pewien, że jest to dobry sposób, żeby to zrobić. Czy ten kod wycieknie, czy pęknie, czy jest w porządku? Być może jest łatwiejszy sposób, który przeoczyłem?

+2

tylko FYI, można użyć '__weak typeof (self) * weakSelf = siebie;' –

+0

cool, to przydatne! – manmal

+4

Mała poprawka do ogólnej deklaracji '__weak typeof (self) weakSelf = self;' typeof (self) jest już wskaźnikiem. – allprog

Odpowiedz

5

Przechodząc zmienna blok może być zerowa, sprawdzić przed wywołaniem lub dodać dochodzić na początku funkcji lub będzie awarię

Ponieważ nie zachowując siebie i założymy, że wykonujesz jakąś długą zadanie na wątek tła przez czas wykonania twojego kodu weakSelf może być zerowy (miejmy nadzieję, że używasz ARC i 5.0, więc nilujesz słabe referencje).

Jeśli nie masz prawdziwych słabych odniesień (< 5.0, bez ARC, kompilator nadal akceptuje __weak, ale to nie ma znaczenia) spowodowałoby to awarię.

Również dostęp do ivar przy użyciu "->" spowoduje awarię, jeśli wskaźnik obiektu jest zerowy, więc musisz się upewnić, że tak się nie stanie.

Nawet jeśli zrobisz kod jako dasblinkenlight, to może on ulec awarii, jeśli weakSelf będzie w tej chwili zerowy, załóżmy, że wysyłasz blok na tle wątku, a następnie obiekt zostaje zwolniony przed wykonaniem bloku, to czyni weakSelf zero tym samym uzyskując dostęp do niego użycie "->" spowoduje awarię. W tym przypadku chciałbym zmodyfikować kod w następujący sposób:

__weak MyClass *weakSelf = self; 
MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
    MyClass *strongSelf = weakSelf; 
    //! whatever task you want executed 
    strongSelf.isFinished = YES; 
    theFinishedBlock(success, e); 
}; 

Również można sprawdzić, czy weakSelf jest zerowa, aby zapobiec kosztowne zadanie z realizacji, jeśli nie ma sensu (obiekt jest już zniszczona). Ale to zależy od przypadku użycia.

Ale jest jeszcze inny przypadek, który musisz wziąć pod uwagę podczas programowania z blokami, na przykład: Możesz mieć instancję obiektu zadania, której rolą jest tylko wykonanie jakiegoś zadania w tle, w takim przypadku ten kod może się nie powieść, ponieważ utworzy nowe zadanie i może zostać zwolniony, zanim blok zostanie wykonany na wątku tła, w takim przypadku powinieneś zachować siebie i nie zatrzymywać bloku w obiekcie (to zapobiegnie zatrzymaniu cyklu).

+0

dzięki! tak, to jest iOS5, dzięki Bogu. – manmal

+0

isFinished jest właściwością readonly, więc nie chcę, aby '' 'strongSelf.isFinished = YES''' działał ... jest tam tylko dla KVO – manmal

+1

Specify to normalne przypisanie w prywatnej kategorii, to sprawi, że będzie ono gotowe do zapisu w swoim kodzie zajęć, ale tylko poza nim, to również pominie niepotrzebne ręczne powiadomienia KVO. –

0

Lekkim rozwiązaniem jest utworzenie metody i umożliwienie kompilatorowi obsługiwać ją za Ciebie. Działa dobrze, ale nie jestem pewien, czy to jest poprawna metoda. Czy ktoś może powiedzieć, czy jest poprawny?

__weak MyClass *weakSelf = self; 
MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
    [weakSelf makeIsFinishedYes]; 
}; 

- (void)makeIsFinishedYes 
{ 
    isFinished_ = YES; 
} 
Powiązane problemy