Fork me on GitHub

320学习笔记 2

http://www.cnblogs.com/scorpiozj/archive/2011/06/27/2091259.html

做iphone的,UINavigationController+UItableViewController组合的应用是必须会的,那么我们必须学习下如何使用320来实现此类应用。

考虑这样的需求:点击tableview上的feed行就从apple store上获取排名前10的专辑信息,链接:http://itunes.apple.com/us/rss/topalbums/limit=10/explicit=true/xml.  具体流程:程序启动后是一tableview(图1),点击rss 后在tableview中显示所有专辑信息,每个cel(图2)l中左边是专辑图片,右上是歌手名,右下是专辑名.流程很简单,页面显示就两个:通常rooview+detailView就搞定,此外还需要一个获取数据的类就OK了.参考了320的一种现成的cell式样,好像没有和我们所需相同的,那么我们需要自定义cell.

 图1

图2

在开始工程前,我们首先看一下320中实现上述的tableview的一个大致框架(图3):

图3

在UIKit下,tableview的实现主要通过设置tableview的datasource和delegate,这是苹果典型的MVC思维。在320中也贯彻了MVC思想:需要tableviewController,dataSource,tableItem,tableItemCell,Model以及object。datasource,顾名思义是为tableview提供数据,它首先生成model来获得所需数据(FeedObj),然后根据原数据的类型生成相应的tableItem,最后根据tableItem来选择合适的tableItemCell。

下面我们开始创建工程,可以选择xcode的viewController模板,然后将320添加进工程(过程略,参见官方的脚本文件).做好以上设置后,就可以开始了.我们大概需要以下类文件:rootViewController,tableViewController,tableItem,tableItemCell,Model,dataSource和obj.

以下将代码列出,并做简单说明.

MyThree20ProjAppDelegate主要的操作是生成url映射.

 1 #import <UIKit/UIKit.h>
2
3 @class MyThree20ProjViewController;
4
5 @interface MyThree20ProjAppDelegate : NSObject <UIApplicationDelegate> {
6 UIWindow *window;
7 MyThree20ProjViewController *viewController;
8 }
9
10 @property (nonatomic, retain) IBOutlet UIWindow *window;
11 @property (nonatomic, retain) IBOutlet MyThree20ProjViewController *viewController;
12
13 @end
14
15 #import "MyThree20ProjAppDelegate.h"
16 #import "MyThree20ProjViewController.h"
17
18 #import <Three20/Three20.h>
19
20
21 @implementation MyThree20ProjAppDelegate
22
23 @synthesize window;
24 @synthesize viewController;
25
26 - (void)applicationDidFinishLaunching:(UIApplication *)application {
27 TTNavigator *navigator = [TTNavigator navigator];
28 navigator.persistenceMode = TTNavigatorPersistenceModeAll;
29 navigator.window = self.window;
30
31 TTURLMap *map = navigator.URLMap;
32
33 // Any URL that doesn't match will fall back on this one, and open in the web browser
34 // [map from:@"*" toViewController:[TTWebController class]];
35
36 [map from:@"tt://root" toSharedViewController:NSClassFromString(@"MyThree20ProjViewController")];
37
38 [map from:@"tt://feed" toSharedViewController:NSClassFromString(@"RssFeedTableViewController")];
39 if (![navigator restoreViewControllers]) {
40 [navigator openURLAction:[TTURLAction actionWithURLPath:@"tt://root"]];
41 }
42 }
43
44 - (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)URL {
45 [[TTNavigator navigator] openURLAction:[TTURLAction actionWithURLPath:URL.absoluteString]];
46 return YES;
47 }
48
49 - (void)dealloc {
50 [viewController release];
51 [window release];
52 [super dealloc];
53 }

接着就是熟悉的RootViewController,这里生成一个tableview

#import <UIKit/UIKit.h>

@interface MyThree20ProjViewController : TTTableViewController {

}

@end

#import "MyThree20ProjViewController.h"

@implementation MyThree20ProjViewController

- (void)viewDidLoad {
[super viewDidLoad];

self.title = @"My Three20";


self.dataSource = [TTSectionedDataSource dataSourceWithObjects:
@"F",
[TTTableTextItem itemWithText:@"feed" URL:@"tt://feed"],
nil];

}

- (void)dealloc {
[super dealloc];
}

@end

RssFeedTableViewController,是320中tableViewController的子类,可以通过不同的datasource显示不同的view.

#import <UIKit/UIKit.h>

@interface RssFeedTableViewController : TTTableViewController {

}

@end

#import "RssFeedTableViewController.h"
#import "RssFeedDataSource.h"

@implementation RssFeedTableViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
self.title = @"Rss";
self.variableHeightRows = YES;//很重要,否则cell高度无法改变
}
return self;
}

- (void)createModel {

self.dataSource = [[[RssFeedDataSource alloc] init] autorelease];

}

- (id<UITableViewDelegate>)createDelegate {
return [[[TTTableViewDragRefreshDelegate alloc] initWithController:self] autorelease];//下拉刷新,但本文未实现
}

- (void)dealloc {
[super dealloc];
}

@end

我们接着看下RssFeedDataSource,因为我们的tableview不需要section,所以是listdatasource的子类.通过model来获取所需数据,并生成相应的tableItem对象集合

#import <Foundation/Foundation.h>

#import "RssFeedModel.h"

@interface RssFeedDataSource : TTListDataSource {

RssFeedModel *_feedModel;
}

-(id)initWithQuery:(NSString *)query;
@end

#import "RssFeedDataSource.h"
#import "RssFeedObject.h"

#import "RssTableItem.h"
#import "RssTableItemCell.h"

@implementation RssFeedDataSource

-(id) init
{
if (self = [super init])
{
_feedModel = [[RssFeedModel alloc] initWithSearchQuery:@"a"];
}

return self;
}

-(id)initWithQuery:(NSString *)query
{
if (self = [super init])
{
_feedModel = [[RssFeedModel alloc] initWithSearchQuery:query];
}
return self;
}

- (void)dealloc
{
TT_RELEASE_SAFELY(_feedModel);
[super dealloc];
}

- (id<TTModel>)model {
return _feedModel;
}

