oc基础

iOS KVC (六) KVC容器类及深层次原理

2018-05-17  本文已影响58人  奔跑吧小蚂蚁

iOS KVC(一)基本了解
iOS KVC (二) 不可不知的赋值深层次原理
iOS KVC (三)不可不知的取值深层次原理
iOS KVC (四)keyPath的深度解析
iOS KVC (五)KVC几种典型的异常处理
iOS KVC (六) KVC容器类及深层次原理
iOS KVC(七) KVC正确性的验证
iOS KVC (八) KVC几种常见应用
iOS KVC (九) KVC模型转化(1) 模型打印 description, debugDescription
iOS KVC (十)模型转换(2)模型转换

容器类

容器类主要是指NSArray、NSMutableArray、NSDictionary、NSMutableDictionary等有序容器和NSSet等无序容器。

有序不可变容器类

对于NSArray可以通过valueForKey:进行访问,如下代码所示

#import "ViewController.h"
@interface ViewController ()

@property (nonatomic, strong) NSArray *kvcArr;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self demoArray];
}

- (void)demoArray
{
    self.kvcArr = @[@1, @2, @3, @4];
    
    NSObject *obj = [self valueForKey:@"kvcArr"];
    
    NSLog(@"obj = %@", obj);
}

打印数据:
2018-05-17 14:46:38.862732+0700 KVC[30470:807433] obj = (
    1,
    2,
    3,
    4
)

对于NSDictionary也是一样的,下面看一下代码。

#import "ViewController.h"
@interface ViewController ()

@property (nonatomic, strong) NSDictionary *kvcDict;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self demoDictionary];
}

- (void)demoDictionary{
    self.kvcDict = @{@"1" : @"One", @"2" : @"Two", @"3" : @"Three"};
    
    NSObject *obj = [self valueForKey:@"kvcDict"];
    
    NSLog(@"obj = %@", obj);
}

打印数据:
2018-05-17 14:49:18.219101+0700 KVC[30534:809791] obj = {
    1 = One;
    2 = Two;
    3 = Three;
}
从上面我们可以看出对于有序不可变容器类NSArray和NSDictionary等等,都可以使用valueForKey :这个方法来获取该属性。

有序可变容器类

下面我们看一下可变容器类,比如说NSMutableArray和NSMutableDictionary。比如对于NSMutableArray可以使用下面方法获取数组。

#import "ViewController.h"
@interface ViewController ()

@property (nonatomic, strong) NSMutableArray *kvcArrM;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self demoNSMutableArray];
}

- (void)demoNSMutableArray
{
    NSArray *arr = @[@1, @2, @3, @4];
    self.kvcArrM = [NSMutableArray arrayWithArray:arr];
    
    NSObject *obj = [self mutableArrayValueForKey:@"kvcArrM"];
    
    NSLog(@"obj = %@", obj);
}

打印数据:
2018-05-17 15:37:17.358111+0700 KVC[31200:836978] obj = (
    1,
    2,
    3,
    4
)

下面我们看一下方法- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;的深层次原理。

下面我们就直接看代码

#import <UIKit/UIKit.h>

@interface ZFSecondVC : UIViewController
- (void)demoMutableArrayValueForKey;

- (void)addItem;

- (void)addAntherItem;

- (void)removeLastItem;

@end

#import "ZFSecondVC.h"

@interface ZFSecondVC ()
@property (nonatomic, strong) NSMutableArray *kvcArrM;

@end

@implementation ZFSecondVC

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
}

- (void)dealloc
{
    [self removeObserver:self forKeyPath:@"kvcArrM"];
}

#pragma mark - Object Private Function

- (void)demoMutableArrayValueForKey
{
    self.kvcArrM = [NSMutableArray array];
    [self addObserver:self forKeyPath:@"kvcArrM" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}

- (void)addItem
{
    [self.kvcArrM addObject:@"One"];
}

- (void)addAntherItem
{
    [[self mutableArrayValueForKey:@"kvcArrM"] addObject:@"Two"];
    [[self mutableArrayValueForKey:@"kvcArrM"] addObject:@"Three"];
}

- (void)removeLastItem
{
    [[self mutableArrayValueForKey:@"kvcArrM"] removeLastObject];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"change = %@", change);
    NSLog(@"arrM = %@", self.kvcArrM);
}

#import "ViewController.h"
#import "ZFSecondVC.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    ZFSecondVC *VC = [[ZFSecondVC alloc] init];
    
    [VC demoMutableArrayValueForKey];
    [VC addItem];
    [VC addAntherItem];
    [VC removeLastItem];
}

打印数据:

2018-05-17 16:03:54.130555+0700 KVC[31726:857467] change = {
    indexes = "<_NSCachedIndexSet: 0x600000222520>[number of indexes: 1 (in 1 ranges), indexes: (1)]";
    kind = 2;
    new =     (
        Two
    );
}
2018-05-17 16:03:54.130703+0700 KVC[31726:857467] arrM = (
    One,
    Two
)
2018-05-17 16:03:54.130910+0700 KVC[31726:857467] change = {
    indexes = "<_NSCachedIndexSet: 0x600000222820>[number of indexes: 1 (in 1 ranges), indexes: (2)]";
    kind = 2;
    new =     (
        Three
    );
}
2018-05-17 16:03:54.131154+0700 KVC[31726:857467] arrM = (
    One,
    Two,
    Three
)
2018-05-17 16:03:54.131295+0700 KVC[31726:857467] change = {
    indexes = "<_NSCachedIndexSet: 0x600000222820>[number of indexes: 1 (in 1 ranges), indexes: (2)]";
    kind = 3;
    old =     (
        Three
    );
}
2018-05-17 16:03:54.131417+0700 KVC[31726:857467] arrM = (
    One,
    Two
)

总结:
从上面可以看出,可变数组里面元素的改变可以被KVO监听到了。当调用[self.kvcArrM addObject:@"One"];时不会触发KVO,只有调用方式改变为[[self mutableArrayValueForKey:@"kvcArrM"] addObject:@"Two"];才会触发KVO。

无序可变容器类

对于无序可变容器常用的就是NSMutableSet,对于可变无序容器类和上面讲的可变有序容器类的数组有点相似,主要是下面这个方法。

- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;

下面看一下调用该方法底层深层次的一些东西。

上一篇 下一篇

猜你喜欢

热点阅读