“This is the seventh day of my participation in the August More Text Challenge. For details, see: August More Text Challenge.”
A preface.
KVO
Some details of- explore
KVO
The principle of - The custom
KVO
KVO official documentation link
I. Detailed analysis of KVO
About 1.context
Official details of the registration are shown belowListen to the callback
delete
static void *PersonNameContext = &PersonNameContext;
@interface LGViewController ()
@property (nonatomic, strong) LGPerson *person;
@end
@implementation LGViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [LGPerson new];
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:PersonNameContext];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.person.name = @"test";
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if(context == PersonNameContext){
NSLog(@"% @",change); }} - (void)dealloc{
[self.person removeObserver:self forKeyPath:@"name" context:PersonNameContext];
}
Copy the code
Print the result
According to the official documentation, if we use KVO without removeObserver for example, if we go into a VC and there’s a singleton that holds and observes the VC’s properties even if the VC is released and the singleton doesn’t release and continues to observe the VC’s properties, the VC that was released before the properties change will continue to receive the message The wild pointer crashed because it had been released
Two.KVO details
1. Manually observe the properties
// Automatic switch
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key{
return NO;
}
- (void)setName:(NSString *)name
{
[self willChangeValueForKey:@"name"];
_name = name;
[self didChangeValueForKey:@"name"];
}
Copy the code
2. Listen to a property that is controlled by two other variables
+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
if ([key isEqualToString:@"downloadProgress"]) {
NSArray *affectingKeys = @[@"totalData"The @"writtenData"];
keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
}
return keyPaths;
}
- (NSString *)downloadProgress{
if (self.writtenData == 0) {
self.writtenData = 10;
}
if (self.totalData == 0) {
self.totalData = 100;
}
return [[NSString alloc] initWithFormat:@"%f".1.0f*self.writtenData/self.totalData];
}
// Listen to the downloadProgress property
[self.person addObserver:self forKeyPath:@"downloadProgress" options:(NSKeyValueObservingOptionNew) context:NULL];
// Change these two attributes
self.person.writtenData += 10;
self.person.totalData += 1;
Copy the code
3. Observation of mutable arrays
[self.person addObserver:self forKeyPath:@"dateArray" options:(NSKeyValueObservingOptionNew) context:PersonDataArrayContext];
self.person.dateArray = [NSMutableArray arrayWithCapacity:1];
[[self.person mutableArrayValueForKey:@"dateArray"] addObject:@"1"]; Print the result2021-08-15 11:16:20.182185+0800 001- KVO [39513:1527764] {
kind = 1;
new= (); }2021-08-15 11:16:25.016788+0800 001- KVO [39513:1527764] {
indexes = "<_NSCachedIndexSet: 0x6000010b84e0>[number of indexes: 1 (in 1 ranges), indexes: (0)]";
kind = 2;
new = (
1
);
}
typedef NS_ENUM(NSUInteger, NSKeyValueChange) {
NSKeyValueChangeSetting = 1,
NSKeyValueChangeInsertion = 2,
NSKeyValueChangeRemoval = 3,
NSKeyValueChangeReplacement = 4}; kind=2Is of type INSERTCopy the code
Three.KVO principle
1. Kvo principle analysis
- Only properties are observed
setter
- The middle class –
self.person
->LGPerson isa
Have changedNSKVONotifying_LGPerson (LGPerson subclass)
- What are the things-method-properties
setNickName
–class
–dealloc
–_isKVOA
- Inherit – rewrite – actual implementation
Setter subclass
– Parent class changednickName
The value ofwillchange
Of the parent classsetter
didChange
NSKVONotifying_LGPerson
Whether to remove+isa
Will come back at the time of removal observation
// The listener is dynamically generatedNSKVONotifying_LGPerson
#pragma mark - iterates over classes and subclasses - (void)printClasses:(Class)cls{
// Total number of registered classes
int count = objc_getClassList(NULL, 0);
// Create an array containing the given object
NSMutableArray *mArray = [NSMutableArray arrayWithObject:cls];
// Get all registered classes
Class* classes = (Class*)malloc(sizeof(Class)*count);
objc_getClassList(classes, count);
for (int i = 0; i<count; i++) {
if (cls == class_getSuperclass(classes[i])) {
[mArray addObject:classes[i]];
}
}
free(classes);
NSLog(@"classes = %@", mArray);
}
Copy the code
Iv.KVO principle
- 1.
isa
->LGPerson
->NSKVONotifying_LGPerson
–disappear
- 1.1 Dynamic Generation
NSKVONotifying_LGPerson
- 1.2
LGPerson
VSNSKVONotifying_LGPerson
Father and son - 1.3
NSKVONotifying_LGPerson
What are the methods -
'setNickName' // Override the set methodCopy the code
-
`class` Copy the code
-
`dealloc` Copy the code
-
`_isKVOA` Copy the code
- 1.4
isa
Point back // through this method_isKVOA
- 1.5
NSKVONotifying_LGPerson
Whether to destroy
-2. Setter KVO instance method (setter)/class
-
2.1 Members VS attributes
-
2.2 Modifying LGPerson properties
#pragma mark - traversal method -ivar-property - (void)printClassAllMethod:(Class)cls{
unsigned int count = 0;
Method *methodList = class_copyMethodList(cls, &count);
for (int i = 0; i<count; i++) {
Method method = methodList[i];
SEL sel = method_getName(method);
IMP imp = class_getMethodImplementation(cls, sel);
NSLog(@"%@-%p",NSStringFromSelector(sel),imp);
}
free(methodList);
}
// Iterate over the methods of NSKVONotifying_LGPerson
[self printClassAllMethod:objc_getClass("NSKVONotifying_LGPerson")];
2021-08-15 12:20:25.681840+0800 002-- Discussion on KVO Principle [39748:1566211] setNickName:-0x7fff207bf03f
2021-08-15 12:20:25.682122+0800 002-- Discussion on KVO Principle [39748:1566211] class0x7fff207bdb49The 2021-08-15 12:20:25. 682305 + 0800-002KVODiscussion on principle [39748:1566211]dealloc0x7fff207bd8f7The 2021-08-15 12:20:25. 682472 + 0800-002KVODiscussion on principle [39748:1566211]_isKVOA0x7fff207bd8ef
Copy the code
remove
The former isNSKVONotifying_LGPerson
remove
After isLGPerson
instructionsisa
Refers to the back