Analysis of object-c Programming tips-KVO and KVC

Source: Internet
Author: User

Analysis of object-c Programming tips-KVO and KVC
KVC key-value encoding 1, Overview

KVO, that is, Key-Value Observing, provides a mechanism. When the attribute of a specified object is modified, the object will receive a notification. It plays a major role in message communication between the control layer and the model layer. The object in the controller layer observes the attributes of the model layer object, so that the view object can indirectly observe the attributes of the model through the controller layer and decouple the model and view.

For example, demo project IOSKvoUse

Initialization: The model object uses the current viewController as the observer of its score attribute.

1. In viewController

 

[m_studentKVO addObserver:selfforKeyPath:@m_stuScoreoptions:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:nil];

 

2. You can click the button on the interface to change the model data.

 

[m_studentKVO setValue:[NSStringstringWithFormat:@%d,score]forKey:@m_stuScore];

 

3. Because viewController is registered as an observer, the observeValueForKeyPath of the observer will be called and the viewControllermodel data will be updated.

4. You can refresh the corresponding interface in the callback method of the observer.

 

if([keyPath isEqualToString:@m_stuScore]){        m_lable.text = [NSStringstringWithFormat:@score:%@, [m_studentKVOvalueForKey:@m_stuScore]];    }

 

Ii. KVO Diagram 1. determine whether there is a KVO scenario, that is, whether an object needs to notify its attribute to change to another object. PersonObjectNeed to know BankObjectAttributes accountBalanceAny changes. 2. PersonObjectYou must register yourself BankObjectOf accountBalanceAttribute observer. By sending addObserver: forKeyPath: options: context: Message.

3. The observer responds to the attribute change notification by implementing the observeValueForKeyPath: ofObject: change: context: method. In this method, the observer performs personalized operations on the notification response. If the parent class implements this method, pay attention to calling the parent class method at the end of the method.

 

4. If you follow the KVO programming logicobserveValueForKeyPath:ofObject:change:context:The method is automatically called.

 

Iii. Usage

The system framework already supports KVO and is easy to use.

L register the observer:

 

- (void)registerAsObserver {    /*     Register 'inspector' to receive change notifications for the openingBalance property of     the 'account' object and specify that both the old and new values of openingBalance     should be provided in the observe… method.     */    [account addObserver:inspector             forKeyPath:@openingBalance                 options:(NSKeyValueObservingOptionNew |                            NSKeyValueObservingOptionOld)                    context:NULL];}
Receive notification addObserver:forKeyPath:options:context: The method does not target the observer, the observer, and context For any strong reference, That is to say, they must be guaranteed by yourself.

 

Returns a change dictionary:

1, NSKeyValueChangeKindKey

Normal attribute change: NSKeyValueChangeKindKey returns NSKeyValueChangeSetting

Set object change: NSKeyValueChangeInsertion, NSKeyValueChangeRemoval, or NSKeyValueChangeReplacement.

 

2, NSKeyValueChangeOldKey

Returns the value before the object property change.

3, NSKeyValueChangeNewKey

Returns the value after the attribute is changed.

 

