Estoy escribiendo el middleware para una aplicación de cacao, y estoy debatiendo sobre cómo exactamente diseñar callbacks para muchos procesos de larga ejecución.Cocoa Callback Design: Best Practice
Cuando la interfaz de usuario llamará a una función que se ejecuta durante mucho tiempo, es necesario proporcionar un delegado para permitir al menos:
- Informe de éxito (con valor de retorno)
- Informe de fallos (con el valor de error)
- Informe de Progreso (terminado, total esperado)
he intentado algunas técnicas en el pasado, se muestra a continuación
@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
Para las opciones 1, la pregunta es cómo redactar la respuesta del delegado. La primera manera que consideré es (los nombres de las funciones son mínimas por simplicidad)
//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
En mi experiencia, opción de devolución de llamada 1 usando un protocolo genérico era difícil de usar ya que si una clase quería ser una devolución de llamada para operaciones múltiples no pudo distinguir qué devolución de llamada estaba recibiendo.
La opción de devolución de llamada2 era engorrosa de usar y no se sentía natural de usar. Además, si el protocolo se extendió, sería necesario modificar cada llamada.
devolución de llamada Opción 1 usando un protocolo específicopara cada proceso parece ser el método más fácil de leer y escalable, sin embargo me pregunto si hacer un nuevo protocolo para cada función es demasiado prolijo (Di un objeto dado tiene 10+ tales 'operaciones largas', luego 10 protocolos diferentes).
¿Qué conclusiones han llegado a otras personas al implementar dichos diseños?
--edit: En respuesta a la respuesta de Dave DeLong
tengo tres clases que tienen '' operaciones largas, no de las operaciones en cada clase o entre clases están muy relacionados. Algunas son solicitudes de recursos de red, otras son solicitudes de procesamiento largas.
--edit: Una nota al margen, me parece que tienen un problema en el que no puedo invocar selectores bucle de ejecución para los mensajes que tienen más de un argumento. ¿Es esto una limitación de diseño o hay una forma de evitar esto?
Por ejemplo, tengo un mensaje tal como - (id) someMessage: (id) otherData value1: (id) VALUE2 MoreData: (id) Value3
Las funciones performSelector qué cola Runloop de no apoyan dichos selectores .
Acepto que nombrar explícitamente las devoluciones de llamada, aunque sea detallado, conduce a una mejor legibilidad. Todavía no he leído en 'bloques', pero se ven mucho más flexibles que los selectores. Siempre sentí que el sobrecargado de un parámetro/dos parámetros realiza funciones de selector donde se produce un truco y un resultado de mal diseño. – Akusete