layout: 斯坦福大學(xué)ios公開(kāi)課筆記(6)--
title: 多態(tài)與多個(gè)MVC的使用
date: 2017-05-21 22:23:08
tags:
這節(jié)課主要介紹了多態(tài)的概念和使用从祝,還有多個(gè)MVC使用持舆,在這之中介紹了UINavigationController和UITabbarController的使用。
多態(tài)
多態(tài)是面向?qū)ο蟪绦蛟O(shè)計(jì)中類(lèi)的三大特征之一粪狼,另外兩個(gè)是繼承和封裝含思。objective-c是一個(gè)面向?qū)ο蟮拈_(kāi)發(fā)語(yǔ)言撵儿,所以了解如何使用多態(tài)是非常有必要的。
在將多態(tài)的時(shí)候有一個(gè)概念不得不提---抽象惶桐。
抽象
抽象表示這個(gè)類(lèi)不能被實(shí)例化使用撮弧,他只能用于作為具體類(lèi)的超類(lèi)潘懊。簡(jiǎn)單來(lái)說(shuō)抽象就相當(dāng)于概念車(chē)。我們把車(chē)具體化給他四個(gè)輪子贿衍,他可能就是汽車(chē)??授舟,給他兩個(gè)輪子,他可能就是自行車(chē)??舌厨。這就是抽象岂却。
如何實(shí)現(xiàn)
這里我們對(duì)之前寫(xiě)的Machismo紙牌配對(duì)游戲進(jìn)行了修改,不了解這個(gè)游戲的請(qǐng)先看這里,使得它可以對(duì)任何種類(lèi)的卡牌進(jìn)行配對(duì)游戲裙椭。
首先躏哩,我們之前的代碼是這樣的:
- (CardMatchingGame *)game
{
if(!_game)
{
_game = [[CardMatchingGame alloc] initWithCardCount:[self.cardButtons count] usingDeck:[self createDeck]];
}
return _game;
}
- (Deck *)createDeck
{
return [[PlayingCardDeck alloc] init];
}
這里的return [[PlayingCardDeck alloc] init];
代表我們只會(huì)返回PlayingCardDeck
這個(gè)牌堆中的排,如果想要把他抽象揉燃,我們首先要把這里改成return nil;
扫尺。這樣他就變成了一個(gè)抽象類(lèi)。
然后我們將- (Deck *)createDeck;
這個(gè)方法放置到.h公有文件中炊汤,并且寫(xiě)一些注釋來(lái)說(shuō)明他就是這個(gè)抽象類(lèi)具體化時(shí)所需要用到的方法正驻。
//用來(lái)返回不同種類(lèi)的卡牌
- (Deck *)createDeck; //abstract
接下來(lái)我們新建一個(gè)controller繼承之前抽象好的控制器,然后重寫(xiě)createDeck
方法抢腐,返回正確的卡牌姑曙,就完成了我們的多態(tài)。這樣迈倍,我們可以創(chuàng)建很多控制器返回不同的卡牌類(lèi)型伤靠,并且使用同一套邏輯進(jìn)行游戲。
#import "ViewController.h"
@interface PlayingCardViewController : ViewController
@end
#import "PlayingCardViewController.h"
#import "PlayingCardDeck.h"
@interface PlayingCardViewController ()
@end
@implementation PlayingCardViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (Deck *)createDeck
{
return [[PlayingCardDeck alloc] init];
}
@end
對(duì)了啼染,這里要注意宴合,如果你是使用storyboard創(chuàng)建的界面,別忘了把控制器的Class改成剛剛具體化的類(lèi)迹鹅。
多個(gè)MVC協(xié)作
UINavigationController
UINavigationController導(dǎo)航欄卦洽,它本身也算作是一個(gè)MVC,他的view就是頂部的導(dǎo)航欄斜棚。他有一個(gè)rootViewController作為輸出口指向其他MVC阀蒂。
導(dǎo)航欄擁有一個(gè)自己的容器,這個(gè)容器使用的是棧結(jié)構(gòu)弟蚀,每次我們?cè)趫?zhí)行進(jìn)入下一個(gè)頁(yè)面或者返回到上一個(gè)頁(yè)面的時(shí)候都是一個(gè)椫拢空間壓入和彈出的功能的執(zhí)行。
每次我們壓入新的MVC的時(shí)候粗梭,系統(tǒng)都會(huì)從storyboard生成一個(gè)新的文件,然后顯示出來(lái)级零。而當(dāng)我們彈出的時(shí)候断医,頁(yè)面消失滞乙,這部分也會(huì)被釋放掉。這時(shí)候如果你有需要持久化使用的數(shù)據(jù)鉴嗤,你就要把他保存起來(lái)斩启。
如何壓入一個(gè)MVC
答案是使用segue
。他是storyboard和Xcode之間唯一聯(lián)系的地方醉锅,我們通過(guò)segue
的標(biāo)示符來(lái)判斷跳到哪一個(gè)MVC兔簇。
如何彈出一個(gè)MVC
通過(guò)方法
[self.navigationController popViewControllerWithAnimated:YES];
就可以彈出當(dāng)前的MVC
如何使用segue
我們需要讓Xcode知道當(dāng)我要調(diào)到下一個(gè)頁(yè)面的時(shí)候我選擇的是什么類(lèi)型的東西,比如我們要從日歷中的月份跳到日期的時(shí)候硬耍,我們需要知道我點(diǎn)擊的是幾號(hào)的日期垄琐。
- (void)prepareForSegue:(UIStroyboardSegue *)segue sender: (id)sender
{
if ([segue.identifier isEqualToString:@"DoSomething"])
{
if ([segue.destinationViewController isKindOfClass:[DoSomethingVC class]]){
DoSomethingVC *doVC = (DoSomethingVC *)segue.desitinationViewController;
doVC.infoString = ...
}
}
}
多個(gè)MVC協(xié)作的Demo
這里我們使用到了上節(jié)課使用的項(xiàng)目Attributor.在這次的課中我們給他添加一個(gè)新的MVC经柴,并要求這個(gè)MVC可以獲得上一個(gè)MVC的數(shù)據(jù)然后分析出有多少個(gè)字符改變了顏色或者多少個(gè)字符添加了邊框狸窘。
在storyboard中我們使用導(dǎo)航欄來(lái)控制各個(gè)MVC
設(shè)置頁(yè)面?zhèn)髦?/h3>
如果想要分析上一個(gè)頁(yè)面中設(shè)置字符的顏色,就一定要拿到上一個(gè)頁(yè)面中修改過(guò)的字符串信息坯认。這里就要用到頁(yè)面?zhèn)髦档墓δ芊堋m?yè)面?zhèn)髦岛?jiǎn)單來(lái)說(shuō)就是在頭文件中添加一個(gè)公有的屬性,然后在跳轉(zhuǎn)頁(yè)面的時(shí)候講值傳給他牛哺。
@interface TextStatsViewController : UIViewController
@property (nonatomic ,strong) NSAttributedString *textToAnalyze;
@end
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:@"Analyzer Text"])
{
if([segue.destinationViewController isKindOfClass:[TextStatsViewController class]])
{
TextStatsViewController *tsvc = (TextStatsViewController *)segue.destinationViewController;
tsvc.textToAnalyze = self.body.textStorage;
}
}
}
處理字符串
處理字符串主要是把上個(gè)頁(yè)面穿過(guò)來(lái)的字符串通過(guò)NSRange
一個(gè)一個(gè)字符的分析陋气,看看他有沒(méi)有使用顏色變化或者邊框變化。
- (NSAttributedString *)chaactersWithAttributtr:(NSString *)attributName
{
NSMutableAttributedString *characters = [[NSMutableAttributedString alloc] init];
int index = 0;
while (index < [self.textToAnalyze length])
{
NSRange range;
id value = [self.textToAnalyze attribute:attributName atIndex:index effectiveRange:&range];
if(value)
{
[characters appendAttributedString:[self.textToAnalyze attributedSubstringFromRange:range]];
index = range.length + range.location;
}
else
{
index++;
}
}
return characters;
}
- (void)updateUI
{
self.colorfulCharachersLabel.text = [NSString stringWithFormat:@"%ld colorful characters",[[self chaactersWithAttributtr:NSForegroundColorAttributeName] length]];
self.outletCharachersLabel.text = [NSString stringWithFormat:@"%ld outline characters",[[self chaactersWithAttributtr:NSStrokeWidthAttributeName] length]];
}
寫(xiě)好之后就可以統(tǒng)計(jì)上一個(gè)頁(yè)面的字符串啦引润。