-
Protocol翻译过来, 叫做”协议”
- 在写java的时候都会有接口interface这个概念,接口就是一堆方法的声明没有实现,而在OC里面Interface是一个类的头文件的声明,并不是真正意义上的接口的意思,在OC中接口是由一个叫做协议的protocol来实现的
- protocol它可以声明一些必须实现的方法和选择实现 的方法。这个和java是完全不同的
-
Protocol的作用
- 用来声明一些方法
- 也就说, 一个Protocol是由一系列的方法声明组成的
2.protocol 语法格式
- Protocol的定义
@protocol
协议名称
// 方法声明列表
@end
- 类遵守协议
- 一个类可以遵守1个或多个协议
- 任何类只要遵守了Protocol,就相当于拥有了Protocol的所有方法声明
@interface
类名 : 父类 <协议名称1, 协议名称2,…>
@end
- 示例
@protocol
SportProtocol
<NSObject>- (void)playFootball;- (void)playBasketball;@end#import "SportProtocol.h" // 导入协议@interface Studnet : NSObject<SportProtocol> // 遵守协议@end@implementation Student// 实现协议方法- (void)playBasketball{ NSLog(@"%s", __func__);}// 实现协议方法- (void)playFootball{ NSLog(@"%s", __func__);}@end
3.protocol和继承区别
- 继承之后默认就有实现, 而protocol只有声明没有实现
- 相同类型的类可以使用继承, 但是不同类型的类只能使用protocol
- protocol可以用于存储方法的声明, 可以将多个类中共同的方法抽取出来, 以后让这些类遵守协议即可
Protocol其他用法
1.protocol 的使用注意
- 1)Protocol:就一个用途,用来声明一大堆的方法(不能声明成员变量),不能写实现。
@protocol
SportProtocol
<NSObject>{ int _age; // 错误写法}- (void)playFootball;- (void)playBasketball;@end
- 2)只要父类遵守了某个协议,那么子类也遵守。
@protocol
SportProtocol
<NSObject>- (void)playFootball;- (void)playBasketball;@end
#import "SportProtocol.h"
@interface
Student
: NSObject <SportProtocol>@end@interface GoodStudent : Student@end@implementation GoodStudent- (void)playFootball{ NSLog(@"%s", __func__);}- (void)playBasketball{ NSLog(@"%s", __func__);}@end
- 3)OC不能继承多个类(单继承)但是能够遵守多个协议。继承(:),遵守协议(< >)
#import "SportProtocol.h"
#import "StudyProtocol.h"
@interface
Student
: NSObject <SportProtocol, StudyProtocol>@end
- 4)协议可以遵守协议,一个协议遵守了另一个协议,就可以拥有另一份协议中的方法声明
@protocol
A
-(
void
)
methodA
;
@end
@protocol
B <A>-(void)methodB;@end
@interface
Student
: NSObject <B>-(void)methodA; // 同时拥有A/B协议中的方法声明-(void)methodB;@end
2.基协议
-
NSObject是一个基类,最根本最基本的类,任何其他类最终都要继承它
-
还有名字也叫NSObject的协议,它是一个基协议,最根本最基本的协议
-
NSObject协议中声明很多最基本的方法
- description
- retain
- release
-
建议每个新的协议都要遵守NSObject协议
@protocol
SportProtocol
<NSObject> // 基协议- (void)playFootball;- (void)playBasketball;@end
3.@required和@optional关键字
- 协议中有2个关键字可以控制方法是否要实现(默认是@required,在大多数情况下,用途在于程序员之间的交流)
- @required:这个方法必须要实现(若不实现,编译器会发出警告)
- @optional:这个方法不一定要实现
@protocol SportProtocol <NSObject> @required // 如果遵守协议的类不实现会报警告 - (void)playFootball; @optional // 如果遵守协议的类不实现不会报警告 - (void)playBasketball; @end
Protocol类型限制
1.protocol类型限制
-
设定情景:
- 某攻城狮A希望找一个会做饭、洗衣服的女生做女朋友,有国企工作的优先。
- 满足条件的女生都可以向他发送消息
-
从题目中我们得到要求
- 会做饭
- 会洗衣服
- 有份好工作
@protocol
WifeCondition
<
NSObject
>
-
(void)cooking;- (void)washing;- (void)job;@end
- 如何在代码中要求对象必须具备这些行为?
- 数据类型<协议名称> 变量名
// 如果没有遵守协议则会报警告
id
<
WifeCondition
>
wife
= [[Person alloc] init];
代理设计模式
-
什么是设计模式
- 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
-
什么是代理设计模式
- 生活中大家一定遇到这样的情况了:比如说我要买一包纸,不妨就是心相印的吧,那一般人的话我应该不是去心相印的工厂里面直接去买吧,而是我们在心相印专卖店或者什么超市啊,这些地方购买,这些地方实际上就是洁丽雅毛巾的代理。这其实和我们OO中的代理模式是很相似的。
-
代理设计模式的场合:
- 当对象A发生了一些行为,想告知对象B(让对象B成为对象A的代理对象)
- 对象B想监听对象A的一些行为(让对象B成为对象A的代理对象)
- 当对象A无法处理某些行为的时候,想让对象B帮忙处理(让对象B成为对象A的代理对象)
2.代理设计模式示例
- 婴儿吃饭睡觉
baby.h
// 协议
#import <Foundation/Foundation.h>
@class
Baby
;@protocol BabyProtocol <NSObject>- (void)feedWithBaby:(Baby *)baby;- (void)hypnosisWithBaby:(Baby *)baby;@end@interface Baby : NSObject// 食量@property (nonatomic, assign) int food;// 睡意@property (nonatomic, assign) int drowsiness;// 饿- (void)hungry;// 睡意- (void)sleepy;@property (nonatomic, weak) id<BabyProtocol> nanny;@end
#import "Baby.h"
#import "Mother.h"
#import "Father.h"
@implementation
Baby
-
(void)hungry{ self.food -= 5; NSLog(@"婴儿饿了"); // 通知保姆 if ([self.nanny respondsToSelector:@selector(feedWithBaby:)]) { [self.nanny feedWithBaby:self];}}- (void)sleepy{ self.drowsiness += 5; NSLog(@"婴儿困了"); // 通知保姆 if ([self.nanny respondsToSelector:@selector(hypnosisWithBaby:)]) { [self.nanny hypnosisWithBaby:self]; }}@end
// 保姆
@interface
Nanny
: NSObject <BabyProtocol>@end@implementation Nanny- (void)feedWithBaby:(Baby *)baby{ baby.food += 10; NSLog(@"给婴儿喂奶, 现在的食量是%i", baby.food);}- (void)hypnosisWithBaby:(Baby *)baby{ baby.drowsiness += 10; NSLog(@"哄婴儿睡觉, 现在的睡意是%i", baby.drowsiness);}@end
- 有一个婴儿,他本身不会自己吃饭和洗澡等等一些事情,于是婴儿就请了一个保姆,于是婴儿和保姆之间商定了一个协议,协议中写明了保姆需要做什么事情,而保姆就是这个代理人,即:婴儿和保姆之间有个协议,保姆遵守该协议,于是保姆就需要实现该协议中的条款成为代理人
3.代理设计模式练习
- 学生通过中介找房子的过程,学生不知道怎么找所以让代理帮忙找
student.h
#import <Foundation/Foundation.h>
@class
Student
;//谁的代理就写在谁的头部@protocol StudentDelegate <NSObject>- (void)helpToFindRoom:(Student *)student;@end@interface Student : NSObject@property (nonatomic, strong) NSString *name;@property (nonatomic, strong) id<StudentDelegate> delegate;- (void)goToGuangZhou;@end
sudent.m
#import "Student.h"
@implementation
Student
-
(void)goToGuangZhou{ if ([_delegate respondsToSelector:@selector(helpToFindRoom:)]) { [_delegate helpToFindRoom:self]; }}@end
teacher.h
#import <Foundation/Foundation.h>
#import "Student.h"
@interface
Teacher
: NSObject <StudentDelegate>@end
teacher.m
#import "Teacher.h"
@implementation
Teacher
-
(void)helpToFindRoom:(Student *)student{ NSLog(@"帮%@同学找房子", student.name);}@end
main.m
#import <Foundation/Foundation.h>
#import "Student.h"
#import "Teacher.h"
/*
学生来广州找代理帮他找房子
*/
int
main
(
int
argc, const char * argv[]) { @autoreleasepool { Student *stu = [[Student alloc] init]; Teacher *tea = [[Teacher alloc] init]; stu.name = @"zhangsan";stu.delegate = tea; [stu goToGuangZhou]; } return 0;}
frame方式,文字尺寸
给模型增加frame数据
- 所有子控件的frame
- cell的高度
@interface
XMGStatus
: NSObject/**** 文字\图片数据 ****/// ...../**** frame数据 ****//** 头像的frame */@property (nonatomic, assign) CGRect iconFrame;// ...../** cell的高度 */@property (nonatomic, assign) CGFloat cellHeight;@end
- 重写模型cellHeight属性的get方法
-
(
CGFloat
)
cellHeight
{
if (_cellHeight == 0) { // ... 计算所有子控件的frame、cell的高度} return _cellHeight;}
在控制器中
- 实现一个返回cell高度的代理方法
- 在这个方法中返回indexPath位置对应cell的高度
/**
* 返回每一行cell的具体高度
*/
-
(
CGFloat
)
tableView:
(
UITableView
*)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ XMGStatus *status = self.statuses[indexPath.row]; return status.cellHeight;}
- 给cell传递模型数据
-
(
UITableViewCell
*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *ID = @"tg"; // 访问缓存池 XMGStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; // 设置数据(传递模型数据) cell.status = self.statuses[indexPath.row]; return cell;}
新建一个继承自
UITableViewCell
的子类,比如XMGStatusCell
@interface
XMGStatusCell
: UITableViewCell@end
在XMGStatusCell.m文件中
- 重写
-initWithStyle:reuseIdentifier:
方法
- 在这个方法中添加所有需要显示的子控件
- 给子控件做一些初始化设置(设置字体、文字颜色等)
/**
* 在这个方法中添加所有的子控件
*/
-
(
instancetype
)
initWithStyle:
(
UITableViewCellStyle
)
style
reuseIdentifier:(NSString *)reuseIdentifier{ if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {// ...... } return self;}
在XMGStatusCell.h文件中提供一个模型属性,比如XMGTg模型
@class
XMGStatus
;@interface XMGStatusCell : UITableViewCell/** 团购模型数据 */@property (nonatomic, strong) XMGStatus *status;@end
在XMGTgCell.m中重写模型属性的set方法
- 在set方法中给子控件设置模型数据
-
(
void
)
setStatus:
(
XMGStatus
*)status{ _status = status; // .......}
重写
-layoutSubviews
方法
- 一定要调用
[super layoutSubviews]
- 在这个方法中设置所有子控件的frame
/**
* 在这个方法中设置所有子控件的frame
*/
-
(
void
)
layoutSubviews
{
[super layoutSubviews]; // ......}
计算文字尺寸的方法
// 计算文字所占据的尺寸
NSDictionary
*nameAttrs = @{NSFontAttributeName : [UIFont systemFontOfSize:17]}; CGSize nameSize = [self.name sizeWithAttributes:nameAttrs]; self.nameFrame = (CGRect){ {nameX, nameY},nameSize };// 文字 CGFloat textX = iconX; CGFloat textY = CGRectGetMaxY(self.iconFrame) + margin; CGFloat textW = [UIScreen mainScreen].bounds.size.width - 2 * textX; CGSize textMaxSize = CGSizeMake(textW, MAXFLOAT); NSDictionary *textAttrs = @{NSFontAttributeName : [UIFont systemFontOfSize:14]}; CGFloat textH = [self.text boundingRectWithSize:textMaxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:textAttrs context:nil].size.height; self.textFrame = CGRectMake(textX, textY, textW, textH);
storyboard方式
对比自定义等高cell,需要几个额外的步骤(iOS8开始才支持)
- 添加子控件和contentView之间的间距约束
- 设置tableViewCell的真实行高和估算行高
// 告诉tableView所有cell的真实高度是自动计算(根据设置的约束来计算)
self
.
tableView
.
rowHeight
=
UITableViewAutomaticDimension;// 告诉tableView所有cell的估算高度self.tableView.estimatedRowHeight = 44;
如果要支持iOS8之前
- 如果cell内部有自动换行的label,需要设置preferredMaxLayoutWidth属性
XMGStatusCell.m
-
(
void
)
awakeFromNib
{
// 手动设置文字的最大宽度(目的是:让label知道自己文字的最大宽度,进而能够计算出自己的frame) self.text_label.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20;}
- 计算cell高度的方法
XMGStatusCell.m```objc- (CGFloat)height{
// 强制布局cell内部的所有子控件(label根据文字多少计算出自己最真实的尺寸) [self layoutIfNeeded]; // 计算cell的高度 if (self.sta.picture) { return CGRectGetMaxY(self.pictureImageView.frame) + 10; }else{ return CGRectGetMaxY(self.text_label.frame) + 10; }
}```- 设置tableView的cell估算高度
ViewController.m
objc// 告诉tableView所有cell的估算高度(设置了估算高度,就可以减少tableView:heightForRowAtIndexPath:方法的调用次数)self.tableView.estimatedRowHeight = 200;
- 在代理方法中计算cell的高度
XMGStatusCell
*
cell
;
-
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ // 创建一个cell(cell的作用:根据模型数据布局所有的子控件,进而计算出cell的高度) if (!cell) { cell = [tableView dequeueReusableCellWithIdentifier:ID]; } // 设置模型数据 cell.status = self.statuses[indexPath.row]; return cell.height;}- (CGFloat)height{ // 强制布局cell内部的所有子控件(label根据文字多少计算出自己最真实的尺寸) [self layoutIfNeeded]; // 计算cell的高度 if (self.status.picture) { return CGRectGetMaxY(self.pictureImageView.frame) + 10; } else { return CGRectGetMaxY(self.text_label.frame) + 10; }
- 学习ios 重要还是要理清楚思路 在做或者看老师代码的时候 自己多想想为什么 不要自己看着就抄 另外还是要推荐一下 蓝懿IOS这个培训机构 和刘国斌老师刘国斌老师还是很有名气的,听朋友说刘老师成立了蓝懿iOS,,老师讲课方式很独特,能够尽量让每个人都能弄明白,有的比较难懂的地方,如果有的地方还是不懂得话,老师会换个其它方法再讲解,这对于我们这些学习iOS的同学是非常好的,多种方式的讲解会理解得更全面,这个必须得给个赞,嘻嘻,还有就是这里的学习环境很好,很安静,可以很安心的学习,安静的环境是学习的基础,小班讲课,每个班20几个学生,学习氛围非常好,每天都学到9点多才离开教室,练习的时间很充裕,而且如果在练习的过程中有什么困难,随时可以向老师求助,不像其它机构,通过视频教学,有的甚至学完之后都看不到讲师本人,问点问题都不方便,这就是蓝懿与其它机构的区别,相信在刘国斌老师的细心指导下,每个蓝懿学员都能找到满意的工作,加油!
-
写博客第一百零五天;
QQ:565803433
-