版權聲明:原創作品,謝絕轉載!否則將追究法律責任。
代理:
另一個裝飾設計模式,代理,是一個代表或者協調另一個對象的行為機制。例如當你用一個tableView,你必須實現他里面的一個tableView:numberOfRowsInSection:.方法。你不希望tableView知道他有多少行在每個section,因此這個計算每個區有幾行的任務交給了UITableView的代理。他允許tableView類是獨立的數據顯示。
當你創建一個UITableView的時候下面發生的:
這個tableView的對象的工作是用來展示tableView的,然而最終他將需要一些信息他沒有的。然后轉向他的代理和要求額外的信息通過發送一條信息。在Objective-c實現代理的設計模式。一個類可以定義可選或者必須的方法通過協議。
你可能想生成一個對象的子類更容易並覆蓋必須的方法,但考慮到你只能基於單個類的子類。如果你想讓一個物體是兩個或者兩個以上的其他的對象的代表。你不能通過子類來實現這一目標。
注意:這是一個重要的設計模式。蘋果在UIKit類里面用到了很多。 UITableView,UITextView, UITextField, UIWebView, UIAlert, UIActionSheet, UICollectionView, UIPickerView,UIGestureRecognizer, UIScrollView.這里面都有
怎么使用代理的設計模式呢?
在Viewcontroller的實現文件里面導入頭文件:
#import "LibraryAPI.h"#import "Album+TableRepresentation.h"
現在添加一個延展來添加私有變量:
@interface ViewController () {
UITableView *dataTable;
NSArray *allAlbums;
NSDictionary *currentAlbumData;
int currentAlbumIndex;
}
@end
然后在延展的括號后面添加協議名字:
@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
這使你的代理符合一個協議,使你能使用協議里面的方法。在這里你表示你的ViewController符合UITableViewDataSource 和UITableViewDelegate 協議。這種方法tableView可以絕對肯定的由其委托實現他協議必須實現的方法。
接下來在viewDidLoad寫以下代碼:
- (void)viewDidLoad
{
[super viewDidLoad];
// 1
self.view.backgroundColor = [UIColor colorWithRed:0.76f green:0.81f blue:0.87f alpha:1];
currentAlbumIndex = 0;
//2
allAlbums = [[LibraryAPI sharedInstance] getAlbums];
// 3
// the uitableview that presents the album data
dataTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 120, self.view.frame.size.width, self.view.frame.size.height-120) style:UITableViewStyleGrouped];
dataTable.delegate = self;
dataTable.dataSource = self;
dataTable.backgroundView = nil;
[self.view addSubview:dataTable];
}
對上面代碼的解釋:
1:改變背景顏色
2:得到專輯的列表用API而不是直接用PersistencyManager
3:這里創建tableView。你聲明這個ViewController是是tableView的代理或者數據源,因此tableView所有的信息都將要被這個Viewcontroller提供。
現在添加下面方法到Viewcontroller的實現文件里面
- (void)showDataForAlbumAtIndex:(int)albumIndex
{
// defensive code: make sure the requested index is lower than the amount of albums
if (albumIndex < allAlbums.count)
{
// fetch the album
Album *album = allAlbums[albumIndex];
// save the albums data to present it later in the tableview
currentAlbumData = [album tr_tableRepresentation];
}
else
{
currentAlbumData = nil;
}
// we have the data we need, let's refresh our tableview
[dataTable reloadData];
}
showDataForAlbumAtIndex從專輯的數組得到想要的專輯數據。當你想顯示最新的數據的時候你需要調用reloadData。他是tableView想他的代理詢問例如有多少section應該出現在tableVeiw上,在每個section里面有很多行,並且每行應該怎么顯示。
在ViewDidLoad最后一行添加[self showDataForAlbumAtIndex:currentAlbumIndex]
;
在應用加載當前專輯。並且currentAlbumIndex 先前設置0,他在集合里面展示第一個專輯。
編譯運行項目你得到一個崩潰下面有一個異常在debug窗口:
你把Viewcontroller設置為tableView的數據源或者代理。你必須實現他里面所有的必須實現的方法包括tableView:numberOfRowsInSection:但是你沒有這樣做。
在實現文件里面添加以下代碼:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [currentAlbumData[@"titles"] count];
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell"];
}
cell.textLabel.text = currentAlbumData[@"titles"][indexPath.row];
cell.detailTextLabel.text = currentAlbumData[@"values"][indexPath.row];
return cell;
}
tableView:numberOfRowsInSection: 返回在tableView里面顯示多少行。和在數據結構里面標題的個數匹配、
tableView:cellForRowAtIndexPath:創建返回一個cell帶有標題和值;
編譯運行項目你的應用應該這樣展示:
到目前為止看起來不錯。但是如果你還記得完成應用后第一次啟動的畫面。在屏幕的頂部有一個水平照片的滑動視圖。而不是專用的水平滑動的視圖為什么不使他重用呢?
為了讓他重用,所有內容的顯示等都交給了另一個對象:一個代理。這個水平滑動視圖應該聲明協議方法讓他的代理來實現。類似於tableView的代理方法是怎么工作的。我們在下一個設計模式里面討論如何實現。
一個適配器設計模式允許你的類和不兼容的接口一起工作。它封裝在一個對象,並公開了一個標准的接口和該對象進行交互。如果你熟悉適配器設計模式,那么你會發現蘋果實現了它以稍微不同的方式--蘋果使用協議來做這項工作。你可能熟悉的協議像UITableViewDelegate,UScrollViewDelegate,NSCoding,和NSCopying。例如用這個NSCopying協議任何類可以提供標准的copy方法。