-(Void) observeValueForKeyPath :( NSString *) keyPath ofObject :( id) object change :( NSDictionary *) change context :( void *) context {if ([keyPath isEqual: @ openingBalance]) {[openingBalanceInspectorField setObjectValue: [change objectForKey: NSKeyValueChangeNewKey];}/* If the parent class implements this method, do not forget to call it. NSObject does not implement this method. */[super observeValueForKeyPath: keyPath ofObject: object change: change context: context];}

Delete observer

 

 

- (void)unregisterForChangeNotification {    [observedObject removeObserver:inspector forKeyPath:@openingBalance];}


 

4. Follow KVO

Class attributes must follow KVC. The KVC method is used to modify attributes and trigger notifications. The observer registers itself and implements the observer method.

KVO can be implemented in two ways. One is the automatic notification method supported by NSObject, which is effective for all attributes of classes that follow KVC. Manual implementation means more controllability, but also more encoding.

1. automatic notification

For example, the demo project KVOSalary

You can send automatic notifications in the following ways: Follow the KVC setter method, KVC method, and set proxy.

 

Use the setter method [account setName: @ Savings]; // use setValue: forKey :. [account setValue: @ Savings forKey: @ name]; // use keypath, where 'account' is a kvc-compliant property of 'document '. [document setValue: @ Savings forKeyPath: @ account. name]; // use mutableArrayValueForKey: returns the set proxy. transaction * newTransaction = [[Transaction alloc] init]; NSMutableArray * transactions = [account mutableArrayValueForKey: @ transactions]; [transactions addObject: newTransaction];

2. Manual notification

 

For example, the demo project KVOSalaryManual

Manual control provides more fine-grained control over how and when to send notifications. It can be used to reduce unnecessary notifications and send one notification to multiple attributes.

Override NSObject's class method: automaticallyNotifiesObserversForKey: to implement manual notification, you need to return NO for the attribute requiring manual notification. At the same time, you need to call the parent class method for other attributes. You can use both automatic and manual notifications in a class.

 

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {     BOOL automatic = NO;    if ([theKey isEqualToString:@openingBalance]) {        automatic = NO;    }    else {        automatic = [super automaticallyNotifiesObserversForKey:theKey];    }    return automatic;}

Advantages and precautions of manual notification

 

 

Notifications that do not need to be sent can no longer be sent. That is to say, we should test the input parameters before sending the notification.

 

 

    if(_accountMoney !=accountMoney)    {        [self willChangeValueForKey:@accountMoney];        _accountMoney = accountMoney;        [self didChangeValueForKey:@accountMoney];    }

Multiple keys are required for one change. Add multiple keys to the set method.

 

 

    [self willChangeValueForKey:@accountMoney];    [self willChangeValueForKey:@itemChanged];    _accountMoney = accountMoney;    _itemChanged++;    [self didChangeValueForKey:@accountMoney];    [self didChangeValueForKey:@itemChanged];


 

 

Collection classes should note: not only the type to be changed, but also the scope to be changed must be provided.

 

 

    NSUInteger count = _transationsArray.count;    NSIndexSet *set = [NSIndexSetindexSetWithIndexesInRange:NSMakeRange(0, count)];     [self willChange:NSKeyValueChangeRemoval     valuesAtIndexes:set forKey:@transationsArray];    [_transationsArray removeObjectsAtIndexes:set];    [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:set forKey:@transationsArray];

 

5. Observe the dependency between keys.

For example, the demo project KVODependentKey

For example, a user has a fullName attribute, which is observed by other observers. It depends on the firstName and lastName attributes. That is to say, when you set firstName or lastName, its fullName observer needs to be notified.

 

This is similar to the itemChanged and accountMoney mentioned above. Which uses the nest notification mechanism. Call two didChange methods at the same time in the custom method.

The Code is as follows:

 

-(void)setAccountMoneyNestChangeNotification:(int)accountMoney{    [self willChangeValueForKey:@accountMoney];    [self willChangeValueForKey:@itemChanged];     _accountMoney =accountMoney;    _itemChanged++;     [self didChangeValueForKey:@accountMoney];    [self didChangeValueForKey:@itemChanged];}

 

It encapsulates a layer-by-layer method to implement the modification of multiple attributes caused by an attribute change. It emphasizes that multiple attributes are modified upon a change. It is emphasized that modifications to multiple attributes will affect a certain attribute and change to another attribute. A dependency mechanism is used here. The fullName attribute depends on multiple keys, you only need to tell the KVO framework how it depends.

 

How to Establish dependency?

 

The keyPathsForValuesAffectingValueForKey method is used to return the set dependency set corresponding to the specified key. The framework Automatically Establishes the dependency between fullName and the other two attributes. + (NSSet *) keyPathsForValuesAffectingValueForKey :( NSString *) key {NSSet * keyPaths = [superkeyPathsForValuesAffectingValueForKey: key]; if ([key is=tostring: @ fullName]) {NSArray * affectingKeys = @ [@ lastName, @ firstName]; keyPaths = [keyPaths setByAddingObjectsFromArray: affectingKeys];} return keyPaths ;}

Vi. Observer Mode

 

1. Concept

For example, the demo project ObserverDesignPattern

The observer mode defines one-to-multiple dependencies between objects. When the State of an object changes, all objects dependent on it are notified and automatically updated.Take QQ as an example. When you and your qq friends are dependent on each other, when your friends go online, you can see the status of your friends going online. When they go offline, you can see his offline information. When his name is changed, you can also see his name changed. In this case, you are an observer, and your friends are observed objects, which are generally called target objects. You may ask you if you go online or go offline, and your friends will know, right. In this case, you are a target object, and your friends are converted into observers. That is to say, the observer and the target object are only naming logics of dependencies in a notification scenario. The observer can also be the target object. The following code is implemented using this strategy.

2. Two Classes

An Observer, or a subscriber, receives a notification when the object it observes changes its status.

Subject goal: it is the object to be observed and has its own state change method and notification method.

About implementation?

1. The base class target object encapsulates the methods for adding, deleting, and notifying the observer. The derived class target object is responsible for the specific attribute operations to be observed, and CALLS yyallobservers where the notification is needed.

2. The base class observer object declares the function update method, which can provide default implementation. Like Apple, observeValueForKeyPath throws an exception. This is a good programming practice because it can expose errors earlier. It is best not to provide an empty implementation. This may be because the programmer's error does not implement observeValueForKeyPath, but the compiler does not display this error.

3. Common class framework Diagram

 

 

4. Where can I add or delete an observer?

It is best to encapsulate the operations to add and delete the observer to the target or the observer class, instead of using a driver as used in the demo (my main intention is to make the class structure clearer ). In general, you can add it to init and delete it in dealloc. In this way, the user will not forget the last delete operation due to programming negligence.

7. Implementation of KVO

For example, the demo project KVOPrinciple

KVO is implemented by isa-swizzling. The basic process is that the compiler automatically creates a derived class for the observed object and points the isa of the observed object to the derived class. If you have registered an observation of a certain attribute of a target object, the derived class will override this method and add the notification code in it. This requires a basic understanding of the OC running process. When sending a message, OC finds the class object to which the current object belongs through the isa pointer, and the class object stores the instance method of the current object. Therefore, when sending a message to this object, actually, it is the method sent to the object of the derived class. Because the compiler override the method of the derived class and adds the notification code, it will send a notification to the registered object. Note that the derived class only overrides the property method that registers the observer.

 

Example:

There is a Person class, which has three attributes firstName, lastName, and personId, which are observed objects. There is a PersonObserver class, which observes firstName and lastName, but does not observe personId.

Theoretically, the derived class will overwrite the setFirstName and setLastName methods of the base class, not the setPersonId method. Access this person object through the runtime function object_getClass (p) and a person object namedNSKVONotifying_Person class object.Access through the [p class] method, then we can see that it is still a person object, because the derived class also overrides the class function. When sending a class message to p, the class method of the derived class is also found.

You can print the function tables of different types of objects for testing. Obtain the IMP implementation of its setFirstName for the derived class and the base class, and then directly call and compare it. Currently, using IMP for the base class will crash. The reason is unknown. If the derived class uses its IMP implementation, notifications can be sent normally, which indicates that the implementation of the derived class is used.


8. Summary 1. Introduction

Key-value encoding uses String identifiers to indirectly obtain object attributes. It is the foundation of Cocoa programming, including Cocoa Data, application scripting, binding technology, and attribute declaration. The scripting and binding technology is specifically used for OSX Cocoa. You can use key-value encoding to simplify programming code. Jastor uses the unified setValueForKey and valueForKey.

2. Access Object Attributes and KVC2.1. KVC uses the following four methods:

-(Id) valueForKey :( NSString *) key;

-(Void) setValue :( id) value forKey :( NSString *) key;-(id) valueForKeyPath :( NSString *) keyPath;

-(Void) setValue :( id) value forKeyPath :( NSString *) keyPath;

KVC uses the key or keypath of the string to locate the object attributes. The Key has naming management. It starts with an ASCII code and has no space. It is generally the attribute name. KeyPath is a string separated by points to traverse the deepest attribute values layer by layer.

 

Example above:

[Employee1setValue: @ "lpstudy" forKey: @ "name"];

[EMPLOYEE 1 setvalue: @ [EMPLOYEE 1, EMPLOYEE 2, employee 3] forKeyPath: @ "manager. directerPorts"];

2.2. Use the accessors Method

If yes, the accessor method is still valid. If there is no corresponding accessor method, you can use the above setValue and valueForKey to directly read the property value of the object.

2.3, with KVC capability

To make a class have the KVC function, you must meet one of the following requirements:

L class uses key to declare attributes

@ Property (nonatomic, readonly, strong) NSString * personName;

L it implements the get method and set Method of the key name. If the bool type is returned, the isKey method.

L declares an instance variable, key or _ key

Note:

L valueForKey and valueForKeyPath return the value of the specified key and keyPath. If this key does not exist, valueForUndefinedKey: is called :. Its default implementation is to throw NSUndefinedKeyException; The subclass can rewrite this behavior.

L try to set nil for a non-object type. The object calls setNilValueForKey by default. This method throws NSInvalidArgumentException by default. Your program can overwrite this method to a default value, and then setValue: forKey: sets a new value.

L authentication mechanism validatePersonName

2.4, Search Method

I have not conducted any tests on the network.

SetValue: forKey search method:

1. First search for set : Method. If the @ property, @ synthsize is used for processing, @ synthsize indicates that the compiler automatically generates the set : The setter method in the format. In this case, it will be searched directly.

2. The above setter method is not found. If the class method accessInstanceVariablesDirectly returns YES (Note: This is the class method implemented in NSKeyValueCodingCatogery, and YES is returned by default), press _ , _ Is , , Is In order to search for the member name value.

3. If yes, the value of the member is set. If no value is found, setValue: forUndefinedKey: is called :.

ValueForKey Search Method

1. Press get , , Is To find the getter method and call it directly. If it is a built-in value type such as bool or int, NSNumber will be converted. If it is another type similar to struct, NSValue will be converted.

2. Otherwise, query countOf. , ObjectIn AtIndex :, AtIndexes format. If countOf And one of the other two methods will return a proxy set (collection proxy object) that can respond to all NSArray methods ). The NSArray message method sent to this proxy set (collection proxy object) takes countOf , ObjectIn AtIndex :, AtIndexes is called in the form of a combination of these methods. There is also an optional get : Range: method.

