使用JSON数组填充UITableView

Seb*_*ian 6 json objective-c uitableview ios

我在Storyboard工作,但我认为现在是时候面对代码......

我的服务器上有一个PHP文件,它将我的MySQL数据库表的内容输出为JSON格式的数组:

{
"id":"2",
"name":"The King's Arms",
"city":"London",
"day":"Tuesday",
}
Run Code Online (Sandbox Code Playgroud)

我最终需要所有数据,但是现在我只想将城市字段输出为UITableView.我该怎么做呢?

Pav*_*van 18

我相信在2012/2013这一年,Apple在代码实践方面涵盖了一个精彩的视频,突出显示的一个子主题是处理JSON对象和为它们创建数据对象的一种很好的智能方法.对不起,我忘记了实际视频的名称,如果有人记得,请为我编辑答案.

苹果所涵盖的是拥有存储每个json对象的数据对象.然后,我们将创建一个数组来存储这些对象,并在填充tableView时适当地访问所需的字段.所以在你的情况下你会做这样的事情.

在项目导航器中添加NSObject类型的文件并添加以下代码:

#import <Foundation/Foundation.h>
@interface PlaceDataObject : NSObject

-(id)initWithJSONData:(NSDictionary*)data;

@property (assign) NSInteger placeId;
@property (strong) NSString *placeName;
@property (strong) NSString *placeCity;
@property (strong) NSString *placeDay;

@end
Run Code Online (Sandbox Code Playgroud)

并在您的.m文件中添加此代码

#import "PlaceDataObject.h"
@implementation PlaceDataObject
@synthesize placeId;
@synthesize placeName;
@synthesize placeCity;
@synthesize placeDay;

-(id)initWithJSONData:(NSDictionary*)data{
    self = [super init];
    if(self){
        //NSLog(@"initWithJSONData method called");
        self.placeId = [[data objectForKey:@"id"] integerValue];
        self.placeName =  [data objectForKey:@"name"];
        self.placeCity = [data objectForKey:@"city"];
        self.placeDay = [data objectForKey:@"day"];
    }
    return self;
}
@end
Run Code Online (Sandbox Code Playgroud)

你现在拥有的是一个数据对象类,你可以在任何需要的代码中随处使用它,并获取你所显示的任何表的相应详细信息,无论是city字段表还是city and name表等.通过这样做,你也可以避免json解码您项目中的代码.当"钥匙"的名称发生变化时会发生什么?而不是仔细检查你的代码纠正你的所有密钥,你只需去PlaceDataObject上课并更改appriopriate key,你的应用程序将继续工作.

Apple解释得很好:

"模型对象代表了特殊的知识和专业知识.它们包含应用程序的数据并定义操纵数据的逻辑.精心设计的MVC应用程序将所有重要数据封装在模型对象中......它们代表了与a相关的知识和专业知识.特定的问题域,它们往往是可重用的."

使用自定义对象为服务器中的每个json条目填充数组

现在填充您已经创建的这个自定义数据对象的数组.现在遵循MVC方法,您可能最好拥有处理不同类(Model类)中的数据的所有方法.这就是Apple建议将这些方法放在一个单独的模型类中,在这个模型中所有的处理都会发生.

但是现在我们只是为了演示目的而将下面的代码添加到View Controller中.

在视图控制器的m文件中创建一个方法,该方法将处理您的JSON数组.

//make sure you have a global NSMutableArray *placesArray in your view controllers.h file.
-(void)setupPlacesFromJSONArray:(NSData*)dataFromServerArray{
     NSError *error;
     NSMutableArray *placesArray = [[NSMutableArray alloc] init];
     NSArray *arrayFromServer = [NSJSONSerialization JSONObjectWithData:dataFromServerArray options:0 error:error];

     if(error){
         NSLog(@"error parsing the json data from server with error description - %@", [error localizedDescription]);
     } 
     else {
         placesArray = [[NSMutableArray alloc] init];
         for(NSDictionary *eachPlace in arrayFromServer)
         {
             PlaceDataObject *place = [PlaceDataObject alloc] initWithJSONData:eachPlace];
             [placesArray addObject:place];
         }

         //Now you have your placesArray filled up with all your data objects
     }
 }
Run Code Online (Sandbox Code Playgroud)

你会像上面这样调用上面的方法:

//This is not what your retrievedConnection method name looks like ;)
// but you call the setupPlacesFromJSONArray method inside your connection success method
-(void)connectionWasASuccess:(NSData *)data{
    [self setupPlacesFromJSONArray:data];
}
Run Code Online (Sandbox Code Playgroud)

使用自定义Data对象填充tableView

至于在TableView中填充数据,你可以这样做:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
     //We check against table to make sure we are displaying the right number of cells
     // for the appropriate table. This is so that things will work even if one day you 
     //decide that you want to have two tables instead of one.
     if(tableView == myCitysTable){
          return([placesArray count]);
     }
     return 0;
}


 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
     if(cell)
     {
          //set your configuration of your cell
     }
     //The beauty of this is that you have all your data in one object and grab WHATEVER you like
     //This way in the future you can add another field without doing much.

     if([placesArray count] == 0){
         cell.textLabel.text = @"no places to show";
     }
     else{
         PlacesDataObject *currentPlace = [placesArray objectAtIndex:indexPath.row];
         cell.textLabel.text = [currentPlace placeCity];
         // in the future you can grab whatever data you need like this
         //[currentPlace placeName], or [currentPlace placeDay];
     }    
     return(cell);
}
Run Code Online (Sandbox Code Playgroud)

简短免责声明:上述代码尚未经过测试,但如果一切正常或者我遗漏了任何字符,请告诉我.