2015-03-19 18 views
5

Sono abbastanza nuovo per Objective-C & avere per modificare dinamicamente il valore di

@property (strong, nonatomic) NSMutableArray *allCategories

dall'interno di AFHTTPRequestOperationManager in success blocco.
[self.allCategories addObject:tempObject];
non modifica il valore di allCategories durante l'iterazione in un ciclo.

La variabile è stata inizializzata come
self.allCategories = [[NSMutableArray alloc]init];
in viewDidLoad.Come modificare una variabile non globale (globale) dall'interno di un blocco?

Ho anche provato a creare una variabile temporanea come __block NSMutableArray *tempCategories = [[NSMutableArray alloc]init]; prima di iniziare l'oggetto AFHTTPRequestOperationManager. tempCategories non mantiene il suo valore.

Non riesco a capire cosa sta succedendo.

Modifica
Siamo spiacenti per il disagio
viewDidLoad ha il seguente codice
self.allCategories = [[NSMutableArray alloc]init];
[self loadData];

Ecco il codice

-(NSMutableArray *)loadData 
{ 
    __block NSMutableArray *tempCategories = [[NSMutableArray alloc]init]; 

    manager = [AFHTTPRequestOperationManager manager]; 

    [manager GET:kAPICategoryList 
     parameters:nil 
     success:^(AFHTTPRequestOperation *operation, id responseObject) { 

      // downcast id to NSMutableDictionary 
      NSMutableDictionary *json = (NSMutableDictionary *)responseObject; 

      // check if dictionary is non nil has at least 1 element 
      if (json != nil && [json count] >= 1) { 

       // NSLog(@"json:\t%@", json); 

       // check json is non nil & has success message 
       if ([json objectForKey:kAPIKeyCategoryRoot] != nil) { 

        NSArray *arrCategoriesRoot = [json objectForKey:kAPIKeyCategoryRoot]; 

        // check categories has some data 
        if (arrCategoriesRoot.count >= 1) { 

         for (int i = 0; i < arrCategoriesRoot.count; i++) { 

          SomeModel *pCategory; 

          NSDictionary *dctCategorySingle = [arrCategoriesRoot objectAtIndex:i]; 

          // check category has sub category 
          if ([dctCategorySingle objectForKey:kAPIKeyCategorySubCategory] != nil) { 
           // create category with sub category 
           pCategory = [[SomeModel alloc]initWithSubCategorisedCategoryID:[dctCategorySingle objectForKey:kAPIKeyCategoryID] 
                           name:[dctCategorySingle objectForKey:kAPIKeyCategoryName] 
                          image:kIMGCategoryDefault 
                         subCategory:[dctCategorySingle objectForKey:kAPIKeyCategorySubCategory]]; 
          } else{ 
           // create just a category 
           pCategory = [[SomeModel alloc]initWithCategoryID:[dctCategorySingle objectForKey:kAPIKeyCategoryID] 
                       name:[dctCategorySingle objectForKey:kAPIKeyCategoryName] 
                       image:kIMGCategoryDefault]; 
          } // else just 
          [tempCategories addObject:pCategory]; 
          [_allCategories addObject:pCategory]; 
         } // for 
         NSLog(@"categories count %lu", [self.allCategories count]); 
        } // if count >= 1 
       } 
       else if ([json objectForKey:kAPIRespMsgCategoryFetchErrKey] != nil) { 
        [Utility showAlertWithTitle:kAPIRespMsgCategoryFetchErrKey 
             message:[json objectForKey:kAPIRespMsgCategoryFetchErrVal] 
              button:kMsgButtonOkayTtl]; 
       } 
      } else { 
       // error in login => enable login 
       NSLog(@"%@", kMsgNetworkEmptyJSON); 
      } 
     } 
    // network error 
     failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
      NSLog(@"error %@", [error localizedDescription]); 
     }]; 
    NSLog(@"tempCategories count %lu", [tempCategories count]); 
    return tempCategories; 
} 

Ecco il modulo di uscita NSLog:

2015/03/19 18: 27: 17,845 MyProject [4011 : 121268] viewDidLoad
2015-03-19 18: 27: 18.133 MyProject [4011: 121268] tempCategories conteggio 0
2015-03-19 18: 27: 18.136 MyProject [4011: 121268] numberOfRowsInSection conteggio 0
2015/03/19 18: 27: 18,137 MyProject [4011: 121268] conteggio numberOfRowsInSection 0
2015/03/19 18: 27: 19,019 MyProject [4011: 121268] contano le categorie 20

quando loadData finiture allCategories non ha dati in esso (nullo).

+0

Potete per favore inserire il codice? – jakedunc

+0

Non hai fornito abbastanza informazioni. Cosa ti fa pensare che non stia cambiando i valori? Pubblica il codice che effettua la chiamata al tuo AFHTTPRequestOperationManager, più il codice dove concludi che la chiamata a addObject non sta facendo nulla. La mia ipotesi è che non si capisce come funzionano i blocchi di completamento asincrono e si aspetta che il valore venga modificato non appena si effettua la chiamata. –

