解析 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:方法无法返回合理的错误信息。

这些只是最明显的警告 - 但请放心,还有更多!

因此,在访问远程资源时,通常使用NSURLConnectionNSURLSession(或在后台使用这些资源的第三方库)。在第一个可行的方法中,使用异步类方法:

+ (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 位置数据的主要内容,如果未能解决你的问题,请参考以下文章

在(SQLite)数据库中解析谷歌位置历史

告诉错误位置的 JavaScript JSON 解析器

在 BigQuery 中加载 JSON / JSON 在从位置开始的行中解析错误 ...:解析器在字符串结束之前终止

C#解析数组形式的json数据

C#解析多层Json数据

C#解析数组形式的json数据