2010-05-11 11 views
1

Je développe NSOperation (appelez-le A) qui contient NSOperationQueue pour d'autres NSOperations (qui est une autre classe étendue différente de A, appelez ces opérations B). Lorsque l'opération A est en cours (exécution des opérations B), comment puis-je appeler une fonction/méthode spécifique sur l'opération A lorsqu'un certain événement a lieu sur les opérations B? Par exemple chaque opération B qui le termine appelle une fonction sur l'opération A qui se retourne?Effectuer le sélecteur sur le parent NSOperation

* Nested NSOperation et NSOperationQueue (s)

espoir ce code mockup pseudo peut aider à dessiner l'image.

//My classes extended from NSOperation 

NSOperation ClassA 

NSOperation ClassB 

//MainApp 

-(void)applicationDidFinishLaunching:(NSNotification *)aNotification { 

    ClassA A1; 

    ClassA A2; 

    NSOperationQueue Queue; 
    Queue AddOperation: A1; 
    Queue AddOperation: A2; 


} 

//Main of ClassA 

-(void)main { 

    ClassB B1; 

    ClassB B2; 

    NSOperationQueue Queue; 
    Queue AddOperation: B1; 
    Queue AddOperation: B2; 

} 

//Main of ClassB 

-(void)main { 

    //Do some work and when done call selector on ClassA above 

} 
+3

Sons alambiqués et terribles. Qu'essayez-vous de faire? –

+0

Un pseudo-code pourrait rendre le problème plus clair. –

+0

@Dave DeLong: Ceci est une expérience de codage. L'application prend le nombre d'URL qui pointent vers un fichier de téléchargement sur un serveur. NSOperation est créé pour chaque URL, la taille du fichier est déterminée et divisée en blocs. A partir de là, chaque fragment du fichier est téléchargé par NSOperation séparé. Cela a-t-il du sens. – MikeM

Répondre

1

NSOperation dispose d'un mécanisme pour enregistrer les dépendances. Voir NSOperation's documentation.

Séparons le travail de votre A fait: AX: frai B s et AY: la collecte des données dans B. Je pense qu'il est préférable de concevoir B afin qu'il puisse être utilisé sans A. Laissez-B il suffit de télécharger les données et le maintenir dans la propriété data, comme dans

@interface B:NSOperation{ 
} 
-initWithURL:(NSURL*)url atPosition:(NSUInteger)position; 
@property (readonly)NSData* data; 
@end; 

A ne doit pas avoir sa propre file d'attente, un par objet. Générer B ne prend pas beaucoup de temps non plus, donc AX ne doit pas nécessairement être une opération.

Alors, je voudrais simplement définir les opérations AY et B, préparer une seule file d'attente, et exécuter quelque chose comme

NSOperationQueue* queue=...; 
NSArray* urls = ... ; 
for(NSURL* url in urls){ 
    AY* ay=[[AY alloc] init]; 
    for(chunks in url){ 
     B* b= an instance for B for the chunk in url 
     [ay addDependency:b]; 
     [queue addOperation:b]; 
    } 
    [queue addOperation:ay]; 
} 

Ensuite, dans l » principale AY, vous pouvez

-main{ 
     NSArray*bs=[self dependencies]; 
     for(B*b in bs){ 
      NSData* data=b.data; 
     } 
} 

Remarque que, grâce aux dépendances, il est garanti que lorsque AY est exécuté, tous les B ont terminé leur opération. De cette façon, l'implémentation de B est indépendante de A.

+0

Ne pense pas que c'est exactement ce que je cherchais. Puisque l'objet A (qui est l'extension de NSOperation) engendre plusieurs autres objets Bs (qui sont aussi des extensions de NSOperation) et que l'objet Bs télécharge un morceau de fichier, je veux que chaque objet B contacte leur objet parent A et leur dise ce nombre d'octets du fichier "(ou tout autre message). – MikeM

+0

Je suggère de diviser la tâche de l'objet A en AX: engendrer B et AY: collecter les données de B. Je vais modifier ma réponse en conséquence. – Yuji

0

J'ai écrit une classe appelée MXSuperOperation pour imbriquer NSOperations pour l'application sur laquelle je travaille actuellement. Je l'ai posté ici:

https://gist.github.com/joerick/e4d2c99a2127715d9bc3

MXSuperOperation et ajouter sous-catégorie dans la sous-opérations -mainError: méthode.

@interface OperationA : MXSuperOperation 

@end 

@implementation OperationA 

- (BOOL)mainError:(NSError **)error 
{ 
    [self addSuboperation:[OperationB new]]; 
    [self addSuboperation:[OperationB new]]; 

    return YES; 
} 

@end 

ensuite pour exécuter quelque chose à la fin de tous les OperationB s, vous pouvez ajouter un completionBlock à OPÉRATIONNEL:

[operationA setCompletionBlockWithSuccess:^(id operation) { 
    NSLog(@"success"); 
} failure:^(id operation, NSError *error) { 
    NSLog(@"error %@", error); 
}]; 

Ou vous pouvez mettre en œuvre -endError: en OPÉRATIONNEL (selon la façon dont vous voulez structurer le code).

Notez que cette classe est construite sur une sous-classe NSOperation que j'ai appelée MXCheckedOperation, qui codifie simplement les succès/échecs et les rapports d'erreurs pour les NSOperations.