从特定 url 提取数据时 NSJSONSerialization 崩溃
Posted
技术标签:
【中文标题】从特定 url 提取数据时 NSJSONSerialization 崩溃【英文标题】:NSJSONSerialization crashes when pulling data from specific url 【发布时间】:2013-03-17 19:26:51 【问题描述】:我正在尝试从此网址提取数据,但遇到了一些问题。为什么这会在NSJSONSerialization
行上崩溃?有没有更好的方法从这个网站下载信息?
编辑:我将 jsonArray 从 NSArray 更改为 NSDictionary,但它仍然在同一个位置崩溃。有没有其他方法可以下载这些数据?
NSString *url=@"https://api.p04.simcity.com/simcity/rest/users/search/J3d1.json";
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSURLResponse *resp = nil;
NSError *err = nil;
NSData *response = [NSURLConnection sendSynchronousRequest: theRequest returningResponse: &resp error: &err];
NSDictionary *jsonArray = [NSJSONSerialization JSONObjectWithData: response options: NSJSONReadingMutableContainers error: &err];
NSLog(@"%@",jsonArray);
作为参考,JSON 是:
"users": [
"uri": "/rest/user/20624",
"tutorialState": 0,
"nucleusId": 20624,
"id": 20624,
"screenName": "R3DEYEJ3D1",
"lastLogin": 1362666027000,
"isOnline": "true",
"avatarImage": "https://api.p04.simcity.com/simcity/rest/user/20624/avatar",
"cities_count": 0,
"canChat": "true"
,
"uri": "/rest/user/46326",
"tutorialState": 0,
"nucleusId": 46326,
"id": 46326,
"screenName": "J3D1_WARR10R",
"lastLogin": 1363336534000,
"isOnline": "false",
"avatarImage": "https://api.p04.simcity.com/simcity/rest/user/46326/avatar",
"cities_count": 0,
"canChat": "true"
]
【问题讨论】:
你没有得到一个数组作为响应。你已经有了一本字典。 可以标记崩溃的地方,可能还有错误信息。 它似乎解析得很好。有什么问题 【参考方案1】:您的服务器提供了一个不受操作系统信任的证书 - 我必须使用 -k
标志来标记您的 JSON,所以应该早点想到这一点。
为了解决这个问题,您需要切换到使用异步NSURLConnection
并实现其委托方法。请参阅this stack overflow question 的此答案,以实施针对您的解析问题的有效解决方案。我在应用程序委托中实现了它,但是您可以将它放在异步 NSOperation
中并在那里使用它。
警告:此代码将连接到任何服务器,无论信任如何。这是要求一个人在中间攻击。启用此类信任时,请勿将敏感信息发送到服务器。您必须实现代码来验证您的服务器的身份,并将- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
中的if (YES)
替换为针对该检查结果的测试。
我目前的理解是,这应该通过将您的证书的公钥作为 DER 文件包含在应用程序包中来完成,并使用SecCertificateCreateWithData
创建一个SecCertficiateRef
,该SecCertficiateRef
将用作SecTrustSetAnchorCertificates
的输入。然后,应该使用SecTrustEvaluate
来验证身份。我基于阅读Certificate, Key, and Trust Services Reference 和this blog post 中的示例代码了解如何信任您自己的证书。
@interface AppDelegate () <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
// This is needed to collect the response as it comes back from the server
@property (nonatomic, strong) NSMutableData *mutableResponseData;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
// Xcode template code for setting up window, ignore...
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
self.viewController = [[ViewController alloc] initWithNibName:@"ViewController_iPhone" bundle:nil];
else
self.viewController = [[ViewController alloc] initWithNibName:@"ViewController_iPad" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
// Instantiate our connection
NSString *urlString = @"https://api.p04.simcity.com/simcity/rest/users/search/J3d1.json";
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
if(![NSURLConnection connectionWithRequest:request delegate:self])
NSLog(@"Handle an error case here.");
return YES;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
// Prepare to recevie data from the connection
NSLog(@"did receive response: %@", response);
self.mutableResponseData = [NSMutableData data];
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
// Handle an error case here
NSLog(@"did fail with error: %@", error);
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
// Build up the response data
[self.mutableResponseData appendData:data];
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
NSError *error = nil;
id JSONObject = [NSJSONSerialization JSONObjectWithData:self.mutableResponseData options: NSJSONReadingMutableContainers error:&error];
if (!JSONObject)
// Handle error here
NSLog(@"error with JSON object");
else if ([JSONObject isKindOfClass:[NSDictionary class]])
//we're in business
NSDictionary *dict = JSONObject;
NSLog(@"dict is %@", dict);
else
// Handle case of other root JSON object class...
// The following two methods allow any credential to be used. THIS IS VULNERABLE TO MAN IN THE MIDDLE ATTACK IN ITS CURRENT FORM
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
// WE ARE POTENTIALLY TRUSTING ANY CERTIFICATE HERE. Replace YES with verification of YOUR server's identity to avoid man in the middle attack.
// FOR ALL THAT'S GOOD DON'T SHIP THIS CODE
#warning Seriously, don't ship this.
if (YES)
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
@end
【讨论】:
这样做了,仍然在同一行崩溃 请详细了解如何执行此操作,因为这听起来可能是问题所在。 @user1413558 我现在想弄清楚,我没有得到响应数据,没有 NSURLResponse,也没有错误,所以这很有趣:) @user1413558 我刚刚用正确解析的实现更新了我的答案。请仔细阅读我的 cmets,因为它信任任何服务器的证书。【参考方案2】:如果数据为零,NSJSONSerialization 总是会崩溃。您需要输入条件以查看该 URL 是否包含任何数据。
【讨论】:
不,不会的。它将设置错误对象并返回nil
:developer.apple.com/library/ios/#documentation/Foundation/…
@MikeD 试试看 - 传递 nil
会因参数无效异常而崩溃。【参考方案3】:
尝试将 url 放入浏览器以确保为您提供有效的 JSON,同时确保解析的数据是 Array 或 NSDictionary
【讨论】:
以上是关于从特定 url 提取数据时 NSJSONSerialization 崩溃的主要内容,如果未能解决你的问题,请参考以下文章