1

我仍在努力进行 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
4

1 回答 1

1

您应该对代码进行一些改进:

首先,遵守 Objective-C 中的“命名约定”至关重要。属性,应以小写字母开头。例如:

@property (nonatomic, copy) NSString* address;

类型的属性NSString 应该具有“复制”属性(托管对象除外)。

几乎总是一个类的名称应该是单数形式,而不是

@class LocationResults;

我建议给它命名

@class Location;

声明 ivars 的首选方式是在implementation中。所以,而不是在接口中声明 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];

不是从远程服务器加载资源的合适方式:它是一种同步方法,仅使用线程等待将来发生的事情(来自底层网络代码的响应)。

底层网络代码在内部将其工作分派到内部私有线程上。

结果是,当您只使用一个无论如何都不会做任何事情而被阻塞的线程时,您就是在浪费系统资源。而且 - 更重要的是 - 由于您在主线程中调用此方法,因此阻塞了主线程,从而阻塞了 UIKit 显示更新和其他 UIKit 任务。

此外,网络请求可能会以无数种方式失败。该方法dataWithContentsOfURL:无法返回合理的错误信息。

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

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

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

虽然这种方法更好,但它仍然有许多警告:无法取消,无法定制身份验证,无法定制任何东西。

有一堆问题和答案如何sendAsynchronousRequest:queue:completionHandler:在 SO 上使用。以下是一些相关的问题和答案:

如何从 GCD 返回 UIImage 类型

NSData dataWithContentsOfURL:不返回浏览器中显示的 URL 数据

反序列化 JSON 数据时发生错误

根据经验,始终检查返回值,如果给出错误 输出参数,则提供一个NSError对象。

在这种情况下,sendAsynchronousRequest:queue:completionHandler:您还应该检查 HTTP 响应的状态代码和 Content-Type,并确认您确实得到了您所请求的内容和您所期望的内容。


话虽如此,您将按如下方式填充您的位置数组:

在您的完成处理程序sendAsynchronousRequest:queue:completionHandler:,首先检查错误和状态代码是否符合您的期望。如果这是真的,您已经获得了一个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:应该是直截了当的。

于 2013-11-12T12:31:23.233 回答