- (void)tableViewDidLoadModel:(UITableView*)tableView
{
NSMutableArray *items = [[NSMutableArray alloc] initWithCapacity:1];
for (RssFeedObject *rssObj in _feedModel.dataArr)
{




RssTableItem *itemObj = [RssTableItem itemWithRssFeedObj:rssObj];

[items addObject:itemObj];
}

self.items = items;
TT_RELEASE_SAFELY(items);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
- (NSString*)titleForLoading:(BOOL)reloading {
if (reloading) {
return NSLocalizedString(@"Updating Twitter feed...", @"Twitter feed updating text");
} else {
return NSLocalizedString(@"Loading Twitter feed...", @"Twitter feed loading text");
}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
- (NSString*)titleForEmpty {
return NSLocalizedString(@"No tweets found.", @"Twitter feed no results");
}

///////////////////////////////////////////////////////////////////////////////////////////////////
- (NSString*)subtitleForError:(NSError*)error {
return NSLocalizedString(@"Sorry, there was an error loading the Twitter stream.", @"");
}

- (Class)tableView:(UITableView*)tableView cellClassForObject:(id) object {

if ([object isKindOfClass:[RssTableItem class]]) {
return [RssTableItemCell class];
} else {
return [super tableView:tableView cellClassForObject:object];
}
}

- (void)tableView:(UITableView*)tableView prepareCell:(UITableViewCell*)cell
forRowAtIndexPath:(NSIndexPath*)indexPath {
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}

@end

我们再看下model是怎么工作的.因为我们需要请求数据,所以生成TTURLRequestModel的子类,在requestDidFinishLoad:方法解析数据,获得的结果会返回给datasource

#import <Foundation/Foundation.h>

@interface RssFeedModel : TTURLRequestModel {

NSString *_queryStr;

NSMutableArray *_dataArr;
}

@property (nonatomic, copy) NSString *queryStr;
@property (nonatomic, retain) NSMutableArray *dataArr;

- (id)initWithSearchQuery:(NSString*)searchQuery;
@end

#import "RssFeedModel.h"
#import "RssFeedObject.h"

#define kID @"id"
#define kImArtist @"im:artist"
#define kLink @"link"
#define kCategory @"category"
#define kTitle @"title"
#define kImContentType @"im:contentType"
#define kRights @"rights"
#define kImPrice @"im:price"
#define kImImage @"im:image"
#define kImReleaseDate @"im:releaseDate"
#define kImItemCount @"im:itemCount"
#define kImName @"im:name"
#define kUpdated @"updated"
#define kContent @"content"

#define KeysArray nil

#define KEntityName @"___Entity_Name___"
#define kEntityType @"___Entity_Type___"
#define kEntityValue @"___Entity_Value___"

#define kHeight @"height"
#define kImageHeight @"60"

#define kRSSFeed @"http://itunes.apple.com/us/rss/topalbums/limit=10/explicit=true/xml"

@implementation RssFeedModel
@synthesize queryStr = _queryStr, dataArr = _dataArr;

- (id)initWithSearchQuery:(NSString*)searchQuery
{
if (self = [super init])
{
self.queryStr = searchQuery?searchQuery:@"";
_dataArr = [[NSMutableArray alloc] initWithCapacity:1];
}
return self;
}

- (void) dealloc {
TT_RELEASE_SAFELY(_queryStr);
TT_RELEASE_SAFELY(_dataArr);
[super dealloc];
}

- (void)load:(TTURLRequestCachePolicy)cachePolicy more:(BOOL)more
{
NSString* url = [NSString stringWithFormat:@"%@",kRSSFeed];

TTURLRequest* request = [TTURLRequest
requestWithURL: url
delegate: self];

request.cachePolicy = cachePolicy;
request.cacheExpirationAge = TT_CACHE_EXPIRATION_AGE_NEVER;
TTURLXMLResponse* response = [[TTURLXMLResponse alloc] init];
response.isRssFeed = YES;
request.response = response;
TT_RELEASE_SAFELY(response);

[request send];
}



- (void)requestDidFinishLoad:(TTURLRequest*)request
{

// [NSArray arrayWithObjects:kID,kImArtist,kLink,kCategory,kTitle,kImContentType
TTURLXMLResponse *xmlResponse = request.response;

NSDictionary *feed = xmlResponse.rootObject;

NSArray *allKey = [feed allKeys];

NSMutableArray *mArr = [NSMutableArray arrayWithCapacity:1];
for (NSString *str in allKey)
{
NSLog(@"%@\n",str);
[mArr addObject:[feed objectForKey:str]];
}
NSArray *entry = [feed objectForKey:@"entry"];//rss feed:每个是一个dictionary代表一行



for(NSDictionary *item in entry)
{
RssFeedObject *obj = [[RssFeedObject alloc] init];

for( NSString *str in [item allKeys])
{
id attr = [item valueForKey:str];
if ([attr isKindOfClass:[NSDictionary class]])
{

NSArray *attrKeys = [attr allKeys];

NSString *entityName = [(NSDictionary *)attr valueForKey:KEntityName];
if ([entityName isEqualToString:kID])
{
obj.readMore = [(NSDictionary *)attr valueForKey:kEntityValue];

}

else if ([entityName isEqualToString:kImArtist])
{
obj.artist = [(NSDictionary *)attr valueForKey:kEntityValue];

}

else if ([entityName isEqualToString:kCategory])
{
obj.genre = [(NSDictionary *)attr valueForKey:@"label"];

}

else if ([entityName isEqualToString:kTitle])
{
obj.header = [(NSDictionary *)attr valueForKey:kEntityValue];

}

else if ([entityName isEqualToString:kRights])
{
obj.copyRight = [(NSDictionary *)attr valueForKey:kEntityValue];

}

else if ([entityName isEqualToString:kImPrice])
{
obj.price = [(NSDictionary *)attr valueForKey:kEntityValue];

}


else if ([entityName isEqualToString:kImReleaseDate])
{
obj.releaseDate = [(NSDictionary *)attr valueForKey:kEntityValue];

}


else if ([entityName isEqualToString:kImItemCount])
{
obj.itemCount = [(NSDictionary *)attr valueForKey:kEntityValue];

}


else if ([entityName isEqualToString:kImName])
{
obj.title = [(NSDictionary *)attr valueForKey:kEntityValue];

}


else if ([entityName isEqualToString:kUpdated])
{
obj.updateDate = [(NSDictionary *)attr valueForKey:kEntityValue];

}
else {

}

}

else if ([attr isKindOfClass:[NSArray class]])
{
for (NSDictionary *imagDic in attr)
{
NSString *height = [imagDic valueForKey:kHeight];
if ([height isEqualToString:kImageHeight])
{
obj.imageLink = [imagDic valueForKey:kEntityValue];
}
}
}

}

[self.dataArr addObject:obj];
TT_RELEASE_SAFELY(obj);
}

NSDictionary *item = [entry objectAtIndex:0];

NSArray *itemKeys = [item allKeys];
NSMutableArray *itemContent = [NSMutableArray arrayWithCapacity:1];
for(NSString *str in itemKeys)
{
[itemContent addObject:[item objectForKey:str]];
NSLog(@"%@:%@\n",str,[item objectForKey:str]);
}



NSLog(@"%@",feed);

[super requestDidFinishLoad:request];//important
}
@end

tableItemCell就是自定义的cell,tableItem是tableviewcell所代表的object,在cell中需要将object与view(就是cell)联系起来.在这里我们也可以体会到MVC在iOS中真的是无处不在.

#import <Foundation/Foundation.h>

@class RssFeedObject;

@interface RssTableItem : TTTableItem
{
NSString *_artist;
NSString *_title;
NSString *_link;
NSString *_imageName;
}

@property (nonatomic, copy) NSString *artist;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *link;
@property (nonatomic, copy) NSString *imageName;

+(id)itemWithRssFeedObj:(RssFeedObject *)obj;

-(id)initWithRssFeedObj:(RssFeedObject *)obj;
@end

#import "RssTableItem.h"
#import "RssFeedObject.h"

@implementation RssTableItem
@synthesize artist = _artist, title = _title,link = _link,imageName = _imageName;

- (id)init
{
if (self = [super init])
{
_artist = nil;
_title = nil;
_link = nil;
_imageName = nil;
}
return self;
}

+(id)itemWithRssFeedObj:(RssFeedObject *)obj
{
RssTableItem *item = [[[RssTableItem alloc] init] autorelease];
item.artist = obj.artist;
item.title = obj.title;
item.link = obj.readMore;
item.imageName = obj.imageLink;

return item;

}

-(id)initWithRssFeedObj:(RssFeedObject *)obj
{
if (self = [[RssTableItem alloc] init])
{
self.artist = obj.artist;
self.title = obj.title;
self.link = obj.readMore;
self.imageName = obj.imageLink;
}

return self;
}

- (void)dealloc
{
TT_RELEASE_SAFELY(_artist);
TT_RELEASE_SAFELY(_title);
TT_RELEASE_SAFELY(_title);
TT_RELEASE_SAFELY(_imageName);
[super dealloc];
}

@end
#import <Foundation/Foundation.h>

@interface RssTableItemCell : TTTableViewCell {
UILabel *_artistLab;
UILabel *_titleLab;
TTImageView *_myImageView;
}

@end

#import "RssTableItemCell.h"
#import "RssTableItem.h"

@implementation RssTableItemCell
+ (CGFloat)tableView:(UITableView*)tableView rowHeightForObject:(id)object
{
return 60;
}

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)identifier
{
if (self = [super initWithStyle:style reuseIdentifier:identifier])
{
_myImageView = [[TTImageView alloc] initWithFrame:CGRectMake(5, 0, 60, 60)];
[self.contentView addSubview:_myImageView];

_artistLab = [[UILabel alloc] initWithFrame:CGRectMake(70, 10, 200, 10)];
_artistLab.textColor = [UIColor grayColor];
_artistLab.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:_artistLab];


_titleLab = [[UILabel alloc] initWithFrame:CGRectMake(70, 30, 200, 20)];
_titleLab.textColor = [UIColor grayColor];
_titleLab.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:_titleLab];

}
return self;
}

