Domanda

Ho una domanda. Forse 2 domande.

Primo si riferisce a questo pezzo di codice:

-(void)isLoggedIn {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];
}
.

Vorrei che questo metodo non sia un vuoto, vorrei che restituisca un bool o qualcosa che posso usare come: l'utente è loggato> ok fai qualcosa da qualche parte nell'app; L'utente non è loggato> OK richiedi l'utente a una schermata in cui può introdurre le sue credenziali e accedere.

La seconda domanda è correlata a questo pezzo di codice:

-(void)detail {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUser];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];
}
.

Vorrei che questo metodo mi renda un NSarray con l'analizzato JSON, che posso usare ovunque voglio.

Questi metodi sono contenuti in un modello chiamato NetworkModel (Nsobject Subclass). Mi sto solo chiedendo perché dovrei fare tutto dentro i blocchi. Dovrei avere pezzi interagendo con la rete dappertutto, e non organizzato in un unico luogo / classe unico. C'è un modo per farlo. Non voglio avere 5 righe di richieste ogni viewcontroller. Voglio definire i metodi che posso chiamare da qualsiasi viewcontroller (ovviamente importando i file di intestazione dove necessario).

Qualche suggerimento? Grazie a consigli!

È stato utile?

Soluzione

Puoi farlo con 2 approcci, si modifica i tuoi metodi per poter utilizzare blocchi o utilizzare un semaforo per attendere la richiesta ASYNC:

con semaforo (il modo brutto)

-(BOOL)isLoggedIn {

__block BOOL isLoggedIn;
 dispatch_semaphore_t waiter = dispatch_semaphore_create(0);

NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
    isLoggedIn = YES;
    dispatch_semaphore_signal(waiter);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
    isLoggedIn = NO;
    dispatch_semaphore_signal(waiter);

}];

dispatch_group_wait(waiter, DISPATCH_TIME_FOREVER);
return isLoggedIn;
}
.

Il modo giusto per farlo

-(void)isLoggedIn:(void(^)(BOOL isLoggedIn))completionBlock {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
    completionBlock(YES);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
    completionBlock(NO);
}];
}
.

Per la tua seconda domanda, è possibile impostare una variabile di blocco sulla classe di rete che verrà chiamata quando la richiesta è completata o fallisce.

Comunque penso che non sia abbastanza familiare con i blocchi (a causa della tua seconda domanda) e penso che dopo alcuni blocchi inizierai a piacerli e vedrai che il codice non è complicato se hai piccoli snippeti di codiceCiò esegue la richiesta e l'analisi, vedrai anche che è così facile debug e trovare i problemi, intendo, questo era anche il mio caso quando ho iniziato a lavorare con blocchi.

Utilizzo di una variabile di blocco

@interface YourNetworkClass:NSObject {
void(^resultHandlerBlock)(NSArray *results); //this block has as param a NSArray, you can change it to whatever you want
}

-(void)setResultHandlerBlock:(void(^)(NSArray *array))handlerBlock;

@implementation YourNetworkClass

-(void)setResultHandlerBlock:(void(^)(NSArray *array))handlerBlock {
resultHandlerBlock = block;
}

-(void)anotherMethodThatDoesNetworkOperationsAndReturnsAnArray {
 ....
 resultHandlerBlock(arrayOfResults);
}


@interface AViewControllerThatUseNetwork: UIViewController {
}

@implementation AViewControllerThatUseNetwork 

-(void)initNetworkClass {
  YourNetworkClass *networkClass = [[YourNetworkClass alloc] init]; //or other init methods
  [networkClass setResultHandlerBlock:^(NSArray *results) {
   //do whatever you want with the array
}];
}
.

Altri suggerimenti

Ho chiesto qualcosa di simile a una volta indietro.Credo che troverai la tua soluzione lì. Passing Blocks a un metodo Afnetworking?

In generale, dovrai cambiare il modo in cui si ritiene che dovresti ottenere i dati da "se registrati in restituzione" per "controllare se posso accedere, se ciò non riesce a fare qualcosa all'interno del blocco AFNetworking.

.

Il link sopra risponde anche alla tua seconda domanda.

I tuoi metodi dovrebbero prendere un blocco (o due) che verranno eseguiti dai blocchi di successo di AFNetworking (o errore).Questo approccio abbraccia la natura asincrona di ciò che stai cercando di fare.Non è possibile aggiungere valori di ritorno ai metodi a causa di questa asincronicità.


.

Quindi, cambieresti il tuo metodo per:

-(void)isLoggedInWithCompletion:(LoginCompletionBlock)completion {
    ...

    [manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"JSON: %@", responseObject);
        completion(/* whatever parameters your block specifies */);
    } ...
}
.

Allora, piccolo aggiornamento sulla situazione (grazie a tutti i preziosi suggerimenti ... grazie a Guys!). Ora il mio codice sembra questo (nella mia NetworkModel.m, ovviamente ho aggiunto il metodo a NetworkModel.h in modo che io possa chiamarlo ovunque):

-(void)isLoggedIn:(void(^)(BOOL isLoggedIn))completionBlock {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
    if ([[NSString stringWithFormat:@"%@", responseObject] isEqualToString:@"true"]) {
        completionBlock(YES);
    } else {
       completionBlock(NO);
    }
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
    completionBlock(NO);
}];
}
.

Nel mio AppDelegate.h Ho incluso la mia NetworkModel.h e nel mio AppDelegate.m Ora ho il seguente codice:

[[self model] isLoggedIn:^(BOOL isLoggedIn) {
    if (isLoggedIn == YES) {
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"Start01"];
        [self.window setRootViewController:controller];
    } else {
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"Start00"];
        [self.window setRootViewController:controller];
    }    
}];
.

E funziona bene. Ma ora ho un'altra domanda su questo. Quando eseguo l'app, c'è qualcosa di strano che succede. Non appena recupera le informazioni sullo stato del login dell'utente, salta da VC (il controller InitialView Designated - Start00 sul mio storyboard) in VC (LogedInvc - Start01 sul mio storyboard). C'è un modo per non mostrare questo kinda saltare all'utente? O questo è un comportamento normale? Ora l'utente vede per un secondo il primo schermo e poi lo schermo dovrebbe effettivamente vedere (perché ha effettuato l'accesso).

Ma immagino il modo più semplice per lavorare con i blocchi e tutto questo è quello di usarli proprio dove ho bisogno. Invece di cercare di incapsularli in metodi o classi o qualsiasi altra cosa. Non appena i dati sono lì, farò quello che ho, direttamente all'interno del successo o del blocco del fallimento. Sto pensando giusto?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top