IOS的MVC
1 翻牌游戏
1.1 问题
根据苹果MVC设计模式的思想原则实现一个简单的翻牌游戏,功能如下:
1)界面上随机摆放12张背面朝上的纸牌,界面效果如图-1所示:
图- 1
2)点击纸牌可以使纸牌翻页,翻牌后进行数字和花色的匹配,如果数字一样得4分,花色一样得1分;
3)在界面的左下角有一个记录得分的标签,界面如图-2所示:
图- 2
1.2 方案
首先使用Xcode创建一个带有xib的项目,在xib界面拖放12个UIButton对象和一个计分的UILabel对象,因为纸牌可以点击,所以使用UIButton控件作为纸牌对象,并且在检查器中设置好纸牌的背景图片。
其次根据苹果IOS开发的MVC原则,将整个案例的类分为三个群组,即Model层——用来保存游戏的纸牌数据和分数计算,View层——保存游戏的界面(xib文件)以及Controller层——控制程序的流程,协调View层和Model层。
然后创建TRCard类(纸牌类)用来管理纸牌的数据,TRDeck类(牌桌类)管理发牌的规则,TRCardGame类(游戏类)管理整个游戏的逻辑,这三个类都属于Model层,分别给这三个类增加属性和方法,实现各自管理的数据和逻辑。
最后在TRCardGameController类里面实现Model层和View层的通信逻辑。
1.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:搭建游戏界面
首先在xib界面拖放12个UIButton对象和一个计分的UILabel对象,因为纸牌可以点击这是使用UIButton对象作为纸牌。
其次给纸牌设置背景图片,选中纸牌的背景图片拖放到Xcode导航栏的View群组里面,会弹出如图-3所示对话框,在Copy items if needed选项前的复选框打钩,表明将图片拷贝到项目中:
图-3
点击Finish按钮之后,可以在导航栏的View群组里面看见添加进来的两张图片,名字分别为cardback.png和cardfront.png,分别是纸牌正面图片和背面图片,如图-4所示:
图-4
然后在右边栏的第四个检查器里面设置纸牌的背景图,初始界面将按钮的背景图设置为纸牌的背面图片cardback.png,如图-5所示:
图-5
步骤二:创建TRCard类、TRDeck类和TRCardGame类
创建Model层的三个类,TRCard,TRDeck和TRGame,这三个类全都继承至NSObject,如图-6所示:
图-6
其次在TRCard类里面声明NSString类型的用来表示纸牌内容的属性content,而每张牌由级别和花色组成,因此再声明两个属性rank和suit,分别用来表示级别和花色,在这里级别使用NSUInteger类型,花色使用特殊的字符表示,因此是NSString类型,代码如下所示:
- //这张牌的内容, 如:"♣A"
- @property (nonatomic, strong, readonly)NSString *content;
- //纸牌花色♠♥♣♦
- @property (nonatomic, strong)NSString *suit;
- //纸牌级别
- @property (nonatomic) NSUInteger rank;
然后再声明两个BOOL类型的属性用来表示纸牌的两个状态,chosen表示是否被选中状态,matched表示是否被匹配状态,代码如下所示:
- @property (nonatomic, getter=isChosen) BOOL chosen;
- @property (nonatomic, getter=isMatched) BOOL matched;
在这里定义属性使用了getter关键字,这是一种开发习惯,将BOOL类型属性的getter方法进行重新命名,表达更清楚明确,在这里自动生成的两个属性的getter方法名为isChosen和isMatched。
实际的开发中为了提高代码的效率,根据程序的需要通常会重写属性的setter和getter方法,属性suit只能接受♠♥♣♦这四种花色,赋值其他字符是非法的,为了保护suit属性,可以在suit的setter方法里面增加以下限制代码,如下所示:
- + (NSArray *)validSuits
- {
- return @[@"♠", @"♥", @"♣", @"♦"];
- }
- - (void)setSuit:(NSString *)suit
- {
- //判断传入的参数是否合法
- if([[TRCardvalidSuits] containsObject:suit]){
- _suit = suit;
- }
- }
以上代码中validSuits方法可以在TRCard.h文件中公开方便外部使用,否则外部可能不知道哪些是合法字符。同样的为了保护suit属性在getter方法里面也可以增加一些限制的代码,如下所示:
- -(NSString *)suit
- {
- //判断_suit实例变量是否为空,如果为空则返回?,保证_suit不会为空
- return _suit ? _suit : @"?";
- }
此时需要注意,重写完setter和getter方法之后系统不会再自动生成实例变量_suit,因此需要使用@synthesize关键字来生成实例变量_suit,代码如下所示:
- @synthesize suit = _suit;
同样为了保护rank属性,也可以将rank的setter方法和getter方法重写,代码如下所示:
- - (void)setRank:(NSUInteger)rank
- {
- //纸牌一共有13个级别
- if(rank <= 13){
- _rank = rank;
- }
- }
纸牌的内容是由花色和级别组成,因此重写content的getter方法即可,每次调用getter方法时即可获取到纸牌的显示内容,代码如下所示:
- + (NSArray *)randStrins
- {
- //纸牌13个级别对应的字符串,由小到大放入数组
- return @[@"?", @"A", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"J", @"Q", @"K"];
- }
- - (NSString *)content
- {
- NSString *rankString = [TRCardrandStrins][self.rank];
- return [self.suitstringByAppendingString:rankString];
- }
最后在TRCard类里面增加一个公开的方法,用于获取纸牌的最大级别,方便其他对象使用,代码如下所示:
- //返回级别的最大值
- + (NSUInteger)maxRank
- {
- return [[TRCardrandStrins] count] - 1;
- }
步骤三:TRDeck类添加属性和方法
TRDeck类主要是管理发牌的规则,既然是发牌,就需要拥有一个纸牌数组的属性,因此声明一个NSMutableArray类型的私有属性cards,使用懒汉模式(延迟加载)给实例变量_cards进行初始化,代码如下所示:
- //声明属性
- @property (nonatomic, strong) NSMutableArray *cards;
- //重写setter方法初始化_card实例变量
- - (NSMutableArray *)cards
- {
- if(!_cards)_cards = [[NSMutableArrayalloc]init];
- return _cards;
- }
然后在TRDeck的初始化方法里面按照纸牌的规则给_card数组添加纸牌对象,一共52个纸牌对象,代码如下所示:
- - (instancetype)init
- {
- self = [super init];
- if (self) {
- for (NSString *suit in [TRCardvalidSuits]) {
- for(NSUInteger rank = 1; rank<=[TRCardmaxRank]; rank++){
- //创建纸牌对象
- TRCard *card = [[TRCardalloc]init];
- card.suit = suit;
- card.rank = rank;
- //将纸牌对象添加的纸牌数组中
- [self.cardsaddObject:card];
- }
- }
- }
- return self;
- }
最后实现随机发牌的方法randomCard,此方法需要在TRDeck.h文件中公开,代码如下所示:
- - (TRCard *)randomCard
- {
- //使用随机函数,随机出一个数组下标,
- unsignedint index = arc4random() % self.cards.count;
- //根据随机出的数组下标从数组中获取到纸牌对象
- TRCard *card = self.cards[index];
- //从纸牌数值将刚才获取的纸牌对象移除
- [self.cardsremoveObjectAtIndex:index];
- return card;
- }
步骤四:TRCardGame类添加属性和方法
TRCardGame类是用来管理整个游戏的逻辑,分析本案例主要需要实现纸牌匹配和计算分数的逻辑,因此首先声明一个NSInteger的属性score,此时需要注意分数只能由TRCardGame类进行计算和修改,外部对该属性只能读取不能修改,因此在TRCardGame.h文件中声明一个只读的score属性,在TRCardGame.m文件中声明一个可读写的score属性,代码如下所示:
- //TRCardGame.h文件中
- @property (nonatomic, readonly) NSInteger score;
- //TRCardGame.m文件中
- @property (nonatomic, readwrite) NSInteger score;
其次TRCardGame需要随机产生12张纸牌,所以需要声明一个NSMutableArray类型的属性cards,同样在setter方法中进行实例变量_cards初始化,代码如下所示:
- //声明属性
- @property (nonatomic, strong) NSMutableArray *cards;
- //重写setter方法初始化_card实例变量
- - (NSMutableArray *)cards
- {
- if(!_cards)_cards = [[NSMutableArrayalloc]init];
- return _cards;
- }
然后自定义一个TRCardGame类的初始化方法initWithCardCount:usingDeck:,此方法用来初始化TRCardGame对象,此方法中使用一个TRDeck对象随机出12张纸牌,此时需要注意初始化方法通常都是需要公开在.h文件中进行声明,代码如下所示:
- - (instancetype)initWithCardCount:(NSUInteger)count usingDeck:(TRDeck *)deck
- {
- self = [super init];
- if (self) {
- for(inti=0; i<count; i++){
- TRCard *card = [deck randomCard];
- [self.cardsaddObject:card];
- }
- }
- return self;
- }
最后实现纸牌的匹配逻辑,定义一个动态方法chooseCardAtIndex:,当用户选中某张牌是调用此方法,其中TRCard对象的匹配判断应有TRCard类提供,同样此方法需要在.h文件中公开,代码如下所示:
- TRCardGame类中的代码:
- //根据下标返回指定扑克牌
- - (TRCard *)cardAtIndex:(NSUInteger)index
- {
- return index<self.cards.count ? self.cards[index] : nil;
- }
- //用户选中了一张牌
- - (void)chooseCardAtIndex:(NSUInteger)index
- {
- //进行匹配
- TRCard *card = [self cardAtIndex:index];
- if(![card isMatched]){
- if([card isChosen]){
- card.chosen = NO;//再翻回去
- }else{//没有匹配,也没有在正面
- //匹配其他翻过来的牌
- for (TRCard *otherCard in self.cards) {
- if([otherCardisChosen] && ![otherCardisMatched]){
- int score = [card match:otherCard];
- if(score){//匹配成功
- self.score += score;
- card.matched = YES;
- otherCard.matched = YES;
- }else{//匹配失败
- otherCard.chosen = NO;
- }
- }
- }
- //把牌翻过来
- card.chosen = YES;
- }
- }
- }
- TRCard类中的代码:
- - (int)match:(TRCard *)otherCard
- {
- int score = 0;
- if(self.rank == otherCard.rank) score = 4;
- else if(self.suit == otherCard.suit) score = 1;
- return score;
- }
步骤五:通过TRCardGameController实现View和Model层的通信
第一步已经搭建好了界面,此时需要将xib中的对象关联到TRCardGameController中,首先关联计分UILabel对象,以拉线的方式关联成TRCardGameController的私有属性scoreLabel,代码如下所示:
- @property (weak, nonatomic) IBOutletUILabel *scoreLabel;
其次关联12个纸牌对象,选中一张纸牌按住control键,往TRCardGameController.m文件的类扩展中拖,在弹出的对话框Connection选项中选择Outlet Collection,如图-7所示:
图-7
释放鼠标会自动生成一个NSArray类型的属性cardButtons,该数组里面的元素指向xib中的一个对象,选中代码前的是新圆圈,依次关联xib上的其他11张纸牌,这样_cardButtons数组里面的元素指向12个xib创建的纸牌对象,如图-8所示:
图-8
然后将12个纸牌对象以拉线的方式关联同一个IBAction方法touchCardButton:,每当选择纸牌时需要进行纸牌匹配的逻辑判断计算得分,这件事情需要TRCardGame对象去实现,因此TRCardGameController类需要拥有一个TRCardGame类的私有属性以及一个TRDeck类的私有属性,声明属性并且进行初始化,代码如下所示:
- @property (nonatomic, strong) TRDeck *deck;
- @property (nonatomic, strong) TRCardGame *game;
- - (TRDeck *)deck
- {
- if(!_deck)_deck = [[TRDeckalloc]init];
- return _deck;
- }
- - (TRCardGame *)game
- {
- if(!_game)_game = [[TRCardGamealloc]initWithCardCount:self.cardButtons.countusingDeck:self.deck];
- return _game;
- }
然后在touchCardButton:方法里通过TRCardGame对进行纸牌的匹配逻辑计算,代码如下所示:
- //点击按钮计算纸牌的匹配逻辑
- - (IBAction)touchCardButton:(UIButton *)sender
- {
- NSUIntegerchooseCardIndex = [self.cardButtonsindexOfObject:sender];
- [self.gamechooseCardAtIndex:chooseCardIndex];
- }
最后通过TRCardGame对象得出的匹配的结果更新界面,代码如下所示:
- //更新整个界面
- - (void)updateUI
- {
- for (UIButton *cardButton in self.cardButtons) {
- NSUInteger index = [self.cardButtonsindexOfObject:cardButton];
- TRCard *card = [self.gamecardAtIndex:index];
- [cardButtonsetTitle:[self titleForCard:card] forState:UIControlStateNormal];
- [cardButtonsetBackgroundImage:[self imageForCard:card] forState:UIControlStateNormal];
- cardButton.enabled = ![card isMatched];
- self.scoreLabel.text = [NSStringstringWithFormat:@"Score:%d", self.game.score];
- }
- }
- //根据纸牌选中的状态更改纸牌背景图片
- - (UIImage *)imageForCard:(TRCard *)card
- {
- if([card isChosen]){
- return [UIImageimageNamed:@"cardfront.png"];
- }else{
- return [UIImageimageNamed:@"cardback.png"];
- }
- }
- //根据纸牌选中的状态更改纸牌的title
- - (NSString *)titleForCard:(TRCard *)card
- {
- return [card isChosen] ? card.content : @"";
- }
- //点击按钮更新界面
- - (IBAction)touchCardButton:(UIButton *)sender
- {
- NSUIntegerchooseCardIndex = [self.cardButtonsindexOfObject:sender];
- [self.gamechooseCardAtIndex:chooseCardIndex];
- [selfupdateUI];
- }
1.4 完整代码
本案例中,TRCardGameViewController.m文件中的完整代码如下所示:
- #import "TRCardGameViewController.h"
- #import "TRCardGame.h"
- @interfaceTRCardGameViewController ()
- @property (nonatomic, strong) TRDeck *deck;
- @property (nonatomic, strong) TRCardGame *game;
- @property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *cardButtons;
- @property (weak, nonatomic) IBOutletUILabel *scoreLabel;
- @end
- @implementationTRCardGameViewController
- - (TRDeck *)deck
- {
- if(!_deck)_deck = [[TRDeckalloc]init];
- return _deck;
- }
- - (TRCardGame *)game
- {
- if(!_game)_game = [[TRCardGamealloc]initWithCardCount:self.cardButtons.countusingDeck:self.deck];
- return _game;
- }
- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
- {
- self = [super initWithNibName:nibNameOrNilbundle:nibBundleOrNil];
- if (self) {
- // Custom initialization
- }
- return self;
- }
- - (IBAction)touchCardButton:(UIButton *)sender
- {
- NSUIntegerchooseCardIndex = [self.cardButtonsindexOfObject:sender];
- [self.gamechooseCardAtIndex:chooseCardIndex];
- [selfupdateUI];
- }
- - (void)updateUI
- {
- for (UIButton *cardButton in self.cardButtons) {
- NSUInteger index = [self.cardButtonsindexOfObject:cardButton];
- TRCard *card = [self.gamecardAtIndex:index];
- [cardButtonsetTitle:[self titleForCard:card] forState:UIControlStateNormal];
- [cardButtonsetBackgroundImage:[self imageForCard:card] forState:UIControlStateNormal];
- cardButton.enabled = ![card isMatched];
- self.scoreLabel.text = [NSStringstringWithFormat:@"Score:%d", self.game.score];
- }
- }
- - (UIImage *)imageForCard:(TRCard *)card
- {
- if([card isChosen]){
- return [UIImageimageNamed:@"cardfront.png"];
- }else{
- return [UIImageimageNamed:@"cardback.png"];
- }
- }
- - (NSString *)titleForCard:(TRCard *)card
- {
- return [card isChosen] ? card.content : @"";
- }
- @end
本案例中,TRCard.h文件中的完整代码如下所示:
- #import<Foundation/Foundation.h>
- //扑克牌类
- @interfaceTRCard : NSObject
- @property (nonatomic, getter=isChosen) BOOL chosen;//被选中
- @property (nonatomic, getter=isMatched) BOOL matched;//被匹配
- @property (nonatomic, strong, readonly)NSString *content;//这张牌的内容, 如:"♣️A"
- @property (nonatomic, strong)NSString *suit;//花色♠️♥️♣️♦️
- @property (nonatomic) NSUInteger rank;//级别
- //和另外的一个扑克牌匹配,返回得分
- - (int)match:(TRCard *)otherCard;
- //返回合法的花色
- + (NSArray *)validSuits;
- //返回级别的最大值
- + (NSUInteger)maxRank;
- @end
本案例中,TRCard.m文件中的完整代码如下所示:
- #import "TRCard.h"
- @implementationTRCard
- @synthesize suit = _suit;
- - (int)match:(TRCard *)otherCard
- {
- int score = 0;
- if(self.rank == otherCard.rank) score = 4;
- else if(self.suit == otherCard.suit) score = 1;
- return score;
- }
- + (NSArray *)validSuits
- {
- return @[@"♠️", @"♥️", @"♣️", @"♦️"];
- }
- - (void)setSuit:(NSString *)suit
- {
- if([[TRCardvalidSuits] containsObject:suit]){
- _suit = suit;
- }
- }
- -(NSString *)suit
- {
- return _suit ? _suit : @"?";
- }
- - (void)setRank:(NSUInteger)rank
- {
- if(rank <= 13){
- _rank = rank;
- }
- }
- + (NSArray *)randStrins
- {
- return @[@"?", @"A", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"J", @"Q", @"K"];
- }
- - (NSString *)content
- {
- NSString *rankString = [TRCardrandStrins][self.rank];
- return [self.suitstringByAppendingString:rankString];
- }
- //返回级别的最大值
- + (NSUInteger)maxRank
- {
- return [[TRCardrandStrins] count] - 1;
- }
- @end
本案例中,TRDeck.h文件中的完整代码如下所示:
- #import<Foundation/Foundation.h>
- #import "TRCard.h"
- //牌桌类
- @interfaceTRDeck : NSObject
- - (TRCard *)randomCard;
- @end
本案例中,TRDeck.m文件中的完整代码如下所示:
- #import "TRDeck.h"
- @interfaceTRDeck ()
- @property (nonatomic, strong) NSMutableArray *cards;
- @end
- @implementationTRDeck
- - (NSMutableArray *)cards
- {
- if(!_cards)_cards = [[NSMutableArrayalloc]init];
- return _cards;
- }
- - (instancetype)init
- {
- self = [super init];
- if (self) {
- for (NSString *suit in [TRCardvalidSuits]) {
- for(NSUInteger rank = 1; rank<=[TRCardmaxRank]; rank++){
- //创建纸牌对象
- TRCard *card = [[TRCardalloc]init];
- card.suit = suit;
- card.rank = rank;
- //将纸牌对象添加的纸牌数组中
- [self.cardsaddObject:card];
- }
- }
- }
- return self;
- }
- //随机发牌
- - (TRCard *)randomCard
- {
- unsignedint index = arc4random() % self.cards.count;
- TRCard *card = self.cards[index];
- [self.cardsremoveObjectAtIndex:index];
- return card;
- }
- @end
本案例中,TRCardGame.h文件中的完整代码如下所示:
- #import<Foundation/Foundation.h>
- #import "TRCard.h"
- #import "TRDeck.h"
- //游戏类
- @interfaceTRCardGame : NSObject
- - (instancetype)initWithCardCount:(NSUInteger)count usingDeck:(TRDeck *)deck;
- //用户选中了一张牌
- - (void)chooseCardAtIndex:(NSUInteger)index;
- //根据下标返回指定扑克牌
- - (TRCard *)cardAtIndex:(NSUInteger)index;
- @property (nonatomic, readonly) NSInteger score;//分数
- @end
本案例中,TRCardGame.m文件中的完整代码如下所示:
- #import "TRCardGame.h"
- @interfaceTRCardGame ()
- @property (nonatomic, strong)NSMutableArray *cards;
- @property (nonatomic, readwrite) NSInteger score;//分数
- @end
- @implementationTRCardGame
- - (NSMutableArray *)cards
- {
- if (!_cards) {
- _cards = [[NSMutableArrayalloc]init];
- }
- return _cards;
- }
- - (instancetype)initWithCardCount:(NSUInteger)count usingDeck:(TRDeck *)deck
- {
- self = [super init];
- if (self) {
- for(inti=0; i<count; i++){
- TRCard *card = [deck randomCard];
- [self.cardsaddObject:card];
- }
- }
- return self;
- }
- //用户选中了一张牌
- - (void)chooseCardAtIndex:(NSUInteger)index
- {
- //进行匹配
- TRCard *card = [self cardAtIndex:index];
- if(![card isMatched]){
- if([card isChosen]){
- card.chosen = NO;//再翻回去
- }else{//没有匹配,也没有在正面
- //匹配其他翻过来的牌
- for (TRCard *otherCard in self.cards) {
- if([otherCardisChosen] && ![otherCardisMatched]){
- int score = [card match:otherCard];
- if(score){//匹配成功
- self.score += score;
- card.matched = YES;
- otherCard.matched = YES;
- }else{//匹配失败
- otherCard.chosen = NO;
- }
- }
- }
- //把牌翻过来
- card.chosen = YES;
- }
- }
- }
- //根据下标返回指定扑克牌
- - (TRCard *)cardAtIndex:(NSUInteger)index
- {
- return index<self.cards.count ? self.cards[index] : nil;
- }
- @end
IOS的MVC的更多相关文章
- PHP项目感悟 -- 从CI框架来看iOS的MVC
其实这几天一直都想找时间把这个感悟整理出来,也是这一段一直思考的问题,因为这一段参加一个PHP后台项目的开发,框架使用的是CI,随着项目的进展,对于CI接触的也越多,但是由于理解的可能并不深刻,我也只 ...
- iOS中MVC等设计模式详解
iOS中MVC等设计模式详解 在iOS编程,利用设计模式可以大大提高你的开发效率,虽然在编写代码之初你需要花费较大时间把各种业务逻辑封装起来.(事实证明这是值得的!) 模型-视图-控制器(MVC)设计 ...
- 【iOS 开发】iOS 开发 简介 (IOS项目文件 | MVC 模式 | 事件响应机制 | Storyboard 控制界面 | 代码控制界面 | Retina 屏幕图片适配)
一. iOS 项目简介 1. iOS 文件简介 创建一个 HelloWorld 项目, 在这个 IOS 项目中有四个目录 : 如下图; -- HelloWorldTests 目录 : 单元测试相关的类 ...
- iOS 基于MVC设计模式的基类设计
iOS 基于MVC设计模式的基类设计 https://www.jianshu.com/p/3b580ffdae00
- IOS的MVC和MVVM模式简明介绍
iOS中的MVC(Model-View-Controller)将软件系统分为Model.View.Controller三部分,结构图如下: Model: 你的应用本质上是什么(但不是它的展示方式) C ...
- iOS基于MVC的项目重构总结
关于MVC的争论 关于MVC的争论已经有很多,对此我的观点是:对于iOS开发中的绝大部分场景来说,MVC本身是没有问题的,你认为的MVC的问题,一定是你自己理解的问题(资深架构师请自动忽略本文). 行 ...
- iOS中MVC设计模式
在组织大型项目的代码文件时,我们常用MVC的思想.MVC的概念讲起来非常简单,就和对象(object)一样.但是理解和应用起来却非常困难.今天我们就简单总结一下MVC设计理念. MVC(Model V ...
- 转:iOS基于MVC的项目重构总结
转:http://www.cocoachina.com/ios/20160519/16346.html 关于MVC的争论 关于MVC的争论已经有很多,对此我的观点是:对于iOS开发中的绝大部分场景来说 ...
- iOS开发——MVC详解&Swift+OC
MVC 设计模式 这两天认真研究了一下MVC设计模式,在iOS开发中这个算是重点中的重点了,如果对MVC模式不理解或者说不会用,那么你iOS肯定学不好,或者写不出好的东西,当然本人目前也在学习中,不过 ...
随机推荐
- SQL Server数据库(高级查询)
高级查询 1.连接查询 有外键关系的两张表,通过关系一次查询两张表 (1)select * from 表名,表名 --- 直接使用出现笛卡尔积,两个表数据一一对应,查询出的结果数目是两个表的行的乘积, ...
- Objective-C:Foundation框架-常用类-NSValue
NSNumber是NSValue的子类,前者只能包装数字,后者可以包装任意值.NSArray.NSDictionary只能存储OC对象,不能存储结构体.因此,如果想要在NSArray.NSDictio ...
- 陈朱兴-js写法【案例】:
ajax请求: 一.从服务器端请求数据: var url = '';url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='+ ...
- ORACLE数据泵还原(IMPDP命令)【转】
Oracle数据库还原IMPDP命令是相对于EXPDP命令的,方向是反向的.即对于数据库备份进行还原操作.一.知晓IMPDP命令 ? C:\>impdp -help Import: Rele ...
- spring mvc表单自动装入实体对象
<form action="/springmvc1/user/add" method="post"> id: <input type=&quo ...
- ajax实际的应用
假设两个选择框,前面一个是省份,后面一个是地级市.当选择某一省份的时候,后面的选择框会有此省份对应的地级市.可以根据ajax来实现. function load{ if(true){ var ...
- <input type="hidden" id="haha" name="wang" value="xiaodong" />
jsp中一个隐藏的文本框,文本框里的值是:xiaodong id属性和name属性:就是在JavaScript中或者控制器中根据id或name属性取它的value的值 开发人员所需要,又不想让用户看到 ...
- svn cleanup failed问题解决
1.SVN出错 今早过来Update,报如下错误: 再次更新,svn会要求你执行clean up,但执行clean up仍会报错,说有未完的work item,还要求你执行clean up.汗,陷入死 ...
- 【HDU2087】KMP
KMP算法其实很好理解,就是在匹配串中找最近的相同的串. 下面是HDU的2087: #include<iostream> #include<cstdio> #include&l ...
- Fix the Can’t clobber writable file error in Perforce Version Control System - forward
http://easyprograming.com/eclipse-articles/57-fix-the-cant-clobber-writable-file-error-in-perforce-v ...