3. If not found, search for countOf again. , EnumeratorOf , MemberOf : Format method. If all three methods are found, a proxy set (collection proxy object) that can respond to all NSSet methods is returned ). The NSSet message method sent to this proxy set (collection proxy object) takes countOf , EnumeratorOf , MemberOf : Called in combination.

4, still not found, if the class method accessInstanceVariablesDirectly returns YES, then press _ , _ Is , , Is To directly search for member names. If an instance variable is found, its value will be returned in the form of an object (NSNumber encapsulation for the value type, and NSValue encapsulation for others ).

5. If no more information is found, call valueForUndefinedKey :.

 

Search for members of an ordered set, such as NSMutableArray.

MutableArrayValueForKey: The search method is as follows:

1. Search for insertObject: in AtIndex:, removeObjectFrom AtIndex: or insert : AtIndexes, remove AtIndexes: Format method.

If at least one insert method and at least one remove method are found, a proxy set that can respond to all NSMutableArray methods is also returned. Then the NSMutableArray message method sent to this proxy set uses insertObject: in AtIndex:, removeObjectFrom AtIndex:, insert : AtIndexes, remove AtIndexes: called in combination. There are also two optional interfaces: replaceObjectIn AtIndex: withObject:, replace AtIndexes: :.

2. Otherwise, search for set : Format method. If it is found, the NSMutableArray sent to the proxy set will eventually call the set : Method.

