解析 Json 位置数据
Posted
技术标签:
【中文标题】解析 Json 位置数据【英文标题】:Parsing Json Location Data 【发布时间】:2013-11-12 11:45:08 【问题描述】:我仍在努力进行 ios 开发,但我希望你能帮助我。
目前我有一个 WCF,它返回一些格式为
的 json 数据"Address": "3453453",
"Category": "CONCRETE",
"Closest_Property_Number": 2,
"ID": 42,
"Image1": 324,
"Image2": 0,
"Image3": 0,
"Latitude": 2,
"Longitude": "-6.541902",
"Notes": "GHTFHRG",
"User_ID": 2
然后我创建了一个名为 Location 的类,这里是 Location.m
#import "Location.h"
@implementation Location
NSString* _address;
NSString* _category;
NSString* _closest_Property_Number;
NSString* _iD;
NSString* _image1;
NSString* _latitude;
NSString* _longitude;
NSString* _notes;
NSString* _user_ID;
@synthesize address = _address;
@synthesize category = _category;
@synthesize closest_Property_Number = _closest_Property_Number;
@synthesize iD = _iD;
@synthesize image1 = _image1;
@synthesize latitude = _latitude;
@synthesize longitude = _longitude;
@synthesize notes = _notes;
@synthesize user_ID = _user_ID;
@end
到目前为止,我认为这是对的吗?这是我的所有导入发生的课程
#import "Location.h"
- (void)viewDidLoad
[super viewDidLoad];
// Do any additional setup after loading the view.
NSString *urlAsString = @"http://crm.fpmccann.co.uk/TemperatureWebService/iphonewebservice.svc/retrievelocations";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[NSURLConnection
sendAsynchronousRequest:urlRequest
queue:[[NSOperationQueue alloc] init]
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error)
if ([data length] >0 && error == nil)
NSMutableArray* tmpLocations = [[NSMutableArray alloc] init];
for (NSDictionary* loc in locations)
Location* location = [[Location alloc] initWithParameters:loc];
[tmpLocations addObject:location];
NSMutableArray* tmpAnnotations;
for (NSDictionary* location in tmpLocations)
// retrieve latitude and longitude from location
MKPointAnnotation* annotation = [[MKPointAnnotation alloc] init];
annotation.title = location.address;
newAnnotation.coordinate = location;
[tmpAnnotations addObject:annotation];
dispatch_async(dispatch_get_main_queue(), ^
self.locations = tmpLocations;
self.annotations = tmpAnnotations;
[self.mapView reloadInputViews];
);
else if ([data length] == 0 && error == nil)
NSLog(@"Nothing was downloaded.");
else if (error != nil)
NSLog(@"Error = %@", error);
];
这是我遇到问题的地方,我想使用来自 json 数据的信息在 UImapview 上显示注释。请查看我在下面这部分代码中遇到的错误,并在它们正在发生的行上注释
if ([data length] >0 && error == nil)
NSMutableArray* tmpLocations = [[NSMutableArray alloc] init];
for (NSDictionary* loc in locations) //receiving error use of undeclared identifier 'locations', did you mean 'Location'
Location* location = [[Location alloc] initWithParameters:loc];
[tmpLocations addObject:location];
NSMutableArray* tmpAnnotations;
for (NSDictionary* location in tmpLocations)
// retrieve latitude and longitude from location
MKPointAnnotation* annotation = [[MKPointAnnotation alloc] init];
annotation.title = location.address; // receiving error Property 'address' not found on object of type 'NSDictionary'
newAnnotation.coordinate = location; // receiving error use of undeclared identifier 'newAnnotation'
[tmpAnnotations addObject:annotation];
dispatch_async(dispatch_get_main_queue(), ^
self.locations = tmpLocations; /// receiving error Property 'locations' not found on object of type 'MapViewController'
self.annotations = tmpAnnotations; /// receiving error Property 'annotations' not found on object of type 'MapViewController'
[self.mapView reloadInputViews];
);
这是我的 MapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface MapViewController : UIViewController <MKMapViewDelegate>
@property (nonatomic, retain) IBOutlet MKMapView *mapView;
- (IBAction)refreshTapped:(id)sender;
@end
【问题讨论】:
【参考方案1】:您应该对您的代码进行一些改进:
首先,遵守 Objective-C 中的“命名约定”至关重要。属性,应以小写字母开头。例如:
@property (nonatomic, copy) NSString* address;
NSString
类型的属性应该具有“复制”属性(托管对象除外)。
几乎总是类的名称应该是单数形式,而不是
@class LocationResults;
我建议给它命名
@class Location;
声明 ivars 的首选方式是在实现中。所以,不要在接口中声明 ivars
在文件 Location.h 中
@interface Location : NSObject
NSString* address;
如下所示声明它们:
@interface Location : NSObject
... // public properties and methods
@end
在文件 Location.m 中:
@implementation Location
NSString* _address;
@synthesize address = _address;
注意:
clang 支持“自动合成”属性,它可以让您省略 ivar 声明和
@synthesize
指令。
现在,关于viewDidLoad
中的代码:
您似乎从远程服务器加载资源:
NSData *data = [NSData dataWithContentsOfURL:url];
这不是从远程服务器加载资源的合适方法:它是一个同步方法,它仅使用线程等待将来会发生一些事情(来自底层网络代码的响应)。
底层网络代码在内部将其工作分派到内部私有线程上。
效果是,当你只使用一个因为什么都不做而被阻塞的线程时,你正在浪费系统资源。而且 - 更重要的是 - 由于您在 main 线程中调用此方法,因此您正在 阻塞 主线程,从而阻塞 UIKit 显示更新和其他 UIKit 任务。
此外,网络请求可能会以无数种方式失败。 dataWithContentsOfURL:
方法无法返回合理的错误信息。
这些只是最明显的警告 - 但请放心,还有更多!
因此,在访问远程资源时,通常使用NSURLConnection
或NSURLSession
(或在后台使用这些资源的第三方库)。在第一个可行的方法中,使用异步类方法:
+ (void)sendAsynchronousRequest:(NSURLRequest *)request
queue:(NSOperationQueue *)queue
completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler;
虽然此方法更好,但仍有一些注意事项:无法取消、无法定制身份验证、无法自定义任何内容。
有一堆问题和答案如何在 SO 上使用sendAsynchronousRequest:queue:completionHandler:
。以下是一些相关的问题和答案:
How to return an UIImage type from a GCD
NSData dataWithContentsOfURL: not returning data for URL that shows in browser
ERROR happened while deserializing the JSON data
根据经验,请始终检查返回值,如果给出 error 输出参数,请提供 NSError
对象。
如果是sendAsynchronousRequest:queue:completionHandler:
,您还应该检查 HTTP 响应的状态代码和 Content-Type,并确认您确实得到了您的请求和期望。
话虽如此,您将按如下方式填充您的位置数组:
在sendAsynchronousRequest:queue:completionHandler:
的完成处理程序中,首先检查错误和状态代码是否符合您的期望。如果这是真的,您已经获得了一个包含 JSON 的 NSData
对象,然后在完成处理程序中实现此代码:
NSError* error;
NSArray* locations = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&error];
if (locations != nil)
NSMutableArray* tmpLocations = [[NSMutableArray alloc] init];
for (NSDictionary* loc in locations)
Location* location = [[Location alloc] initWithParameters:loc];
[tmpLocations addObject:location];
NSMutableArray* tmpAnnotations;
for (NSDictionary* location in tmpLocations)
// retrieve latitude and longitude from location
MKPointAnnotation* annotation = [[MKPointAnnotation alloc] init];
annotation.title = location.address;
annotation.coordinate = ...
[tmpAnnotations addObject:annotation];
dispatch_async(dispatch_get_main_queue(), ^
self.locations = tmpLocations;
self.annotations = tmpAnnotations;
[self.tableView reloadData];
);
else
// handle error
....
注意:实际实施取决于您更具体的要求。此实现只是如何解决此类问题的示例。
initWithParameters:
方法应该是直截了当的。
【讨论】:
嗯,首先感谢您非常详细的回复。如果你不介意的话,你能帮我解决一些事情吗?你能打开一个聊天或讨论来帮助我吗? 请查看 .m 和 .h 文件的更改?这是你要问的吗? 几乎 :) 您应该从@interface
中完全删除 ivars。不过,@interface
仍保留在接口文件中。我在编辑的答案中更清楚地说明了这一点,请检查。此外,当您更改类名时,请跟踪文件名。
所以这就是他们所做的小改动,我几乎可以肯定他们是正确的。接下来是 + (void)sendAsynchronousRequest:(NSURLRequest )request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse, NSData*, NSError*))handler;你能帮我解决这个问题吗,我不知道该怎么办。
请看这个例子:***.com/questions/18328379/…以上是关于解析 Json 位置数据的主要内容,如果未能解决你的问题,请参考以下文章