2010-12-14 24 views
0

J'essaie de faire une barre de recherche pour rechercher des choses que je reçois en utilisant NSURLConnection. maintenant, si je recherche quelque chose, cette chaîne est renvoyée comme une URL avec une requête asynchrone, ce qui me donne des données.Recherche à l'aide de NSOperation

NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0]; 
    [theConnection cancel]; 
    [theConnection release]; 

theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self]; 

Ces données sont analysées et quand il réussit je poste une notification

-(void)connectionDidFinishLoading:(NSURLConnection *)connection 
    {  
     xmlParser = [[NSXMLParser alloc] data]; 
     [xmlParser setDelegate:xmlGeocoder]; 
     BOOL success = [xmlParser parse]; 

     if(success == YES){ 
      NSLog(@"No Errors"); 

      [[NSNotificationCenter defaultCenter] postNotificationName:@"getArray" object:self]; 

     }else{ 
      NSLog(@"Error Error Error!!!"); 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"failToGetArray" object:self]; 
     } 
} 

et mon searchresultsTableView est rechargé. Toutes ces méthodes dépendent l'une de l'autre, donc B ne peut pas être exécuté, quand A est encore occupé. J'utilise NSNotificationCenter pour leur dire d'exécuter ce code.

Mais je veux essayer NSOperation et je n'ai aucune idée de comment implémenter cela. Dois-je mettre mes demandes de recherche dans une opération ou dans chaque méthode que j'utilise? Est-ce que quelqu'un peut me donner un exemple de code pour me donner l'idée de comment cela devrait être fait? Merci d'avance ...

Répondre

2

NSOperation est très utile. Pour l'utiliser, vous étendez NSOperation et remplacez la méthode "main". Dans la méthode principale, vous effectuez vos calculs/requêtes Web, etc. NSOperation est donc idéal pour les tâches que vous pouvez suivre en quelques étapes simples. Après chaque étape, vous testez si tout va bien et passez à l'étape suivante. Une fois cela fait, vous pouvez simplement instancier votre NSOperation personnalisé et le remettre à un objet NSOperationQueue et il s'occupera de l'enfilage, du démarrage, de l'arrêt du nettoyage etc.

Dans l'exemple ci-dessous, j'ai écrit un protocole à manipuler l'achèvement de la tâche, je vous conseille de prendre cette approche au lieu d'utiliser la notification - sauf si vous avez plusieurs objets qui doivent être notifiés instantanément.

Faire une nouvelle classe qui étend la classe NSOperation:

//This object takes a "searchTerm" and waits to be "started". 
#import <Foundation/Foundation.h> 

@protocol ISSearchOperationDelegate 

- (void) searchDataReady:(NSArray*) searchResult; 

@end 


@interface ISSearchOperation : NSOperation { 

    id <ISSearchOperationDelegate> delegate; 

    NSString *searchTerm; 
} 

@property(nonatomic, retain) NSString *searchTerm; 

@property(nonatomic, assign) id delegate; 

- (id) initWithSearchTerm:(NSString*) searchString; 

@end 

Lorsqu'un objet extension NSOperation est ajouté à un NSOperationQueue, l'objet de file d'attente essaie d'appeler une méthode « principale » sur le NSOperation, vous devez par conséquent, enveloppez votre tâche dans cette méthode. (notez qu'après chaque sous-tâche terminée, je teste si elle s'est bien déroulée et "return" sinon.) La classe NSOperation a une propriété appelée isCancelled Cette propriété peut être définie par NSOperationQueue, donc vous devez également tester si qui a été défini lors de votre fin de principal pour résumer, vous testez de l'intérieur du principal si chaque étape est allé vous vouliez et vous tester si quelque chose à l'extérieur a annulé votre tâche):..

- (id) initWithSearchTerm:(NSString*) searchString { 

    if (self = [super init]) { 

     [self setSearchTerm:searchString]; 
    } 

    return self; 
} 

- (void) main { 

    [self performSelector:@selector(timeOut) withObject:nil afterDelay:4.0]; 
    if ([self isCancelled]) return; 
    NSData *resultData = [self searchWebServiceForString:self.searchTerm]; 
    if (resultData == nil) return; 
    if ([self isCancelled]) return; 
    NSArray *result = [self parseJSONResult:resultData];  
    if ([self isCancelled]) return; 
    if (result == nil) return; 
    [NSObject cancelPreviousPerformRequestsWithTarget:self]; 
    [delegate performSelectorOnMainThread:@selector(searchDataReady:) withObject:result waitUntilDone:YES]; 
} 

// Je n'ai pas copié l'implémentation de toutes les méthodes que j'appelle pendant main, mais j'espère que vous comprenez qu'il s'agit juste de "tâches" qui doivent être complétées avec succès avant que la prochaine sous-tâche puisse être calculée. Donc d'abord, j'ai mis un test de délai d'attente, puis je reçois mes données du service Web, puis je l'analyse.

Ok pour que tout cela se passe, vous avez besoin d'une file d'attente.

Ainsi, dans la classe que vous voulez être le délégué pour cette opération vous faites ceci:

quelque part mis en place une file d'attente:

NSOperationQueue *q = [[NSOperationQueue alloc] init]; 
[self setQueue:q]; 
[q release]; 


- (void) doSearch:(NSString*) searchString { 

    [queue cancelAllOperations]; 
    ISSearchOperation *searchOperation = [[ISSearchOperation alloc] initWithSearchTerm:searchString]; 
    [searchOperation setDelegate:self]; 
    [queue addOperation:searchOperation]; //this makes the NSOperationQueue call the main method in the NSOperation 
    [searchOperation release]; 
} 

//the delegate method called from inside the NSOperation 
- (void) searchDataReady:(NSArray*) results { 

    //Data is here! 
} 

Certains des avantages avec NSOperations est que du point de l'appelant de vue, nous faisons simplement un objet, définir un délégué, attendez la réponse. Mais dans les coulisses, une série de tâches threadées qui peuvent être annulées à tout moment est exécutée, et d'une manière qui peut gérer si les tâches enfilées échouent. Comme vous pouvez le voir dans la méthode doSearch, il commence par annuler toutes les opérations précédentes, je l'ai fait dans une application où je chercherais un service Web chaque fois qu'un utilisateur a tapé une lettre dans un mot. Cela signifie que si l'utilisateur recherchait "bonjour monde" - je ferais une recherche pour "h", puis "il", puis "hel", puis l'enfer ", puis" bonjour "etc Je voulais arrêter et nettoyer la tâche "h" dès que l'utilisateur a tapé le "e", car il était alors obsolète J'ai découvert que NSOperation était le seul moyen qui donnait la réactivité du threading et aucun des désordres qui accompagnent habituellement de nombreux threads les uns sur les autres

J'espère que vous pouvez l'utiliser pour commencer :)