AFNetworking 将 NSDictionary 作为单个数组值发送,而不是作为完整对象发送

Posted

技术标签:

【中文标题】AFNetworking 将 NSDictionary 作为单个数组值发送,而不是作为完整对象发送【英文标题】:AFNetworking sending NSDictionary as single array values instead of sending them as complete objects 【发布时间】:2013-09-09 18:09:43 【问题描述】:

我正在尝试发送一个NSArray *appData,因为它是一个包含NSDictionaryNSArray请参阅下面的数据布局)但是当我在@987654325 中收到Array @NSDictionary 中的所有值都作为单个数组发送,并且与发送时的格式不同(请参阅下面的 php 日志数据)。

NSDictionary* params 中的所有其他值都可以正确发送和接收。

这是我的代码中的错误还是问题?如果后者是问题,我做错了什么?

注意:我使用的是最新版本的AFNetworking

编辑: 作为@dpassage 答案的结果,我进行了编辑以包含更广泛的测试并将信息作为form-data 发送。测试的有趣之处在于,发送到服务器的@"test" 参数在PHP 中显示得很好,但@"share":appData 却没有,这很奇怪

- (void) checkForUploadEligibility 
   NSArray* dates = [myModel getStatsMaxAndMinResults];
    if ( dates ) 
        NSDictionary* d = [dates objectAtIndex:0];
        NSDate* minDate = d[@"minDate"];
        NSDate* maxDate = d[@"maxDate"];
        NSTimeInterval secondsBetween = [maxDate timeIntervalSinceDate:minDate];

        int numberOfDays = secondsBetween / 86400;
        numberOfDays = abs(numberOfDays);

        if (numberOfDays >= 0) 
            myUser = [myModel getCurrentUser];
            if ( myUser.userWebID && myUser.authToken ) 
                NSArray* appData = [myModel getAllStatsData];
                if (!appData) 
                    return;
                
                NSDictionary* params = @  @"userID": myUser.userWebID,
                                       @"authCode": myUser.authToken,
                                       @"interact":@@"action":@"uploadAppStats",
                                                     @"actionTarget":@"uploadAppStats",
                                       @"share":appData,
                                       @"test":@[@@"test1":@@"test2":@"test2",@@"test3":@"test3"]
                                       ;
                [myShare uploadStats:params statsData:appData];
            

        
    

- (void) uploadStats:(NSDictionary*)params statsData:(NSArray *)statsData 
    NSLog(@"count %i, %@",[statsData count],statsData);
    NSURL *url = [[NSURL alloc]initWithString:sysURL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc]initWithBaseURL:url];

    NSURLRequest *request = [httpClient requestWithMethod:@"POST" path:sysAppURLPath parameters:params];

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
                                                                                        success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
                                                                                            NSLog(@"a: Inside the success block %@",JSON);
                                                                                            if ( [JSON objectForKey:@"ok"] ) 
                                                                                            //    [myModel deleteAllStatsData:statsData];
                                                                                            

                                                                                        
                                                                                        failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON)

                                                                                            NSLog(@"json text is: %@", JSON);
                                                                                            NSLog(@"Request failed with error: %@, %@", error, error.userInfo);
                                                                                        ];
    // Debug HTTP response
    BOOL dbug = YES;
    if (dbug) 
        [operation  setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) 
            NSLog(@"HTTP r: %@",  operation.responseString);
         failure:^(AFHTTPRequestOperation *operation, NSError *error) 
            NSLog(@"HTTP Error: %@",  operation.responseString);
        
         ];
    
    [operation start];


错误日志

