方法返回值必须有方法调用者
Masonry
- 创建约束制造者MASContrains,并且绑定控件,生成一个保存所有约束的数组
- 执行Mas_makeContrains传入的Block
- 让约束制造者安装约束
1:清空约束
2:添加约束 - 返回调用者本身
链式编程
#import <Foundation/Foundation.h>
#import "sumManager.h"
@interface NSObject (sum)
/**
* 给NSObject添加一个类方法
*
* @param block Block参数为sumManager
*
* @return 结果
*/
+ (int)jyf_makeContraons:(void(^)(sumManager *mgr))block;
@end
#import "NSObject+sum.h"
@implementation NSObject (sum)
+ (int)jyf_makeContraons:(void (^)(sumManager *))block{
// 首先初始化一个sumManager
sumManager *mgr = [[sumManager alloc] init];
// Block返回mgr对象
block(mgr);
// 返回结果
return mgr.result;
}
#import <Foundation/Foundation.h>
@interface sumManager : NSObject
/**
* 结果
*/
@property (nonatomic, assign) int result;
//- (instancetype)add:(int)value;
/**
* 返回结果管理者Self
*/
- (sumManager *(^)(int))add;
@end
#import "sumManager.h"
@implementation sumManager
/**
* 实现add方法 加值之后返回Self
*/
- (sumManager *(^)(int value))add{
return ^(int value){
_result += value;
return self;
};
}
@end
响应式编程
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@property (nonatomic, strong) Person *p;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
Person *p = [[Person alloc] init];
// 监听name属性
[p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
_p = p;
}
// 一旦 p对象的name属性变化 哥们就来了
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"%@",self.p.name);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
static int i = 0;
i++;
_p.name = [NSString stringWithFormat:@"%d",i];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
-
KVC的实现过程?
KVC的实质就是重写了属性的Set方法。。。。
所以 在监听的时候 才会监听到。。。 -
重写Set方法有两种情况
1:重写分类 -
KVC底层实现
1:自定义Person子类
2: 重写setName方法,在内部恢复父类方法,通知观察者
3:如何让外界调用自定义的Person子类方法?修改当前对象的isa指针,指向自定义的子类
自定义KVP的实现过程以及思想
-
系统的是在你检测属性的时候创建了一个KVO分类的实现的,那我们就直接写一个
-
仿照系统写一个分类方法
#import <Foundation/Foundation.h>
@interface NSObject (JYFKVO)
- (void)jyf_addObserver:(nonnull NSObject *)observer forKeyPath:(nonnull NSString *)keyPath options:(NSKeyValueObservingOptions)option context:(nullable void *)context;
@end
- 实现
#import "NSObject+JYFKVO.h"
// 因为要通知外界 所以必然要发送消息
#import <objc/message.h>
@implementation NSObject (JYFKVO)
/**
* 监听对象的某一个属性
*
* @param observer 监听者
* @param keyPath keyPath
* @param context context
*/
// self ==> 被观察者(Person)
// observer ==> 观察者
- (void)jyf_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)option context :(void *)context{
/**
1:自定义子类对象
2:重写被监听的对象的setName,在方法中我们来调用super的,调用完毕,通知观察者
3:修改当前对象的isa指针,让它指向我们自定义的子类!!
*/
// 1:动态生成一个类
// 1.1:创建Self的子类!第一步:获取类名
NSString *oldClassName = NSStringFromClass([self class]);
// 新的类名
NSString *newClassName = [@"jyfKVO_" stringByAppendingString:oldClassName];
// 转成C字符串
const char * newName = [newClassName UTF8String];
// 创建一个类的Class对象
Class MyClass = objc_allocateClassPair([self class], newName, 0);
// 注册类 到我们的项目中
objc_registerClassPair(MyClass);
// 2:重写Set方法 添加set方法
// v@:@ 表示没有返回值 没有参数
class_addMethod(MyClass, @selector(setName:), (IMP)setName, "v@:@");
// 3: 修改isa指针 把self的指针 改成我们自定义的子类
object_setClass(self, MyClass);
// 4:保存观察者对象
objc_setAssociatedObject(self, @"objc", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
// 1:调用super的set方法
// 2:通知我们的外界
void setName(id self, SEL _cmd, NSString * newName){
// 复写 调用super的setname方法
// 保存子类类型
id class = [self class];
// 改变self的isa指针
object_setClass(self, class_getSuperclass(class));
// 调用父类的set方法
objc_msgSend(self, @selector(setName:),newName);
// 拿到观察者
id objc = objc_getAssociatedObject(self, @"objc");
// 通知观察者
objc_msgSend(objc, @selector(observeValueForKeyPath:ofObject:change:context:),self,@"name",nil,nil);
// 改回子类类型
object_setClass(self, class);
}
@end
- 在这里打断点发现 走完我们自定义的监听方法,isa指针发生了变化 已经指向了我们的子类
-
使用消息机制 需要打开
Paste_Image.png -
这样 我们就可以发现 能正常监听了 需要注意的是 监听完毕 需要将指针归还给旧类
网友评论