NSUserDefaults

以K-V键值对的形式存储到本地文件(plist),使用时非常方便(小量数据使用)

  • 使用
  • 存储
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:@"jack" forKey:@"name"];
[user setInteger:18 forKey:@"age"];
[user synchronize];
  • 取出
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSInteger age = [user integerForKey:@"age"];
NSString *name = [user objectForKey:@"name"];
NSLog(@"age = %ld, name = %@", (long)age, name);

KVC

KVC的全称是Key-Value Coding。中文就是我们所熟知的键值编码,键值编码是NSKeyValueCoding非正式协议启用的一种机制。对象采用该协议来间接访问该对象属性(既:可以通过一个key值来访问)。这种间接访问机制补充了实例变量及其相关的访问器方法所提供的直接访问.

  • 设置和访问
@interface Book : NSObject{
    @private
        NSString *name;
}
@end


@implementation Book

@end


Book *book = [Book new];
键值访问
[book setValue:@"OCprogram" forKey:@"name"];
NSString *name = [book valueForKey:@"name"];
路径访问
[book setValue:@"OCprogram" forKeyPath:@"name"];
NSString *name = [book valueForKeyPath:@"name"];
NSLog(@"%@", name);
  • 简单运算
一个作者写了很多书
作者里有一个NSArray的books
书有价格
NSString *sum = [author valueForKeyPath:@"books.@sum.price"];
min、max、avg同理

KVO

全称Key-Value observing,就是键值观察,KVO是一种监听机制,它将观察的指定对象属性更改后通知到观察者

在KVO的官方文档中官方文档传送门可以知道,KVO与KVC关系密切,因为KVO的监听属性值变化,这个属性赋值用的是KVC。

KVO是一对多的。

实例

用护士观察孩子的快乐值为例

  • child.h
@interface Child : NSObject
@property(nonatomic,assign)int happyVal;
@end
  • child.m
@implementation Child
-(id)init{
    if(self = [super init]){
        self.happyVal = 100;
        [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeAction:) userInfo:nil repeats:YES];
    }
    return self;
}
-(void)timeAction:(NSTimer *)timer{
    self.happyVal --;
}
@end
  • Nurse.h
@interface Nurse : NSObject
@property Child *child;
-(id)initWithChild:(Child *)child;
-(void)removeObserver;
@end
  • Nurse.m
@implementation Nurse
- (id)initWithChild:(Child *)child{
    if(self = [super init]){
        self.child = child;
        //什么地方写都行,可以一对多
        [_child addObserver:self forKeyPath:@"happyVal" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld
                    context:nil];
    }
    return self;
}
-(void)removeObserver{
    [_child removeObserver:@"happyVal" forKeyPath:@"happyVal"];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"%@", change);
}
@end

Main

Nurse *nurse = [[Nurse alloc] initWithChild:[Child new]];
[[NSRunLoop currentRunLoop] run];
Run loop 是一个事件处理循环,用于调度和协调线程的工作,等待并处理各种事件(如用户输入、定时器事件、网络事件等)。

NSNotification-通知

和KVO类似,是用来管理通知的接收和发送的.也是一对多的。

  • 实例:

孩子有一个NSInteger的sleep,变动时给父亲发通知

  • Child.h
@interface Child : NSObject
@property(nonatomic,assign)NSInteger sleep;
@end
  • Child.m
@implementation Child
-(id)init{
    if(self = [super init]){
        self.sleep = 100;
        [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
    }
    return self;
}
-(void)timerAction:(NSTimer *)timer{
    self.sleep --;
    NSLog(@"当前的sleep = %ld", _sleep);
    if(_sleep < 90){
        NSNumber *sleepNumber = [NSNumber numberWithLong:_sleep];
        NSMutableDictionary *dict = [NSMutableDictionary new];
        dict[@"sleep"] = sleepNumber;
        dict[@"flag"] = @"weak";
        [[NSNotificationCenter defaultCenter] postNotificationName:@"weak_sleep" object:sleepNumber userInfo:dict];
        [timer invalidate];
    }
}
@end
  • Father.h
@interface Father : NSObject

@end
  • Father.m
@implementation Father
-(id)init{
    if(self = [super init]){
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(weekNotification:) name:@"weak_sleep" object:nil];
    }
    return self;
}
-(void)weekNotification:(NSNotification *)notification{
    NSNumber *num =  notification.object;
    NSMutableDictionary *dict = notification.userInfo;
    NSLog(@"小孩子醒了,sleep = %@, dict = %@", num, dict);
}
@end
  • Main
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Child *child = [[Child alloc]init];
        
        Father *father = [[Father alloc]init];
        [[NSRunLoop currentRunLoop] run];
    }
    return 0;
}
  • 结果

2023-12-20 17:47:23.117046+0800 通知[49180:2566753] 当前的sleep = 99

2023-12-20 17:47:24.121308+0800 通知[49180:2566753] 当前的sleep = 98

2023-12-20 17:47:25.116591+0800 通知[49180:2566753] 当前的sleep = 97

2023-12-20 17:47:26.119006+0800 通知[49180:2566753] 当前的sleep = 96

2023-12-20 17:47:27.116444+0800 通知[49180:2566753] 当前的sleep = 95

2023-12-20 17:47:28.117030+0800 通知[49180:2566753] 当前的sleep = 94

2023-12-20 17:47:29.119510+0800 通知[49180:2566753] 当前的sleep = 93

2023-12-20 17:47:30.117480+0800 通知[49180:2566753] 当前的sleep = 92

2023-12-20 17:47:31.116692+0800 通知[49180:2566753] 当前的sleep = 91

2023-12-20 17:47:32.119179+0800 通知[49180:2566753] 当前的sleep = 90

2023-12-20 17:47:33.121476+0800 通知[49180:2566753] 当前的sleep = 89

2023-12-20 17:47:33.121677+0800 通知[49180:2566753] 小孩子醒了,sleep = 89, dict = {

flag = weak;

sleep = 89;

}

谓词

相当于过滤器,指定过滤条件,将符合条件的对象保留下来。

  • 创建
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;

Person-------(int)age
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<%d",22];
.....
  • 使用
NSArray *array = [array filteredArrayUsingPredicate:predicate];

- (NSArray<ObjectType> *)filteredArrayUsingPredicate:(NSPredicate *)predicate;    
// evaluate a predicate against an array of objects and return a filtered array
- (BOOL)evaluateWithObject:(nullable id)object;    
// evaluate a predicate against a single object