+0

Fai attenzione. Non si può essere sicuri di quale thread il blocco di completamento stia tornando, il che significa che potrebbe essere necessario in qualche modo rendere l'accesso al thread-safe. Questo è uno dei motivi per cui avere variabili globali in un'applicazione asincrona non è l'ideale. – damian

risposta

0

Prova questo:

dispatch_async(dispatch_get_main_queue(), ^{ 
[self.allCategories addObject:tempObject]; 
}); 
0

Ho avuto lo stesso problema qualche giorno fa. Il mio problema era che la mia matrice sembrava nulla, le allocazioni di array nel metodo viewdidload potrebbero essere la tua richiesta eseguita prima di viewDidLoad. Controllalo con debug se vedi che l'array è nill, quindi assegna un array a un posto diverso. P.S: Non sono esperto ma potrebbe essere lo stesso problema con me.

0

Definire NSMutableArray con la seguente riga.

@property (nonatomic, strong) NSMutableArray * arrData; 

initialize in viewDidLoad

- (void)viewDidLoad { 

    [super viewDidLoad]; 

    self.arrData = [NSMutableArray array]; 
} 

chiamata seguente metodo con qualsiasi UIButton action per vedere output OR working behavior

- (void) TestMethod { 

    dispatch_queue_t queue = dispatch_queue_create("myQueue", 0); 

    dispatch_async(queue, ^{ 
     AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL urlWithEncoding:@"https://www.google.co.in/?gws_rd=ssl"]]; 
     [httpClient registerHTTPOperationClass:[AFJSONRequestOperation class]]; 
     [httpClient setDefaultHeader:@"Accept" value:@"application/json"]; 
     [httpClient setParameterEncoding:AFJSONParameterEncoding]; 
     NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:@"" parameters:nil]; 
     [request setTimeoutInterval:180]; 
     [AFJSONRequestOperation addAcceptableContentTypes:[NSSet setWithObject:@"text/html"]]; 
     dispatch_semaphore_t sema = dispatch_semaphore_create(0); 

     AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) 
              { 
               [self.arrData addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"test",@"t3da",@"adsf",@"afds", nil]]; 
               dispatch_semaphore_signal(sema); 
              } failure:^ (NSURLRequest *request, NSURLResponse *response, NSError *error, id json){ 

               [self.arrData addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"test",@"t3da",@"adsf",@"afds", nil]]; 
               dispatch_semaphore_signal(sema); 
              }]; 

     [operation start]; 

     dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 
     DLog(@"arrData = %@",self.arrData); 
    }); 
} 
+0

cos'è 'GlobalManager' – Smarto

4

Per quanto ne so dovrebbe funzionare in questo modo .. sono sicuro che il tuo successo il blocco viene chiamato prima di controllare il contenuto di allCategories?

Un'opera blocco di successo in modo asincrono, il che significa che sarà eseguito solo quando il RequestOperation è completato (che può richiedere molto tempo se si sta scaricando qualcosa di grosso)

Se si sta cercando di ottenere il valore di allCategoriesprima del il blocco di successo viene eseguito non si ottiene ciò che si aspetta. Ti consiglio di utilizzare i punti di interruzione o NSLog sul tuo blocco di successo per vedere se è stato eseguito quando pensi che lo stia facendo.

esempio

... 
successBlock:^(AFHTTPRequestOperation *operation, id responseObject) 
{ 
    NSLog(@"Success"); 
    [self.allCategories addObject:tempObject] 
    }]; //End of request 

[operation start]; //Begin executing the AFHTTPOperation 

NSLog("%@",self.allCategories.description); //probably nil or empty 
//since the success block hasn't been called yet 

EDIT:

Come ho però, si restituisce un valore prima è stato impostato con l'operazione asincrona, per restituire un valore da un'operazione asincrona vorrei suggerire di dare un'occhiata a questo answer e this uno. Dovresti anche leggere un po 'di come funziona il task asincrono.

In pratica, ciò che si desidera fare con operazioni/attività asincrone è assicurarsi che il valore sia disponibile quando si desidera utilizzarlo. Il problema principale è che non si conosce quando il valore verrà impostato, ma è possibile assicurarsi che cosa si desidera fare ogni volta che è impostato.

Per fare che è possibile creare un metodo semplice con un blocco di completamento personalizzato

- (void)myCustomMethodWithCompletionBlock: (void (^)(NSArray *))completion { 
    //Do your request 
    //... 
    successBlock:^(AFHTTPRequestOperation *operation, id responseObject) 
    { 
     NSLog(@"Success"); 
     completionBlock(allCategories); 
    }]; //End of request 
} 

Intanto nel metodo principale si chiama

[self myCustomMethodWithCompletionBlock:^(NSArray *allCategories) { 
    self.allCategories = allCategories; 
    //Do other stuff you need to with that variable since now you are 
    //sure the value will be set unless the operation failed 
    }];