一 Delegate
1.定义delegate
.h文件(UITableViewDataSource举例)
@protocol UITableViewDataSource<NSObject>
//@required是必须实现的方法,不实现程序会crash。
@required
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
//@optional中的方法,可实现可不实现。
@optional
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented
.....
@end
@interface UITableView : UIScrollView <NSCoding>
//delegate需要修饰符weak,如果使用strong会造成循环引用
@property (nonatomic, weak, nullable) id <UITableViewDataSource> dataSource;
@end
在定义文件定义了delegate后在父视图的.m文件里实现方法
-(void)viewDidLoad{
tableview.DataSource=self;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 0;
}
delegate相当于A视图需要某项数据,该项数据由B提供,所以A视图提供一个方法给B来实现提供数据这一行为。
二 Block
block大致相当于delegate的另一种形式,它比delegate更加直观,可以将需要实现的内容放到一起,更加直观的观察。
block的大致写法
// 返回数据类型(^方法名字)(需要数据);
@property (nonatomic,copy)void(^testBlock)(void);//属性需要声明为copy
//调用
[self setTestBlock:^ {
}];
//用typedef定义
typedef CGFloat(^TestBlock)(int i);
@property (nonatomic,copy)TestBlock testBlock;
//调用
[self setTestBlock :^CGFloat(int *i){
return 1.0f;
}];
//方法中定义 (返回数据类型(^)(需要数据)方法名称;
-(void)testBlock:(void(^)(NSString *test))testBlock;
//调用
[self testBlock:^(NSString *test) {
}];
使用block时需要注意不要造成循环引用,上述创建的block中,self持有了该block,如果在block里有使用了self,这样就会造成self持有block,block持有self。造成循环引用。这时候需要将self __weak。
__weak typeof(self) weakSelf=self;
[self setTestBlock:^ {
[weakSelf test];
}];
如果是另一个文件定义的block,使用self则不需要__weak;
Test *test=[[Test alloc]init];
[test setTestBlock:^ {
[self test];
}];
需要多次使用self时则还需要添加__strong
__weak typeof(self) weakSelf=self;
[self setTestBlock:^ {
__strong typeof(weakSelf) strongSelf=weakSelf;
[strongSelf test];
[strongSelf test2];
}];
这样做是避免在使用block的过程中weakSelf变成nil。
三 Notification
Notification是iOS的消息通知机制,和delegate类似,但是delegate比Notification调用前的准备复杂,delegate需要先声明委托的方法才可以使用,而Notification则只需要注册消息以及发送消息。
以下是使用Notification的主要方法。
//通常使用defaultCenter来发送消息。
[[NSNotificationCenter defaultCenter] postNotificationName:(NSString *)aName object:(nullable id)anObject;];
//其他方法
- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
//这三个方法的区别在于他的参数
//object参数我理解为这个消息是以什么名义发送的,例如写self,就是以发送该消息的文件的名义发送,这个参数在后面的接收消息时会用到。
//userInfo可以传递你想要传递给消息接收者的内容。
注册消息的方法
[[NSNotificationCenter defaultCenter] addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObjec];
//name为接收这个name发出的消息,object同理.
//接收到消息后会调用selector方法。
//name为nil,object不为nil则接收来自object的所有消息。
//object为nil,name不为nil,则接收名字为name的所有消息。
//都为nil则接收系统所有发出的消息。
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject;
四 KVC
KVC,即是指 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性。在平时使用的时候其实.出来就好,KVC主要是配合归档和解档使用,配合runtime来动态获取model的属性。例如:
// 遍历模型中成员变量
unsigned int outCount = 0;
Ivar *ivars = class_copyIvarList([self class], &outCount);
for (int i = 0 ; i < count; i++) {
Ivar ivar = ivars[i]; // 成员变量名称
const char *name = ivar_getName(ivar);;// 获取出来的是`_`开头的成员变量名,需要截取`_`之后的字符串
NSString *strName = [NSString stringWithUTF8String:name];
strName = [strName substringFromIndex:1];
id value = [self valueForKey:strName];//利用KVC获取值
// 归档 [encoder encodeObject:value forKey:strName];
//解档
// id value = [decoder decodeObjectForKey:strName];
//利用KVC对属性赋值
//[self setValue:value forKey:strName];
}
free(ivars);
五 KVO
Key-Value Observing (KVO) 建立在 KVC 之上,它能够观察一个对象的 KVC key path 值的变化。主要用于观察属性的变化.
例如
@interface TestModel : NSObject {
float test;
}
@end
@implementation TestModel
@end
观察
TestModel *test=[[TestModel alloc]init];
[test setValue:@"10.0" forKey:@"test"];
//NSKeyValueObservingOptionNew 把更改之前的值提供给处理方法
//NSKeyValueObservingOptionOld 把更改之后的值提供给处理方法
//NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。
//NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后。
//context 需要传入的值(需要转换)
[test addObserver:self forKeyPath:@"test" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];
每次观察对象改变会调用
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
//判断keyPath,做要做的,object为添加观察的对象,例如test添加了观察则object为test。
}
//使用后需要移除监听
-(void)delloc{
[test removeObserver:self forKeyPath:@"test"];
}
网友评论