2013-11-12 5 views
1

Я все еще пытаюсь перейти к разработке ios, но я надеюсь, что вы можете мне помочь.Parsing Json Location Data

В настоящее время я 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.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); 
     } 

    }]; 


} 

Вот где я имею проблемы, я хочу показать аннотацию на UImapview, используя информацию из данных JSON. Пожалуйста, смотрите ошибки я имею в этой части кода ниже, прокомментировал на линии, что они происходят

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; 

Предпочтительный способ объявить Ивар является в реализации . Таким образом, вместо того, чтобы объявить Ивар в интерфейсе

В файле Location.h

@interface Location : NSObject{ 
    NSString* address; 
} 

объявить их, как показано ниже:

@interface Location : NSObject 
    ... // public properties and methods 
@end 

В файле Location.m:

@implementation Location { 
    NSString* _address; 
} 
@synthesize address = _address; 

Примечание:

лязг поддерживает «авто-синтезировали» свойства, которые позволяют опустить декларацию Ивар и директиву @synthesize.


Теперь, что касается вашего кода в viewDidLoad:

Вы, кажется, загрузить ресурс с удаленного сервера:

NSData *data = [NSData dataWithContentsOfURL:url]; 

Это не подходящий способ загрузки ресурсов с удаленного сервера: это синхронный метод, который просто использует поток для wa это для чего-то случится в будущем (ответ от базового сетевого кода).

Внутренний сетевой код внутренне передает свои внутренние внутренние потоки.

Эффект заключается в том, что вы тратите впустую системные ресурсы, когда используете только поток, который блокируется, чтобы ничего не делать. И - что еще более важно - поскольку вы вызываете этот метод в своем потоке, вы являетесь , блокируя основной поток и тем самым блокируя обновления дисплея UIKit и другие задачи UIKit.

Кроме того, запрос сети может завершиться неудачно. Метод dataWithContentsOfURL: не может вернуть разумную информацию об ошибке.

Это только самые очевидные оговорки - но будьте уверены, их больше!

Таким образом, при доступе к удаленным ресурсам обычно используйте NSURLConnection или NSURLSession (или стороннюю библиотеку, которая использует их под капотом). В первом жизнеспособного подхода используется метод асинхронного класса:

+ (void)sendAsynchronousRequest:(NSURLRequest *)request 
          queue:(NSOperationQueue *)queue 
       completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler; 

Хотя этот метод лучше, он подоконник имеет ряд предостережений: нет способа отменить, ни способ адаптировать аутентификацию, ни способ настройки ничего.

Там куча вопросов и ответов, как использовать sendAsynchronousRequest:queue:completionHandler: на SO. Вот несколько связанных вопросов и ответов:

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

Как правило, всегда проверять возвращаемые значения и если ошибка параметра выход дается, обеспечивают объект NSError.

В случае sendAsynchronousRequest:queue:completionHandler: вы также должны проверить код состояния ответа HTTP и Content-Type и подтвердить, что вы действительно получаете то, что вы запросили, и что вы ожидаете.


После того, что сказал, вы бы заполнить ваш массив Locations следующим образом:

В обработчике завершения из sendAsynchronousRequest:queue:completionHandler: вы, в первую очередь проверьте ошибки и код состояния, если это соответствует вашим ожиданиям.IFF это правда, вы получили NSData объект, содержащий вашу JSON, а затем в обработчике завершения реализации этого кода:

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: должен быть прямым.

+0

Хм, прежде всего, спасибо за очень подробный ответ. Не могли бы вы помочь мне в нескольких вещах, если вы не возражаете? Не могли бы вы открыть чат или дискуссию, чтобы помочь мне? – Karl

+0

Пожалуйста, задайте свой вопрос здесь, спасибо :) – CouchDeveloper

+0

См. Изменения в файлах .m и .h? Это то, что вы просите? – Karl