That is to say, after modifying the proxy set retrieved by mutableArrayValueForKey : Assign a value again. This method is much less efficient, so we recommend that you implement the above method.

3. Otherwise, if the class method accessInstanceVariablesDirectly returns YES, press _ , To directly search for member names. If it is found, the NSMutableArray message method sent is directly transferred to this member for processing.

4. If no result is found, call setValue: forUndefinedKey :.

Search unordered set members, such as NSSet.

MutableSetValueForKey: The search method is as follows:

1. Search for add Object:, remove Object: or add :, Remove : Format method. If at least one insert method and at least one remove method are found, a proxy set that can respond to all NSMutableSet methods is returned. Then the NSMutableSet message method sent to this proxy set is used to add Object:, remove Object:, add :, Remove : Called in combination. There are also two optional interfaces: intersect , Set :.

2. If the reciever is ManagedObejct, the search will not continue.

3. Otherwise, search for set : Format method. If it is found, the NSMutableSet sent to the proxy set will eventually call the set : Method. That is to say, after modifying the proxy set retrieved by mutableSetValueForKey : Assign a value again. This method is much less efficient, so we recommend that you implement the above method.

4. Otherwise, if the class method accessInstanceVariablesDirectly returns YES, press _ , To directly search for member names. If it is found, the NSMutableSet message method sent is directly transferred to this member for processing.

 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.