一、链式编程
通过点语法,将所有的方法串联,返回所需要的结果,即 结果 = 对象.方法.方法.方法。这样会是代码更加易读,甚至看起来像swift的语法。
Test * test = [[Test alloc] init];
int sum = test.add(10).add(20).result;
NSLog(@"%d", sum);
结果 sum=30;
实现原理:通过block返回对象本身,并更新属性的值
#import <Foundation/Foundation.h>
@interface Test : NSObject
@property (nonatomic, assign) int result;
-(Test *(^)(int num))add;
@end
#import "Test.h"
@implementation Test
-(Test *(^)(int num))add{
return ^(int num){
_result += num;
return self;
};
}
@end
二、函数式编程思想
什么是函数式思想:把一个操作写成一系列的方法
需要:写一个加法计算器,并且加法计算器自带判断是否等于某个值
BOOL b = [[[caculator add:^(NSInteger sum){
//把计算的事情写到block里面
sum += 10;
sum += 20;
return sum;
} ] equle:^BOOL(NSInteger number) {
return number == 30;
}] isEqule];
实现原理:原理上和上面链式的差不多,区别就是链式是在内部实现计算,函数式是在外部实现计算,可以在block中写下你需要计算的内容;
#import <Foundation/Foundation.h>
@interface Caculator : NSObject
@property (nonatomic, assign) NSInteger sum;
@property (nonatomic, assign) BOOL isEqule;
-(instancetype)add:(NSInteger(^)(NSInteger sum))block;
-(instancetype)equle:(BOOL(^)(NSInteger number))block;
@end
#import "Caculator.h"
@implementation Caculator
-(instancetype)add:(NSInteger (^)(NSInteger sum))block{
_sum = block(_sum);
return self;
}
-(instancetype)equle:(BOOL (^)(NSInteger))block{
_isEqule = block(_sum);
return self;
}
@end
说到响应式就必须先说说KVO。
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context;
KVO就是通过键值对的方式对对象的属性进行监听,观察属相的变化,上面第一个方法就是对需要监听的属性添加一个观察者,然后通过第二个方法来获取这个属性的变化。
KVO的原理就是去判断有没有调用一个对象的set方法,其底层实现原理:
1.动态创建NAKVONotifying_,NAKVONotifying_是需要观察的对象的子类,做KVO
2.修改当前对象的isa指针->NAKVONotifying_
3.只要调用对象的set,就会调用NAKVONotifying_的set方法
4.重写NAKVONotifying_的set方法:1.[super set] 2.通知观察者,告诉你属性改变
注意:如果对象的属性没有声明set方法,KVO就无法监听。
那么响应式编程就可以模仿KVO:
#import <Foundation/Foundation.h>
@interface NSObject (KVO)
- (void)custom_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
@end
#import "NSObject+KVO.h"
#import <objc/runtime.h>
#import "CustomClass.h"
@implementation NSObject (KVO)
-(void)custom_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{
//修改isa,本质就是改变当前对象的类名
object_setClass(self, [CustomClass class]);
//把观察者保存到当前对象里
//添加关联
/**
<#id object#>:给哪个对象添加关联上属性
<#const void *key#>:属性名
<#id value#>:关联值
<#objc_AssociationPolicy policy#>:策略(assign,copy...)
*/
objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
#import "Person.h"
@interface CustomClass : Person
@end
#import "CustomClass.h"
#import <objc/runtime.h>
@implementation CustomClass
-(void)setAge:(NSInteger)age{
[super setAge:age];
//通知观察者,属性改变
id observer = objc_getAssociatedObject(self, @"observer");
[observer observeValueForKeyPath:@"age" ofObject:self change:nil context:nil];
}
@end
#import "ViewController.h"
#import "Person.h"
#import "NSObject+KVO.h"
@interface ViewController ()
{
Person * _p;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_p = [[Person alloc] init];
_p.age = 0;
[_p custom_addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
NSLog(@"%zd", _p.age);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
_p.age ++;
}