iOS/Objective-C: Как мога да смесвам делегиране и блокове?

Имам два класа. Delegator използва делегиране, за да изпрати своя резултат. Blocker използва блокове в статични методи.

Без да променям Delegator, как мога да елегантно и лесно внедря methodWithBlock, така че блокът да бъде извикан с резултата, произведен от methodWithDelegate?

Делегатор:

@class Delegator;

@protocol Delegate <NSObject>
- (void)delegator:(Delegator *)sender producedResult:(int)result;
@end

@interface Delegator : NSObject
@property (weak, nonatomic) id <Delegate> delegate;
- (void)methodWithDelegate;
@end

@implementation Delegator
- (void)methodWithDelegate
{
    // Some asynchronous computation resulting in
    [self.delegate delegator:self producedResult:42];
}
@end

Блокатор:

@interface Blocker : NSObject
+ (void)methodWithBlock:(void(^)(int result))block;
@end

@implementation Blocker
+ (void)methodWithBlock:(void(^)(int result))block
{
    // How to call Delegator's methodWithDelegate and return
    // the result using block ?
    ...
}
@end

Изследвани решения:

  • Обвийте Delegator в нов клас или категория и създайте метод, който връща блок, както е предложено в този отговор. Тези решения работят, но са твърде сложни и отнемат много време.

  • Накарайте Blocker да съответства на протокола Delegate и запазете блока в свойство, инстанцирайте го в рамките на метода methodWithBlock и извикайте блока, когато се извика методът за делегиране. Това не работи, тъй като няма силен указател към този нов екземпляр и той се унищожава.

  • В предишното решение, за да избегнете загубата на екземпляра поради липса на силен указател, запазете статичен масив от текущите екземпляри на Blocker и ги изтрийте в метода за обратно извикване на делегат. Отново, това решение работи, но е твърде сложно.


person Julien Dupuis    schedule 30.01.2013    source източник
comment
Не съм сигурен, че можете да избегнете усложнения в този случай. Бих избрал номер 3, ако е приложен правилно, би трябвало да е победител. Не се страхувайте от сложните неща :)   -  person Stavash    schedule 30.01.2013
comment
Не е съвсем ясно какъв резултат връщате от -methodWithDelegate, тъй като всичко във вашия примерен код връща void.   -  person Jonathan Grynspan    schedule 30.01.2013
comment
Не съм напълно сигурен, че разбирам въпроса, но съм почти сигурен, че бих могъл да ви помогна, ако го разбера. Blocker използва статични функции, които изчисляват нещата и след това изпращат резултата чрез блок. Извиквате тези функции по следния начин: [Blocker methodWithBlock:^(int result) { ... do whatever with result ... }];, какъв изглежда е проблемът? Каква справка губиш?   -  person Ismael    schedule 30.01.2013
comment
@Ismael: Опитвам се да внедря метода methodWithBlock.   -  person Julien Dupuis    schedule 01.02.2013


Отговори (2)


Вместо делегати и блокиращи свойства, използвайте наблюдаемо свойство, за да съобщите резултатите. Това е по-чисто (и по-лесно), тъй като работният обект не трябва да се тревожи за красивата си малка глава за това кой може да го гледа. И наблюдаваните обекти не трябва да се притесняват за съответствие с някакъв специален протокол.

person Fruity Geek    schedule 30.01.2013
comment
да Apple изглежда се движи в тази посока, за да комуникира състояние в обекти като NSOperationQueue и да резервира делегиране, когато всъщност искате да се намесите и да промените/разширите функционалността без подкласове. - person Fruity Geek; 31.01.2013

Елегантното и лесно решение е просто да добавите базиран на блок метод към вашия Delegator (напр. чрез категория). Знам, че казахте, че не можете да направите това, но трябва да признаем, че всяко друго решение, базирано на блокове, при което създавате нови класове, за да постигнете желания ефект, се проваля на теста за елегантност.

Като казах това, ако отчаяно се нуждаете от базирани на блокове методи и не можете да разширите Delegator, тогава бих предпочел опция 2, освен вместо да правя тези методи на класа, да ги направя методи за екземпляри и да накарам Blocker да инстанцира Delegator и да дефинира обвиващи методи, така че класовете, които биха използвали Delegator, сега могат да използват Blocker, но с completion блокове, вместо да делегират обратни извиквания. И класът, който преди това е инстанцирал Delegator, сега може да инстанцира Blocker вместо това.

person Rob    schedule 30.01.2013