简体   繁体   English

如何从块内部修改非局部(全局)变量?

[英]How to modify a non-local (global) variable from inside of a block?

I am quite new to Objective-C & have to dynamically change the value of 我是Objective-C的新手,必须动态更改

@property (strong, nonatomic) NSMutableArray *allCategories

from inside of AFHTTPRequestOperationManager in success block. AFHTTPRequestOperationManager内部进入success块。
[self.allCategories addObject:tempObject];
doesn't change the value of allCategories while iterating in a loop. 循环迭代时不会更改allCategories的值。

The variable has been initialized as 该变量已初始化为
self.allCategories = [[NSMutableArray alloc]init];
in viewDidLoad. 在viewDidLoad中。

I have also tried creating a temporary variable as __block NSMutableArray *tempCategories = [[NSMutableArray alloc]init]; 我还尝试过将临时变量创建为__block NSMutableArray *tempCategories = [[NSMutableArray alloc]init]; before initiating AFHTTPRequestOperationManager object. 在启动AFHTTPRequestOperationManager对象之前。 tempCategories doesn't even retain its value. tempCategories甚至不保留其值。

Can't figure out what's happening. 无法弄清楚发生了什么事。

Edit 编辑
Sorry for inconvenience 对造成的不便表示歉意
viewDidLoad has the following code viewDidLoad具有以下代码
self.allCategories = [[NSMutableArray alloc]init];
[self loadData];

Here's the code 这是代码

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

Here's the output form NSLog: 这是NSLog的输出形式:

2015-03-19 18:27:17.845 MyProject[4011:121268] viewDidLoad 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.133 MyProject [4011:121268] tempCategories计数0
2015-03-19 18:27:18.136 MyProject[4011:121268] numberOfRowsInSection count 0 2015-03-19 18:27:18.136 MyProject [4011:121268] numberOfRowsInSection计数0
2015-03-19 18:27:18.137 MyProject[4011:121268] numberOfRowsInSection count 0 2015-03-19 18:27:18.137 MyProject [4011:121268] numberOfRowsInSection计数0
2015-03-19 18:27:19.019 MyProject[4011:121268] categories count 20 2015-03-19 18:27:19.019 MyProject [4011:121268]类别计数20

when loadData finishes allCategories has not data in it (nil). loadData完成时,allCategories中没有数据(无)。

As far as I know it should work that way.. are you sure your success block is being called before you check the content of allCategories ? 据我所知,它应该以这种方式工作..您确定在检查所有allCategories的内容之前确定成功块已被调用吗?

A success block work asynchronously, which means it will be executed only when the RequestOperation is completed (which can take a long time if you're downloading something big) 成功块以异步方式工作,这意味着仅在RequestOperation完成时才执行(如果下载较大的文件可能会花费很长时间)

If you are trying to get the value of allCategories before the success block is executed you won't get what you're expecting. 如果您尝试执行成功块之前获取allCategories的值, allCategories您将无法获得预期的结果。 I would recommend using breakpoints or NSLog on your success block to see if it's been executed when you think it's doing it. 我建议您在成功块上使用断点或NSLog来查看它是否已在您认为正在执行时执行。

eg 例如

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

As I though, you are returning a value before is been set by the async operation, to return a value from an async operation I would suggest take a look to this answer and this one . 就像我一样,您正在返回一个由异步操作设置的before值,要从异步操作返回一个值,我建议您看一下这个答案这个 答案 Also you should read a bit of how async task work. 另外,您还应该阅读一下异步任务的工作原理。

Basically what you want to do with async operations/tasks is make sure the value will be available when you want to use it. 基本上,您要对异步操作/任务执行的操作是确保该值在您要使用时可用。 The main issue with that is that you don't know when the value will be set, but you can make sure what you want to do whenever it's set. 与主要的问题是,你不知道什么时候该值将被设置,但可以确保你想,只要它的设置做什么

To do that you can create a simple method with a custom completion block 为此,您可以创建一个带有自定义完成块的简单方法

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

Meanwhile in your main method you call 同时,在您的主要方法中,您调用

 [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
   }];

Try this: 尝试这个:

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

I had the same problem a few days ago. 几天前我遇到了同样的问题。 My problem was my array seems nil, array allocations in viewdidload method may be your request run before viewDidLoad. 我的问题是我的数组似乎为零,viewdidload方法中的数组分配可能是您的请求在viewDidLoad之前运行。 Check it with debug if you see the array is nill then alloc array different place. 如果您看到数组为零,则使用debug进行检查,然后将数组分配到其他位置。 PS: I m not expert but may be it's the same problem with me. PS:我不是专家,但可能是我遇到了同样的问题。

Define NSMutableArray with following line. 用以下行定义NSMutableArray

@property (nonatomic, strong) NSMutableArray * arrData;

initialize in viewDidLoad viewDidLoad initialize

- (void)viewDidLoad {

    [super viewDidLoad];

    self.arrData = [NSMutableArray array];
}

call following method with any UIButton action for see output OR working behavior 使用任何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);
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM