嗨,我是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。由于我正在构建一个抽象对象,它只处理网络连接,而不知道它在做什么,所以没有理由保留对发送方(委托)的引用。它应该只处理服务,然后调用内部端点(块)。可以在块中使用对self
的weak
引用来避免保留循环。
仅仅因为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中,为类名保留了大写。