count 5, (
        
        date = "2013-09-09 16:10:51 +0000";
        name = selectRoutine;
        shared = 0;
        timeSpent = 3;
    ,
        
        date = "2013-09-09 16:10:53 +0000";
        name = manageExercises;
        shared = 0;
        timeSpent = 1;
    , // MORE.....



   HTTP Error: array(24) 
      multipart/form-data; boundary=Boundary+0xAbCdEfGbOuNdArY
array(5) 
  ["authCode"]=>
  string(32) "e186cdd000a741ef76555009d7e86d80"
  ["interact"]=>
  array(2) 
    ["action"]=>
    string(14) "uploadAppStats"
    ["actionTarget"]=>
    string(14) "uploadAppStats"
  
  ["share"]=>
  array(15) 
    [0]=>
    array(1) 
      ["date"]=>
      string(19) "2013-09-09 19:52:31"
    
    [1]=>
    array(1) 
      ["name"]=>
      string(13) "selectRoutine"
    
    [2]=>
    array(1) 
      ["timeSpent"]=>
      string(1) "3"
    
    [3]=>
    array(1) 
      ["date"]=>
      string(19) "2013-09-09 19:52:33"
    
    [4]=>
    array(1) 
      ["name"]=>
      string(14) "manageRoutines"
    
    [5]=>
    array(1) 
      ["timeSpent"]=>
      string(1) "2"
    
    [6]=>
    array(1) 
      ["date"]=>
      string(19) "2013-09-09 22:24:31"
    
    [7]=>
    array(1) 
      ["name"]=>
      string(13) "selectRoutine"
    
    [8]=>
    array(1) 
      ["timeSpent"]=>
      string(2) "19"
    
    [9]=>
    array(1) 
      ["date"]=>
      string(19) "2013-09-09 22:24:45"
    
    [10]=>
    array(1) 
      ["name"]=>
      string(14) "manageRoutines"
    
    [11]=>
    array(1) 
      ["timeSpent"]=>
      string(2) "14"
    
    [12]=>
    array(1) 
      ["date"]=>
      string(19) "2013-09-09 22:25:58"
    
    [13]=>
    array(1) 
      ["name"]=>
      string(15) "manageExercises"
    
    [14]=>
    array(1) 
      ["timeSpent"]=>
      string(2) "73"
    
  
  ["test"]=>
  array(2) 
    [0]=>
    array(1) 
      ["test1"]=>
      array(1) 
        ["test2"]=>
        string(5) "test2"
      
    
    [1]=>
    array(1) 
      ["test3"]=>
      string(5) "test3"
    
  
  ["userID"]=>
  string(24) "5224b598f86f265801000008"

【问题讨论】:

【参考方案1】:

问题:

插入到@"share":appData 中的NSArray* appData 以某种方式被转换为大量小数组。

解决办法:

如果我在Key-Value NSDictionary @"share" 中插入NSArray,它不会按预期工作。然后我继续将 NSArray 更改为 NSDictionary 也不起作用。

下面的代码起作用了。我不得不将NSArray* appData 重新创建为NSDictionary* appData2。然后我必须将每个人 NSDictionary data object 包装到另一个 NSDictionary 中,但我必须给这个新对象一个显式数字索引...之后它会正确发送信息.

我猜我的问题是一个错误?我真的不知道......但如果有人也有问题,这可以帮助你。

        NSArray* appData = [myModel getAllStatsData];
        if (!appData) 
            return;
        

        NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
        [dateFormat setDateFormat: @"yyyy-MM-dd HH:mm:ss"];
        NSMutableDictionary* choa = [[NSMutableDictionary alloc]init];
        int i = 0;
        for (StatsAppUsage*statObj in appData) 

        [choa addEntriesFromDictionary:@[NSNumber numberWithInteger:i]:@@"date":[dateFormat stringFromDate:statObj.date],
                                                          @"name":statObj.name,
                                                          @"timeSpent": statObj.timeSpent
                                                          
                          ];
            i++;
        
        NSDictionary* appData2 = [[NSDictionary alloc]initWithDictionary:choa];
        NSDictionary* params = @  @"userID": myUser.userWebID,
                                   @"authCode": myUser.authToken,
                                   @"interact":@@"action":@"uploadAppStats",
                                                 @"actionTarget":@"uploadAppStats",
                                   @"share":appData2
                                   ;

@"share" PHP 输出

(
    [0] => Array
        (
            [date] => 2013-09-09 19:52:31
            [name] => selectRoutine
            [timeSpent] => 3
        )

    [1] => Array
        (
            [date] => 2013-09-09 19:52:33
            [name] => manageRoutines
            [timeSpent] => 2
        )

【讨论】:

我只是用这个答案来解决我的问题。非常感谢。即使在我遵循您的解决方案之后,让我陷入困境的一件事是将参数编码设置为AFFormURLParameterEncoding 而不是AFJSONParameterEncoding 的必要步骤。也许在您的答案中突出显示这一点将对未来的读者有很大帮助。 :)【参考方案2】:

我认为问题的出现是因为您使用带有参数的默认 HTTP POST 来发送您的值。您可以通过在服务器端打印出帖子的内容类型来确认这一点;它应该类似于x-www-form-urlencoded。如果是这样的话,这种数据格式就不能真正很好地表达数组和字典。所以你得到了你在服务器端看到的奇怪格式。

您可能想要做的是将数据作为 JSON 发送,而不是作为纯格式参数发送。我相信您要做的是将AFHTTPClientparameterEncoding 属性设置为AFJSONParameterEncoding。这会将您的请求以 JSON 格式发送,它能够在线上正确地表示数组和字典。

【讨论】:

它说当我做print_r($_SERVER["CONTENT_TYPE"]); 我得到application/x-www-form-urlencoded 但我将脚本修改为NSURLRequest *request = [httpClient multipartFormRequestWithMethod:@"POST" path:sysAppURLPath parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) ]; 现在我得到multipart/form-data 但同样的错误 我也试过httpClient.parameterEncoding = AFJSONParameterEncoding;,我可以看到CONTENT_TYPEapplication/json,但我尝试了var_dump($_REQUEST)和$_POST,但都显示为空

以上是关于AFNetworking 将 NSDictionary 作为单个数组值发送,而不是作为完整对象发送的主要内容,如果未能解决你的问题,请参考以下文章

将代码从 AFNetworking 2 迁移到 3

强制将响应对象返回给 AFNetworking

无法将令牌附加到 API 调用(基本身份验证、AFNetworking)

无法使用 AFNetworking 将阵列发布到服务器

AFNetworking 3.0 迁移

AFNetworking 将 NSMutableDictionary 作为 POST 发送