- (void)dealloc
{
TT_RELEASE_SAFELY(_artistLab);
TT_RELEASE_SAFELY(_myImageView);
TT_RELEASE_SAFELY(_titleLab);
[super dealloc];
}

- (void)layoutSubviews
{
[super layoutSubviews];

}

- (id)object
{
return self;;
}

- (void)setObject:(id)obj
{
if (self != obj)
{
[super setObject:obj];
RssTableItem *item = obj;

_myImageView.urlPath = item.imageName;
_artistLab.text = item.artist;
_titleLab.text = item.title;
}
}

@end

最后是一个解析数据的对象模型RssFeedObject.

#import <Foundation/Foundation.h>

@interface RssFeedObject : NSObject {
NSString *_header;
NSString *_title;
NSString *_artist;
NSString *_genre;
NSString *_price;
NSString *_releaseDate;
NSString *_copyRight;
NSString *_readMore;

NSString *_itemCount;
NSString *_imageLink;
NSString *_updateDate;
}

@property (nonatomic, copy) NSString *header,*title,*artist,*genre;
@property (nonatomic, copy) NSString *price,*releaseDate,*copyRight,*readMore;
@property (nonatomic, copy) NSString *itemCount,*imageLink,*updateDate;

@end

#import "RssFeedObject.h"

@implementation RssFeedObject
@synthesize header=_header,title=_title,artist=_artist,genre=_genre;

@synthesize price=_price,releaseDate=_releaseDate,copyRight=_copyRight,readMore=_readMore;

@synthesize itemCount = _itemCount,imageLink = _imageLink,updateDate = _updateDate;
- (void)dealloc
{
TT_RELEASE_SAFELY(_header);
TT_RELEASE_SAFELY(_title);
TT_RELEASE_SAFELY(_artist);
TT_RELEASE_SAFELY(_genre);
TT_RELEASE_SAFELY(_price);
TT_RELEASE_SAFELY(_releaseDate);
TT_RELEASE_SAFELY(_copyRight);
TT_RELEASE_SAFELY(_readMore);

TT_RELEASE_SAFELY(_itemCount);
TT_RELEASE_SAFELY(_imageLink);
TT_RELEASE_SAFELY(_updateDate);
[super dealloc];
}
@end

至此我们的工程就完成了.程序的大致流程如图3所示,具体的代码细节都是很容易理解的.如果有写的不明白或者错误的地方请多多指正.








posted on 2012-02-16 19:34  pengyingh  阅读(400)  评论(0)    收藏  举报

导航