320学习笔记 2

20110625

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映射.

MyThree20ProjAppDelegate
#import <UIKit/UIKit.h>

@class MyThree20ProjViewController;

@interface MyThree20ProjAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow
*window;
MyThree20ProjViewController
*viewController;
}

@property (nonatomic, retain) IBOutlet UIWindow
*window;
@property (nonatomic, retain) IBOutlet MyThree20ProjViewController
*viewController;

@end


#import "MyThree20ProjAppDelegate.h"
#import "MyThree20ProjViewController.h"

#import <Three20/Three20.h>



@implementation MyThree20ProjAppDelegate

@synthesize window;
@synthesize viewController;

- (void)applicationDidFinishLaunching:(UIApplication *)application {
TTNavigator
*navigator = [TTNavigator navigator];
navigator.persistenceMode
= TTNavigatorPersistenceModeAll;
navigator.window
= self.window;

TTURLMap
*map = navigator.URLMap;

// Any URL that doesn't match will fall back on this one, and open in the web browser
// [map from:@"*" toViewController:[TTWebController class]];

[map from:
@"tt://root" toSharedViewController:NSClassFromString(@"MyThree20ProjViewController")];

[map from:
@"tt://feed" toSharedViewController:NSClassFromString(@"RssFeedTableViewController")];
if (![navigator restoreViewControllers]) {
[navigator openURLAction:[TTURLAction actionWithURLPath:
@"tt://root"]];
}
}

- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)URL {
[[TTNavigator navigator] openURLAction:[TTURLAction actionWithURLPath:URL.absoluteString]];
return YES;
}

- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}

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

MyThree20ProjViewController
#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.

RssFeedTableViewController
#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对象集合

RssFeedDataSource
#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

RssFeedModel
#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中真的是无处不在.

RssTableItem
#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
RssTableItemCell
#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.

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所示,具体的代码细节都是很容易理解的.如果有写的不明白或者错误的地方请多多指正.

谢谢.

ps:有谁知道mac下有没有啥好的博客客户端啊,不然家里都打不开,只能到公司里抽时间写

posted on 2011-06-27 12:50  scorpiozj  阅读(1053)  评论(0编辑  收藏  举报