解析 JSON 数据时"objectForKey unrecognized selector"异常



嗨,我是ios的新手,在我的项目中,我在我的应用程序中使用web服务。

在这里,对于服务,我维护单独的后台类,并使用"协议"获得响应。好的,没关系。服务部门对我的反应很好。

但我的问题是,有时它会显示一个异常,比如"objectForKey无法识别的选择器发送",有时它加载得很好。为什么会出现这个问题,请参阅下面的代码。

如果没有数据,它就像警报一样显示没有可用的数据,我会维护if和else条件,但为什么会出现这个问题?

背景服务类别:-

#import "BacGroundGetMethodServiceClass.h"
@interface BacGroundGetMethodServiceClass ()
@end
@implementation BacGroundGetMethodServiceClass
@synthesize delegate;
- (void)viewDidLoad {
    [super viewDidLoad];
}
-(void)getServieCalling :(NSString*)mainurl{

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:mainurl]
                                                           cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                       timeoutInterval:60.0];
    [request setHTTPMethod:@"GET"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error != nil) {
            NSLog(@"fundamental network error = %@", error);
            return;
        }
        if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
            NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
            if (statusCode != 200) {
                NSLog(@"Warning; server should respond with 200 status code, but returned %ld", (long)statusCode);
            }
        }
        NSError *parseError;
        NSMutableArray *responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
        if (responseObject) {

             [self MainService:responseObject];
        }
        else {
            NSLog(@"Error parsing JSON: %@", parseError);
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"responseString = %@", responseString);
        }
    }];
    [task resume];
}
-(void)MainService :(NSMutableArray*) mainArrayList{
    [delegate GetCallService : mainArrayList];
}
@end

我的主类:-

@interface Mainclass ()
{
 BacGroundGetMethodServiceClass * Get;
}

- (void)viewDidLoad {
    [super viewDidLoad];
   [Get getServieCalling:@"my url here"];
}
- (void) GetCallService: (NSMutableArray*)mainArrayList{
    dispatch_async(dispatch_get_main_queue(), ^{
    NameArray = [[NSMutableArray alloc]init];
    IdArray = [[NSMutableArray alloc]init];
    if (mainArrayList.count<1) {
            NSLog(@"No data available");
      }else{
      for (NSDictionary * obj in mainArrayList) {
        NSString * Name = [obj objectForKey:@"Name"];
        NSString * Id = [obj objectForKey:@"id"];
        [NameArray addObject:Name];
        [IdArray addObject:Id];
      }
     NSLog(@"final NameArray is %@",NameArray);
     NSLog(@"final IdArray is %@",IdArray);
       });
 }

也许你必须更改这一行

NSMutableArray *responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];

在这个中

id responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];

然后让控制器对某个Objective-C类型进行强制转换,因为它应该知道它对服务调用的期望(服务对象是一个抽象,所以它不必知道它在处理什么)。不管怎样,您正在处理的网络操作可能会因网络问题或服务器端而失败。控制器也必须知道何时发生故障。

在这种情况下,也可以尝试使用blocks而不是protocols。。。我认为它可能更可重用,并且它将防止您总是编写大量代码来允许委派模式。看看这里:https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html或者在GitHub上查看AFNetworking代码,它完全是由块组成的,你可以看到如何使用它们

添加

对我来说,这完全取决于OOP。由于我正在构建一个抽象对象,它只处理网络连接,而不知道它在做什么,所以没有理由保留对发送方(委托)的引用。它应该只处理服务,然后调用内部端点(块)。可以在块中使用对selfweak引用来避免保留循环。

仅仅因为JSONSerialization解析了一些东西并不意味着结果就是一个字典。它也可以是一个数组。这会导致你看到的问题。而且在任何地方都看不到协议。获取一本Objective-C书籍,了解什么是协议。

您确实需要在代码中进行一些严重的错误检查。NSLog未进行错误处理。NSLog用于在开发过程中发现问题,但您没有处理这些问题。

就我个人而言,如果我看到诸如"BacGroundGetMethodServiceClass"、"getServieCalling"之类的东西,我认为您需要花费一些时间来提高代码的可读性。阅读一些示例应用程序代码,并了解苹果的命名准则。方法和变量应该被命名,这样读者就可以在不依赖任何注释的情况下弄清楚它们的用途——我在你的代码中没有看到任何注释。

首先在调用之前检查错误对象

[self MainService:responseObject];

这就像

if (parseError)
   NSLog(@"JSONObjectWithData error: %@", parseError);
else
   [self MainService:responseObject];

然后,在GetCallService方法中迭代响应对象时,尝试使用以下代码,而不是使用NSDictionary

for (int i = 0; i < [mainArrayList count]; ++i)
    {
        NSString * Name = [[mainArrayList objectAtIndex:i] obj objectForKey:@"Name"]];
        NSString * Id = [[mainArrayList objectAtIndex:i] obj objectForKey:@"id"]];
        [NameArray addObject:Name];
        [IdArray addObject:Id];
    }

您的问题是在解析JSON时。你不能指望它是NSMutableArray。最好检查一下它是否是NSArray

    NSObject *responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
    if (!parseError && [responseObject isKindOfClass:[NSArray class]]) {

您可以从中创建一个NSMutableArray

[responseObject mutableCopy];

实际导致崩溃的第二个问题是,需要确保数组中确实包含字典。您也不能将nil添加到数组中,所以也要检查一下。

  for (NSObject *obj in mainArrayList) {
      if ([obj isKindOfClass:[NSDictionary class]]){
        NSDictionary *dict = (NSDictionary *) obj;
        NSString *name = [dict objectForKey:@"Name"];
        if (name) {
            [NameArray addObject:name];
        }
        NSString *identifier = [dict objectForKey:@"id"];
        if (identifier){
            [IdArray addObject: identifier];
        }
      }
  }

一个更一般的注意事项是:方法名称或实例变量/属性不要使用大写。在Objective-C中,为类名保留了大写。

相关内容

最新更新