2015-03-19 5 views
5

Я совершенно новый для Objective-C & должен динамически изменять значение

@property (strong, nonatomic) NSMutableArray *allCategories

изнутри AFHTTPRequestOperationManager в success блоке.
[self.allCategories addObject:tempObject];
не изменяет значение allCategories при повторении в петле.

Эта переменная была инициализирована как
self.allCategories = [[NSMutableArray alloc]init];
in viewDidLoad.Как изменить нелокальную (глобальную) переменную изнутри блока?

Я также попытался создать временную переменную как __block NSMutableArray *tempCategories = [[NSMutableArray alloc]init]; перед тем, как начать AFHTTPRequestOperationManager объект. tempCategories даже не сохраняет свою ценность.

Не могу понять, что происходит.

Редактировать
Извините за неудобства
viewDidLoad имеет следующий код
self.allCategories = [[NSMutableArray alloc]init];
[self loadData];

Вот код

-(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; 
} 

Вот выходной формы NSLog:

2015-03-19 18: 27: 17.845 MyProject [4011 : 121268] viewDidLoad
2015-03-19 18: 27: 18.133 MyProject [4011: 121268] tempCategories count 0
2015-03-19 18: 27: 18.136 MyProject [4011: 121268] numberOfRowsInSection count
2015-03-19 18: 27: 18,137 MyProject [4011: сто двадцать одна тысяча двести шестьдесят-восемь] Количество numberOfRowsInSection 0
2015-03-19 18: 27: 19,019 MyProject [4011: 121268] кол категории 20

, когда loadData отделки allCategories не имеет данные в нем (ноль).

+0

Можете ли вы разместить код? – jakedunc

+0

Вы не предоставили достаточно информации. Почему вы думаете, что это не изменение ценностей? Отправьте код, который выполняет вызов вашего AFHTTPRequestOperationManager, плюс код, в котором вы заключаете, что вызов addObject ничего не делает. Я предполагаю, что вы не понимаете, как работают блоки завершения async, и ожидаете, что значение будет изменено, как только вы сделаете вызов. –

+0

Будьте осторожны. Вы не можете быть уверены в том, из какого потока возвращается ваш блок завершения, а это значит, что вам может понадобиться каким-то образом сделать ваш массив доступным к потоку. Это одна из причин, почему глобальные переменные в асинхронном приложении не идеальны. – damian

ответ

0

Попробуйте это:

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

У меня была та же проблема, несколько дней назад. Моя проблема заключалась в том, что мой массив выглядит нулевым, распределение массивов в методе viewdidload может быть запросом вашего запроса перед viewDidLoad. Проверьте его с помощью отладки, если вы видите, что массив равен nill, а затем распределите массив в другом месте. P.S: Я не эксперт, но может быть, это та же проблема со мной.

0

NSMutableArray со следующей строкой.

@property (nonatomic, strong) NSMutableArray * arrData; 

initialize в viewDidLoad

- (void)viewDidLoad { 

    [super viewDidLoad]; 

    self.arrData = [NSMutableArray array]; 
} 

вызова следующий метод с любым UIButton action для см 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

что такое 'GlobalManager' – Smarto

4

Насколько я знаю, он должен работать таким образом .. Вы уверены, что ваш успех блок вызывается до того, как вы проверите содержимое allCategories?

Успех блок работы асинхронно, что означает, что будет выполняться только тогда, когда RequestOperation завершается (что может занять много времени, если вы скачиваете что-то большое)

Если вы пытаетесь получить значение allCategoriesдо блок успеха выполнен, вы не получите то, что ожидаете. Я бы рекомендовал использовать контрольные точки или NSLog в вашем блоке успеха, чтобы убедиться, что он был выполнен, когда вы думаете, что он это делает.

например

... 
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:

Как я, хотя, вы возвращаете значение перед тем, как был установлен с помощью асинхронной операции, чтобы вернуть значение из асинхронной операции я хотел бы предложить взглянуть к этому answer и this один. Также вы должны прочитать немного о том, как работает асинхронная работа.

В основном, что вы хотите делать с асинхронными операциями/задачами, убедитесь, что значение будет доступно, если вы хотите его использовать. Основная проблема заключается в том, что вы не знаете , когда значение будет установлено, но вы можете убедиться, что что вы хотите делать, когда он установлен.

Чтобы сделать это, вы можете создать простой метод с блоком завершения пользовательского

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

Между тем в главном методе вы называете

[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 
    }]; 
Смежные вопросы