Piszę oprogramowanie pośredniczące do aplikacji kakao i zastanawiam się, jak dokładnie zaprojektować wywołania zwrotne dla wielu długotrwałych procesów.Projektowanie połączenia zwrotnego kakao: najlepsza praktyka
Kiedy UI będzie wywołać funkcję, która wykonuje przez długi czas, to musi zapewnić delegata, aby umożliwić co najmniej:
- Report of Success (z wartości zwracanej)
- Raportu Awarii (z wartości błędu)
- Raport Postępu (zakończona, oczekuje całkowity)
próbowałem kilka technik w przeszłości, poniżej
@interface MyClass {
}
//Callback Option1, delgate conforming to protocol
-(void) longRunningProcess2:(id<CallbackProtocol>) delegate;
//Callback Option2, provide a delegate and allow it to provide selectors to callback
-(void) longRunningProcess3:(id) delegate success:(SEL) s1 failure:(SEL) s2 progress:(SEL) s3
@end
W przypadku opcji 1 pytanie brzmi: jak sformułować odpowiedź delegata. Pierwszym sposobem Uważałem to (nazwy funkcji są minimalne dla uproszczenia)
//have a generic callback protocol for every function
@protocol CallbackProtocolGeneric
-(void) success:(id) returnValue;
-(void) failure:(NSError*) error;
@optional
-(void) progress:(NSInteger) completed of:(NSInteger) total;
@end
//have a separate protocol for every function
@protocol CallbackProtocolWithObjectAForOperation1
-(void) objectA:(ObjectA*) objectA operation1SucceedWithValue:(ReturnObject*) value;
-(void) objectA:(ObjectA*) objectA operation1FailedWithError:(NSError*) error;
@optional
-(void) objectA:(ObjectA*) objectA operation1didProgress:(NSInteger) completed of:(NSInteger) total;
@end
Z mojego doświadczenia wynika, opcji oddzwaniania 1 użyciu typowego protokołu był trudny w użyciu, ponieważ jeśli klasa chciał być wywołania zwrotnego dla wielu operacji, które nie były w stanie rozróżnić, który oddzwonił.
Opcja oddzwaniania2 była uciążliwa w użyciu i wydawała się nienaturalna w użyciu. Plus, jeśli protokół został przedłużony, wymagałoby modyfikacji każdego połączenia.
oddzwaniania Opcja 1 użyciu konkretny protokół dla każdego procesu wydaje się być sposób najbardziej czytelny i skalowalne, jednak zastanawiam się, czy tworzenia nowego protokołu dla każdej funkcji jest zbyt rozwlekły (Say dany obiekt ma ponad 10 takie "długie operacje", a następnie 10 różnych protokołów).
Jakie konkluzje mają inne osoby wdrażające takie projekty?
--edit: W odpowiedzi Dave Delong za odpowiedź
mam trzy klasy, które mają „” długie operacje, bez operacji w każdej klasie lub między klasami są bardzo podobne. Niektóre to żądania zasobów sieciowych, inne to długie żądania przetwarzania.
--edit: Na marginesie, wydaje mi się, że problem, gdzie nie może powoływać selektorów bieg pętli komunikatów, które mają więcej niż jeden argument. Czy jest to ograniczenie projektu, czy jest jakiś sposób obejścia tego?
Przykładowo mam komunikatów, takich jak - (ID) someMessage (ID) otherData Value1 (ID) wartość2 moreData (ID) VALUE3
Funkcje performSelector odpowiedniej kolejki runLoop nie obsługują te selektory .
Zgadzam się, że jawne nazewnictwo wywołań zwrotnych, chociaż jest pełne, prowadzi do znacznie lepszej czytelności. Nie czytałem jeszcze "bloków", ale wyglądają one znacznie elastyczniej niż selektory. Zawsze czułem, że przeciążony jeden parametr/dwa parametry wykonują funkcje selektora, gdzie hack i wynik złego projektu. – Akusete