Category基本概念
1.什么是Category
-
Category有很多种翻译: 分类 \ 类别 \ 类目 (一般叫分类)
-
Category是OC特有的语法, 其他语言没有的语法
-
Category的作用
- 可以在不修改原来类的基础上, 为这个类扩充一些方法
- 一个庞大的类可以分模块开发
- 一个庞大的类可以由多个人来编写,更有利于团队合作
2.Category的格式
-
在.h文件中声明类别
-
1)新添加的方法必须写在 @interface 与 @end之间
-
2)ClassName 现有类的类名(要为哪个类扩展方法) + 3)CategoryName 待声明的类别名称
-
4)NewMethod 新添加的方法
@interface ClassName (CategoryName) NewMethod; //在类别中添加方法 //不允许在类别中添加变量 @end -
注意: 1)不允许在声明类别的时候定义变量
-
-
在.m文件中实现类别:
- 1)新方法的实现必须写在@ implementation与@end之间
- 2)ClassName 现有类的类名
- 3)CategoryName 待声明的类别名称
- 4)NewMethod 新添加的方法的实现
@implementation ClassName(CategoryName)
NewMethod
... ...
@end
- 使用Xcode创建分类
Category注意事项
1.分类的使用注意事项
- 分类只能增加方法, 不能增加成员变量
@interface Person (NJ)
{
// 错误写法
// int _age;
}
- (void)eat;
@end
- 分类中写property只会生成方法声明
@interface Person (NJ)
// 只会生成getter/setter方法的声明, 不会生成实现和私有成员变量
@property (nonatomic, assign) int age;
@end
- 分类可以访问原来类中的成员变量
@interface Person : NSObject
{
int _no;
}
@end
@implementation Person (NJ)
- (void)say
{
NSLog(@"%s", __func__);
// 可以访问原有类中得成员变量
NSLog(@"no = %i", _no);
}
@end
- 如果分类和原来类出现同名的方法, 优先调用分类中的方法, 原来类中的方法会被忽略
@implementation Person
- (void)sleep
{
NSLog(@"%s", __func__);
}
@end
@implementation Person (NJ)
- (void)sleep
{
NSLog(@"%s", __func__);
}
@end
int main(int argc, const char * argv[]) {
Person *p = [[Person alloc] init];
[p sleep];
return 0;
}
输出结果:
-[Person(NJ) sleep]
2.分类的编译的顺序
- 多个分类中有同名方法,则执行最后编译的文件方法(注意开发中千万不要这么干)
@implementation Person
- (void)sleep
{
NSLog(@"%s", __func__);
}
@end
@implementation Person (NJ)
- (void)sleep
{
NSLog(@"%s", __func__);
}
@end
@implementation Person (MJ)
- (void)sleep
{
NSLog(@"%s", __func__);
}
@end
int main(int argc, const char * argv[]) {
Person *p = [[Person alloc] init];
[p sleep];
return 0;
}
输出结果:
-[Person(MJ) sleep]
-
方法调用的优先级(从高到低)
- 分类(最后参与编译的分类优先)
- 原来类
- 父类
类扩展(Class Extension)
1.什么是类扩展
-
延展类别又称为扩展(Extendsion),Extension是Category的一个特例
-
可以为某个类扩充一些私有的成员变量和方法
- 写在.m文件中
- 英文名是Class Extension
2.类扩展书写格式
@interface 类名 ()
@end
-
对比分类, 就少了一个分类名称,因此也有人称它为”匿名分类”
Block基本概念
1.什么是Block
-
Block是iOS中一种比较特殊的数据类型
-
Block是苹果官方特别推荐使用的数据类型, 应用场景比较广泛
- 动画
- 多线程
- 集合遍历
- 网络请求回调
-
Block的作用
- 用来保存某一段代码, 可以在恰当的时间再取出来调用
- 功能类似于函数和方法
2.block的格式
- Block的定义格式
返回值类型 (^block变量名)(形参列表) = ^(形参列表) {
};
- block最简单形式
void (^block名)() = ^{代码块;}
例如:
void (^myBlock)() = ^{ NSLog(@"李南江"); };
- block带有参数的block的定义和使用
void (^block名称)(参数列表)
= ^ (参数列表) { // 代码实现; }
例如:
void (^myBlock)(int) = ^(int num){ NSLog(@"num = %i", num); };
- 带有参数和返回值的block
返回类型 (^block名称)(参数列表)
= ^ (参数列表) { // 代码实现; }
例如:
int (^myBlock)(int, int) = ^(int num1, int num2){ return num1 + num2; };
- 调用Block保存的代码
block变量名(实参);
typedef和Block
1.函数指针回顾
- 函数指针使用
int sum(int value1, int value2)
{
return value1 + value2;
}
int minus(int value1, int value2)
{
return value1 - value2;
}
int main(int argc, const char * argv[]) {
int (*sumP) (int, int) = sum;
int res = sumP(10, 20);
NSLog(@"res = %i", res);
int (*minusP) (int , int) = minus;
res = minusP(10, 20);
NSLog(@"res = %i", res);
return 0;
}
- 函数指针别名
typedef int (*calculate) (int, int);
int main(int argc, const char * argv[]) {
calculate sumP = sum;
int res = sumP(10, 20);
NSLog(@"res = %i", res);
calculate minusP = minus;
res = minusP(10, 20);
NSLog(@"res = %i", res);
return 0;
}
2.block和typedef
-
block使用
int main(int argc, const char * argv[]) { int (^sumBlock) (int, int) = ^(int value1, int value2){ return value1 + value2; }; int res = sumBlock(10 , 20); NSLog(@"res = %i", res); int (^minusBlock) (int, int) = ^(int value1, int value2){ return value1 - value2; }; res = minusBlock(10 , 20); NSLog(@"res = %i", res); return 0; } -
block别名
int main(int argc, const char * argv[]) {
calculateBlock sumBlock = ^(int value1, int value2){
return value1 + value2;
};
int res = sumBlock(10, 20);
NSLog(@"res = %i", res);
calculateBlock minusBlock = ^(int value1, int value2){
return value1 - value2;
};
res = minusBlock(10, 20);
NSLog(@"res = %i", res);
return 0;
}
Block注意事项
1.Block注意事项
- 在block内部可以访问block外部的变量
int a = 10;
void (^myBlock)() = ^{
NSLog(@"a = %i", a);
}
myBlock();
输出结果: 10
- block内部也可以定义和block外部的同名的变量(局部变量),此时局部变量会暂时屏蔽外部
int a = 10;
void (^myBlock)() = ^{
int a = 50;
NSLog(@"a = %i", a);
}
myBlock();
输出结果: 50
- 默认情况下, Block内部不能修改外面的局部变量
int b = 5;
void (^myBlock)() = ^{
b = 20; // 报错
NSLog(@"b = %i", b);
};
myBlock();
-
Block内部可以修改使用__block修饰的局部变量
__block int b = 5; void (^myBlock)() = ^{ b = 20; NSLog(@"b = %i", b); }; myBlock(); 输出结果: 20
Protocol基本概念
1.protocol 基本概念
-
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];
代理设计模式
1.
-
什么是设计模式
- 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
-
什么是代理设计模式
- 生活中大家一定遇到这样的情况了:比如说我要买一包纸,不妨就是心相印的吧,那一般人的话我应该不是去心相印的工厂里面直接去买吧,而是我们在心相印专卖店或者什么超市啊,这些地方购买,这些地方实际上就是洁丽雅毛巾的代理。这其实和我们OO中的代理模式是很相似的。
-
代理设计模式的场合:
- 当对象A发生了一些行为,想告知对象B(让对象B成为对象A的代理对象)
- 对象B想监听对象A的一些行为(让对象B成为对象A的代理对象)
- 当对象A无法处理某些行为的时候,想让对象B帮忙处理(让对象B成为对象A的代理对象)
2.代理设计模式示例
- 婴儿吃饭睡觉
// 协议
#import <Foundation/Foundation.h>
@class Baby;
@protocol BabyProtocol <NSObject>
- (void)feedWithBaby:(Baby *)baby;
- (void)hypnosisWithBaby:(Baby *)baby;
@end
#import "BabyProtocol.h"
@interface Baby : NSObject
// 食量
@property (nonatomic, assign) int food;
// 睡意
@property (nonatomic, assign) int drowsiness;
// 饿
- (void)hungry;
// 睡意
- (void)sleepy;
@property (nonatomic, strong) id<BabyProtocol> nanny;
@end
@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.代理设计模式练习
- 学生通过中介找房子的过程,学生不知道怎么找所以让代理帮忙找