2012-10-30 10 views
6

Sono nuovo a MKNetworkKit, ma sono stato in grado di aggiungerlo al mio progetto ed è perfettamente funzionante tranne quando si tratta di cambiamenti di raggiungibilità.L'operazione MKNetworkKit non riprende/completa quando cambia la raggiungibilità

Qui è la situazione:

  1. a disattivare Wi-Fi ed eseguire l'applicazione.
  2. Anche senza raggiungibilità, richiedo (utilizzando POST) alcuni dati creando un MKNetworkOperation dalla sottoclasse MKNetworkEngine. Proprio prima di richiedere dati, l'operazione è impostata come freezable (come da Mugunth Kumar's doc).
  3. Dopo aver abilitato WiFi, viene chiamato checkAndRestoreFrozenOperations in MKNetworkEngine e viene rilevata una operazione in sospeso (quella creata senza raggiungibilità), che tenta di accodarsi.
  4. Successivamente, il mio blocco onCompletion non viene mai chiamato.

C'è qualcosa che non capisco sulle operazioni di congelamento + raggiungibilità in MKNetworkKit? Il blocco funziona solo per le operazioni in cui la raggiungibilità cambia dopo l'avvio di una richiesta? O devo implementare la mia raggiungibilità modificata?

Questo è il codice nella sottoclasse MKNetworkEngine che crea l'operazione e avvia la richiesta. Si noti che il codice irrilevante è stato soppresso.

NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObject:@"value" forKey:@"param"]; 
MKNetworkOperation *op = [self operationWithPath:MYPATH 
              params:params 
             httpMethod:@"POST"]; 
[op setFreezable:YES]; 

[op onCompletion:^(MKNetworkOperation *completedOperation) { 
    // ... 
    // Here is where I process response and send the result to my completion block 
    // It's called when WiFi is available, but not called otherwise. 
    // ... 
} onError:^(NSError *error) { 
    // It's called when WiFi is available, but not called otherwise. 
    DLog(@"Some error"); 
}]; 

[self enqueueOperation:op]; 

return op; 
+0

Ti è istituito un host in il motore? Se si guarda a come vengono gestite le operazioni bloccate, esse non funzionano a meno che non sia definito un host per il motore. –

+0

@KenWoo Sì. Il metodo init nella mia sottoclasse del motore chiama '[super initWithHostName: ]'. – msoler

+0

@msoler Hai funzionato? Ho un problema simile – alandalusi

risposta

6

Questi sono due problemi separati: riprendi rispetto a completo.

  1. curriculum: Il meccanismo/Sblocca Fermo funziona solo se la cache è abilitata

    È necessario richiamare -useCache nelle AppDelegate -didFinishLaunchingWithOptions:

    self.networkEngine = [[MKNetworkEngine alloc] init ...]; 
    [self.networkEngine useCache]; // <- Add this line 
    
  2. completo: Il callback del completamento è non invocato al cambio di stato della rete (ovvero dopo Unfreeze)

    Eppure, se si prende l'azione (1) e inserire un punto di interruzione in MKNetworkOperation.m -checkAndRestoreFrozenOperations alla riga:

    [self enqueueOperation:pendingOperation] 
    

    troverete che viene invocato quando la connettività di rete viene ripristinata, e che in sospeso. Operazioneè il POST in sospeso. Tuttavia, poiché è stato istanziato un nuovo MKNetworkOperation (e quindi il blocco di completamento potrebbe non esistere più) il tuo blocco onCompletion non viene mai chiamato. Una soluzione possibile sarebbe utilizzare una notifica anziché una richiamata.

  3. completa correzione: Un approccio più robusto (2) che funzionerà attraverso lanci è quello di sostituire le ^{} callback blocco da NSNotifications. Registra i tuoi ascoltatori in anticipo, come nel tuo AppDelegate.Ecco le minime modifiche richieste per rendere savvy le notifiche di MKNetworkKit:

    3a. Inserire notifiche costanti nella MKNetworkOperation.h

    #define MKNetworkOperationCompletionNotification @"MKNetworkOperationCompletionNotification" 
    #define MKNetworkOperationErrorNotification @"MKNetworkOperationErrorNotification" 
    

    3b. trasmettere una notifica successo in MKNetworkOperation.m -operationSucceeded (Nota che uso postNotificationOnMainThread modo che detta notifica può essere ascoltato dal thread principale e modificare l'interfaccia utente; vedi NSOperation and NSNotificationCenter on the main thread):

    -(void) operationSucceeded { 
        NSDictionary * aUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: 
         self, NSStringFromClass([MKNetworkOperation class]), 
         nil]; 
        NSNotification * notification = [NSNotification notificationWithName:MKNetworkOperationCompletionNotification 
         object:nil 
         userInfo:aUserInfo]; 
        [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:notification]; 
        ... 
    

    3c. trasmettere una notifica fallimento in MKNetworkOperation.m -operationFailedWithError

    -(void) operationFailedWithError:(NSError*) error { 
        self.error = error; 
        NSDictionary * aUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: 
         self, NSStringFromClass([MKNetworkOperation class]), 
         error, NSStringFromClass([NSError class]), 
         nil]; 
        NSNotification * notification = [NSNotification notificationWithName:MKNetworkOperationErrorNotification 
         object:nil 
         userInfo:aUserInfo]; 
    
        [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:notification]; 
        ... 
    

    3d. Registra un oggetto piuttosto persistente, come l'AppDelegate, come ascoltatore (Non dimenticare di annullare la registrazione):

    // Listen to POST changes 
        NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; 
        [defaultCenter addObserver:self 
         selector:@selector(mkNetworkOperationCompletionNotification:) 
         name:MKNetworkOperationCompletionNotification 
         object:nil]; 
        [defaultCenter addObserver:self 
         selector:@selector(mkNetworkOperationErrorNotification:) 
         name:MKNetworkOperationErrorNotification 
         object:nil]; 
    

    3e. Codice di esempio di ciò che l'ascoltatore potrebbe assomigliare:

    - (void)mkNetworkOperationCompletionNotification:(NSNotification*)notification { 
        MKNetworkOperation *operation = [[notification userInfo] 
         objectForKey:NSStringFromClass([MKNetworkOperation class])]; 
        NSLog(@"operationSucceeded: %@", [operation responseString]); 
    } 
    
    - (void)mkNetworkOperationErrorNotification:(NSNotification*)notification { 
        NSError * error = [[notification userInfo] objectForKey:NSStringFromClass([NSError class])]; 
        NSLog(@"operationFailedWithError: %@", [error localizedDescription]); 
    } 
    

fare questo, il gioco è fatto. X.

(A cura di togliere le modifiche inutili suggerite per MKNetworkOperation.h in risposta precedente, e il paragrafo 3. aggiunto per mostrare come superare le^{} limitazioni.)

+1

Grazie mille per la tua risposta dettagliata, @gothicdev. – msoler

Problemi correlati