[iOS] Objective-c 對的Json操作(六) UITableView 操作 WebApi資料

摘要:[iOS] Objective-c 對的Json操作(六) UITableView 操作 WebApi資料

前面討論了許多Json檔案序列化回強型別的物件集合後,這一篇我們要把這個應用帶進UITableView裡面。這是在開發上常常會碰到的應用。你的公司Server Backend提供了一個WebApi,而App可以經由這個WebApi的服務來取得資料。當然,資料傳遞的方式目前主流上是Json的格式。這一篇要開始把前面討論過的東西帶進UITableView。

 

在Xcode裡面新建一個UITableView專案,在這個專案中,我們要執行以下的步驟。

1.     新增一個對應到http://benluwebapi.azurewebsites.net/api/values 的類別物件。

2.     新增Jastor Library專案裡面。(對此物件還不熟悉的話,請參考前面的章節)

3.     在iPhoneStoreboard的畫面上拖拉出UITableView以及客製化UITableCell

4.     新增一個myCell類別,繼承UITableViewCell。

5.     在Layout畫面對應到ViewController實作UITabelviewdelegate與UITablesource

6.     在ViewController實作存取WebApi資料的程式。

 

1. 新增一個對應到http://benluwebapi.azurewebsites.net/api/values 的類別物件。

把這個網址貼到Json to C# 網站(http://json2csharp.com ),可以取得C#的類別檔,自己需要辛苦一點在把它轉換成Objective-c的類別檔。

 

在專案中建立一個Cocoa Touch Class,我就命名為object.h檔。

object.h 檔案內容

@interface RootObject : Jastor
@property (nonatomic) NSString* title;
@property (nonatomic) NSString* detail;
@property (nonatomic) NSString* image;
@end

object.m 檔案內容

#import 
#import "object.h"
@implementation RootObject
@synthesize title,detail,image;
@end

 

2.    新增Jastor Library專案裡面。

新增libJson.oc.a 與Jastor.h檔還有JastorRuntimeHelper.h檔案到專案之中。

 

3.    iPhoneStoreboard的畫面上拖拉出UITableView以及客製化UITableCell

 

4.    新增一個myCell類別,繼承UITableViewCell

把StoryBoard畫面上的UI控制項與myCell.h檔案產生IBoutlet關聯。

myCell.h檔案內容

@interface myCell : UITableViewCell
@property (weak, atomic) IBOutlet UIImageView *myImage;
@property (weak, nonatomic) IBOutlet UILabel *myLabel;
@property (weak, nonatomic) IBOutlet UILabel *myLabelDetail;
@end

5. Layout畫面對應到ViewController實作UITabelviewdelegateUITablesource

ViewController.h檔案

#import 
#import "object.h"

@interface ViewController : UIViewController
//用來序列化Json的型別
@property (nonatomic)RootObject* info;
//動態陣列用來存放Json物件集合
@property (nonatomic) NSMutableArray *Listobj;
//UITableView的IBoutlet
@property (nonatomic) IBOutlet UITableView* myTable;
@end

 

ViewController.m檔案

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.myTable.delegate = self;
    self.myTable.dataSource = self;
    
    NSURL *url = [NSURL URLWithString:@"http://benluwebapi.azurewebsites.net/api/values"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    
    //取得Json資訊
    NSArray* jsonobj = [NSJSONSerialization JSONObjectWithData:data
                                                       options:NSJSONReadingMutableContainers
                                                         error:nil];
    //初始化Listobj物件
    Listobj = [[NSMutableArray alloc]init];
    
    //迭代出NSArray裡面的所有值,轉成物件後,存放到NSMutableArray裡面
    [jsonobj enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
        NSDictionary* array1 = [jsonobj objectAtIndex:idx];
        RootObject *product = [[RootObject alloc] initWithDictionary:array1];
        [Listobj addObject:product];
    }];
}

 

 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return Listobj.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
     myCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil){
        cell = [[myCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    //取得NSMutableArray裡面的物件
    //接著就可以用物件屬性的方式來操作物件
    RootObject *rootobject = [Listobj objectAtIndex:[indexPath row]];    

    //接著就可以用物件屬性的方式來操作物件
    cell.myLabel.text = rootobject.title;
    cell.myLabelDetail.text = rootobject.detail;
 
    //同步下載方式
    NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: rootobject.image]];
    cell.myImage.image = [UIImage imageWithData:imageData];
    
    return cell;
}

 

範例做到這邊時,編譯這個App,同步下載圖片的時候,在滑動的時候整個就卡卡的。所以這時候要改用非同步的方式來下載圖片。

    //非同步下載方式
        dispatch_async(dispatch_get_global_queue(0,0), ^{
            NSData *imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: rootobject.image]];
            if ( imageData == nil )
                return;
            dispatch_async(dispatch_get_main_queue(), ^{
                // WARNING: is the cell still using the same data by this point??
                cell.myImage.image = [UIImage imageWithData:imageData];
            });
        });

 

 

編譯這個程式之後,可以看到TableView在下載圖片不會在卡卡的,不過解決掉卡卡的問題後,又出現了圖片會錯位的問題。這跟iOS的記憶體運作方式有關係,我們在下一篇再來解釋與解決這個問題。

 

範例程式下載:https://github.com/twbenlu/JsonToUITableViewWithWebApi

參考文獻:

Getting Image from URL Objective C

http://stackoverflow.com/questions/933099/getting-image-from-url-objective-c

iOS 开发UITableView 加载图片的内存管理

http://www.google.com.tw/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&cad=rja&uact=8&ved=0CCoQFjAC&url=http%3A%2F%2Fwww.c-s-a.org.cn%2Fch%2Freader%2Fcreate_pdf.aspx%3Ffile_no%3D20120923&ei=9MLtVM38Nai5mwWHrYKoBQ&usg=AFQjCNFky0Emb24xWciFsEwQl7ga2ul_HA&sig2=YbBPDLG7tBSeIiFBiXMt2A&bvm=bv.86956481,d.dGc