As we all know, Apple does not open source the source code of KVC(key-value-coding), so we cannot directly understand the underlying implementation principle of KVC from the source code, but we can learn and explore its underlying implementation principle from apple’s official documents. Remember that when there is no open source code, Official documents are the best learning materials

Key – Value – Coding apple official documentation address: developer.apple.com/library/arc…).

Below, we start with analyzing the official documents to explore the principle of KVC: (1) the Object Properties of An Object typically specifies Properties in its interface declaration and these properties belong to one of several categories:

Attributes. These are simple values, such as a scalars, strings, or Boolean values. Value objects such as NSNumber and other immutable types such as as NSColor are also considered Attributes. To-one relationships. These are mutable objects with properties of their own change without the object itself changing. For example, a bank account object might have an owner property that is an instance of a Person object, Which itself has an address property. The owner’s address may change without changing The owner reference held by The Bank account. The owner of The bank account did not change. Only their address did collection objects. You commonly use an instance of NSArray or NSSet to hold such a collection, although custom collection classes are also possible. The BankAccount object declared in Listing 2-1 demonstrates one of each type of property.

Listing 2-1Properties of the BankAccount object @interface BankAccount : NSObject

@property (nonatomic) NSNumber* currentBalance; // An attribute @property (nonatomic) Person* owner; // A to-one relation @property (nonatomic) NSArray< Transaction* >* transactions; // A to-many relation

@end In order to maintain encapsulation, An object typically provides accessor methods for the properties on its interface. The object’s author may write these methods explicitly or may rely on the compiler to synthesize them automatically. Either way, the author of code using one of these accessors must write the property name into the code before compiling it. The name of the accessor method becomes a static part of the code that is using it. For example, given the bank account object declared in Listing 2-1, the compiler synthesizes a setter that you can invoke for the myAccount instance:

[myAccount setCurrentBalance: @ (100.0)]; This is direct, but lacks flexibility. A key-value coding compliant object, on the other hand, Offers a more general mechanism to access an object’s properties using string identifiers.

Identifying an Object’s Properties with Keys and Key Paths

A key is a string that identifies a specific property. Typically, by convention, the key representing a property is the name of the property itself as it appears in code. Keys must use ASCII encoding, may not contain whitespace, and usually begin with a lowercase letter (though there are exceptions, such as the URL property found in many classes).

Because the BankAccount class in Listing 2-1 is key-value coding compliant, it recognizes the keys owner, currentBalance, and transactions, which are the names of its properties. Instead of calling the setCurrentBalance: method, you can set the value by its key:

[myAccount setValue: @ (100.0) forKey: @ “currentBalance”]. In fact, you can set all the properties of the myAccount object with the same method, using different key parameters. Because the parameter is a string, it can be a variable that is manipulated at run-time.

A key path is a string of dot-separated keys used to specify a sequence of object properties to traverse. The property of the first key in the sequence is relative to the receiver, and each subsequent key is evaluated relative to the value of the previous property. Key paths are useful for drilling down into a hierarchy of objects with a single method call.

For example, the key path owner.address.street applied to a bank account instance refers to the value of the street string that is stored in the address of the bank account’s owner, assuming the Person and Address classes are also key-value coding compliant.

NOTE

In Swift, instead of using a string to indicate a key or key path, you can use a #keyPath expression. This offers the advantage of a compile time check, as described in the Keys and Key Paths section of the Using Swift with Cocoa and Objective-C (Swift 3) guide.

Getting Attribute Values Using Keys

An object is key-value coding compliant when it adopts the NSKeyValueCoding protocol. An object that inherits from NSObject, which provides a default implementation of the protocol’s essential methods, automatically adopts this protocol with certain default behaviors. Such an object implements at least the following basic key-based getters:

valueForKey: – Returns the value of a property named by the key parameter. If the property named by the key cannot be found according to the rules described in Accessor Search Patterns, then the object sends itself a valueForUndefinedKey: message. The default implementation of valueForUndefinedKey: raises an NSUndefinedKeyException, but subclasses may override this behavior and handle the situation more gracefully. valueForKeyPath: – Returns the value for the specified key path relative to the receiver. Any object in the key path sequence that is not Key-value coding compliant for a particular key — that is, for which the default implementation of value for key: Always find an accessor method – receives a valueForUndefinedKey: message. DictionaryWithValuesForKeys: – Returns the values for an array of keys relative to the receiver. The method calls valueForKey: for each key in the array. The returned NSDictionary contains values for all the keys in the array. NOTE

Collection objects, such as NSArray, NSSet, and NSDictionary, can’t contain nil as a value. Instead, you represent nil values using the NSNull object. NSNull provides a single instance that represents the nil value for object properties. The default implementations of dictionaryWithValuesForKeys: and the related setValuesForKeysWithDictionary: translate between NSNull (in the dictionary parameter) and nil (in the stored property) automatically.

When you use a key path to address a property, if any but the final key in the key path is a to-many relationship (that is, it references a collection), the returned value is a collection containing all the values for the keys to the right of the to-many key. For example, requesting the value of the key path transactions.payee returns an array containing all the payee objects for all the transactions. This also works for multiple arrays in the key path. The key path accounts.transactions.payee returns an array with all the payee objects for all the transactions in all the accounts.

Setting Attribute Values Using Keys

As with getters, key-value coding compliant objects also provide a small group of generalized setters with default behavior based upon the implementation of the NSKeyValueCoding protocol found in NSObject:

setValue:forKey: – Sets the value of the specified key relative to the object receiving the message to the given value. The default implementation of setValue:forKey: automatically unwraps NSNumber and NSValue objects that represent scalars and structs and assigns them to the property. See Representing Non-Object Values for details on the wrapping and unwrapping semantics. If the specified key corresponds to a property that the object receiving the setter call does not have, the object sends itself a setValue:forUndefinedKey: message. The default implementation of setValue:forUndefinedKey: raises an NSUndefinedKeyException. However, subclasses may override this method to handle the request in a custom manner. setValue:forKeyPath: – Sets the given value at the specified key path relative to the receiver. Any object in the key path sequence that is not key-value coding compliant for a particular key receives a setValue:forUndefinedKey: message. setValuesForKeysWithDictionary: – Sets the properties of the receiver with the values in the specified dictionary, using the dictionary keys to identify the properties. The default implementation invokes setValue:forKey: for each key-value pair, substituting nil for NSNull objects as required. In the default implementation, when you attempt to set a non-object property to a nil value, the key-value coding compliant object sends itself a setNilValueForKey: message. The default implementation of setNilValueForKey: raises an NSInvalidArgumentException, but an object may override this behavior to substitute a default value or a marker value instead, as described in Handling Non-Object Values.

Using Keys to Simplify Object Access

To see how key-based getters and setters can simplify your code, consider the following example. In macOS, NSTableView and NSOutlineView objects associate an identifier string with each of their columns. If the model object backing the table is not key-value coding compliant, the table’s data source method is forced to examine each column identifier in turn to find the correct property to return, as shown in Listing 2-2. Further, in the future, when you add another property to your model, in this case the Person object, you must also revisit the data source method, adding another condition to test for the new property and return the relevant value.

Listing 2-2Implementation of data source method without key-value coding

  • (id)tableView:(NSTableView *)tableview objectValueForTableColumn:(id)column row:(NSInteger)row

{ id result = nil; Person *person = [self.people objectAtIndex:row];

if ([[column identifier] isEqualToString:@"name"]) {
    result = [person name];
} else if ([[column identifier] isEqualToString:@"age"]) {
    result = @([person age]);  // Wrap age, a scalar, as an NSNumber
} else if ([[column identifier] isEqualToString:@"favoriteColor"]) {
    result = [person favoriteColor];
} // And so on...

return result;
Copy the code

} On the other hand, Listing 2-3 shows a much more compact implementation of the same data source method that takes advantage of a key-value coding compliant Person object. Using only the valueForKey: getter, the data source method returns the appropriate value using the column identifier as a key. In addition to being shorter, it is also more general, because it continues to work unchanged when new columns are added later, As long as the column identifiers always match the model object’s property names.

Listing 2-3Implementation of data source method with key-value coding

  • (id)tableView:(NSTableView *)tableview objectValueForTableColumn:(id)column row:(NSInteger)row

{ return [[self.people objectAtIndex:row] valueForKey:[column identifier]]; }

The above document mainly explains:

1. Access object attributes category description:

  • Attribute: Columns are simple values such as scalars, strings, or Booleans.
  • For example, an object property named Person is listed in the BankAccount class in the official document.
  • A to-many relation, e.g. A group of numbers, A set

The research of KVC is also carried out on these types.

  1. Getting Attribute Values Using Keys
  • Access using the key value: valueForKey
  • Access using the key-value path: valueForKeyPath
  • Use a dictionary to access: dictionaryWithValuesForKeys: method, was introduced into an array, the array elements of the corresponding attribute Key value represented by string, returns the Key value of the dictionary, the following code:
// jsbankAccount. h file @interface JSBankAccount: NSObject @property (nonatomic, copy) NSString* bankName; // An attribute @property (nonatomic, strong) JSPerson* owner; // A to-one relation @property (nonatomic, strong) NSArray* dayArray; // A to-many relation @end // jsperson. h file @interface JSPerson: NSObject @property (nonatomic, copy) NSString* name; @ the end / / attention because document specified dictionaryWithValuesForKeys internal value is the Key for each array element valueForKey invoked method, so the inside of the array elements cannot be as the Key path; // Test: JSBankAccount *methodTest = [[JSBankAccount alloc] init]; BankName = @" industrial and Commercial bank "; methodTest.owner = [[JSPerson alloc] init]; methodTest.owner.name = @"Julian"; NSLog(@"name =%@", [methodTest valueForKey:@"bankName"]); //valueForKeyPath access NSLog(@"%@",[methodTest valueForKeyPath:@"owner.name"]); / / dictionaryWithValuesForKeys method access, the owner. The name cannot be arr array element value, otherwise call dictionaryWithValuesForKeys method complains valueForUndefinedKey; NSArray * arr = @[@"bankName",@"owner"]; NSLog(@"%@",[methodTest dictionaryWithValuesForKeys:arr]);Copy the code
  1. Setting Attribute Values Using Keys
  • SetValue :forKey: sets the corresponding value of the object receiving the message to the given value according to the specified key value
  • SetValue :forKeyPath: sets the value corresponding to the object receiving the message to the given value according to the key-value path
  • SetValuesForKeysWithDictionary: according to the dictionary keys to a receive message object corresponding to the value is set to the given value, this method will traverse the dictionary, the default implementation calls the setValue: forKey method

Note: didn’t find the corresponding key value is to be able to perform setValue: forUndefinedKey: method, and an error

The function of Accessing the Collection Properties is (61).

  • mutableArrayValueForKey: and mutableArrayValueForKeyPath:
  • mutableSetValueForKey: and mutableSetValueForKeyPath:
  • mutableOrderedSetValueForKey: and mutableOrderedSetValueForKeyPath:

Aggregation Operators

  • @avg +<.key>: Returns the arithmetic average
  • @count: returns the number of elements in the collection. If the correct.key path is specified, the.key path is ignored
  • @max +<.key>: When the @max operator is specified, valueForKeyPath: searches for collection items named by the correct key path and returns the largest item. Searches are compared using the compare: method, as defined by many Foundation classes, such as the NSNumber class. Therefore, the properties indicated by the correct key path must contain objects that respond meaningfully to this message. Searches ignore null-valued collection items
  • @min +<.key>: When the @min operator is specified, valueForKeyPath: searches for collection entries named by the correct key path and returns the smallest entry. Searches are compared using the compare: method, as defined by many Foundation classes, such as the NSNumber class. Therefore, the properties indicated by the correct key path must contain objects that respond meaningfully to this message. Searches ignore null-valued collection items.
  • @sum +<.key>: When the @sum operator is specified, valueForKeyPath: reads the property specified by the correct key path for each element in the collection, converts it to a double value (zero instead of nil), and evaluates the sum of those values. It then returns the result stored in the NSNumber instance.

The Array operator results in valueForKeyPath: Returns an Array of objects corresponding to the specific set of objects indicated by the correct key path.

  • @distinctUnionOfObjects: When specifying the @distinctUnionOfObjects operator, valueForKeyPath: Creates and returns an array containing the different objects of the collection corresponding to the properties specified by the correct key path.
  • @unionOfObjects: When the @UnionOfObjects operator is specified, valueForKeyPath: Creates and returns an array containing all the objects in the collection corresponding to the property specified by the correct key path. Unlike @distinctUnionOfObjects, duplicate objects are not deleted

Nesting Operators operate on nested sets, where each entry in the set itself contains a set.

  • @distinctUnionOfArrays: When specifying the @distinctUnionOfArrays operator, valueForKeyPath: Creates and returns an array containing different combinations of objects for all collections corresponding to the properties specified by the correct key path.
  • @unionOfArrays: When the @unionOfArrays operator is specified, valueForKeyPath: Creates and returns an array containing the combination of all objects in all collections corresponding to the property specified by the correct key path, without removing duplicates.
  • @distinctUnionOfSets: When specifying the @distinctUnionOfSets operator, valueForKeyPath: Creates and returns an NSSet object containing different combinations of all collections corresponding to the properties specified by the correct key path.
//JSTeather.h
typedef struct {
    float x, y, z;
} ThreeFloats;

@interface JSTeather : NSObject
@property (nonatomic, copy)   NSString          *name;
@property (nonatomic, copy)   NSString          *subject;
@property (nonatomic, copy)   NSString          *nick;
@property (nonatomic, assign) int               age;
@property (nonatomic, assign) int               height;
@property (nonatomic, strong) NSMutableArray    *penArr;
@property (nonatomic)         ThreeFloats       threeFloats;
@end


//ViewController.m
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    JSBankAccount *methodTest = [[JSBankAccount alloc] init];
    //属性直接赋值,调用setter方法
    methodTest.bankName = @"工商银行";
    methodTest.owner = [[JSPerson alloc] init];
    methodTest.owner.name = @"Julian";
    /*
     使用秘钥访问属性的方法
     */
    //1.valueForKey访问
    NSLog(@"name =%@", [methodTest valueForKey:@"bankName"]);
    //2.valueForKeyPath 访问
    NSLog(@"%@",[methodTest valueForKeyPath:@"owner.name"]);
    //3.dictionaryWithValuesForKeys 方法访问
    NSArray * arr = @[@"bankName",@"owner"];
    NSLog(@"%@",[methodTest dictionaryWithValuesForKeys:arr]);
    
    /*
     使用密钥设置属性值方法探究
     */
    //1.setValue:forKey:方法设置
    [methodTest setValue:@"中国银行" forKey:@"bankName"];
    NSLog(@"bankName@setValue:%@",methodTest.bankName);
    //2.setValue:forKeyPath:方法设置
    [methodTest setValue:@"xiaoming" forKeyPath:@"owner.name"];
    NSLog(@"owner.name@setValue:forKeyPath:===%@",methodTest.owner.name);
    //2.setValuesForKeysWithDictionary:方法设置
    NSDictionary *keyValuesDic = @{@"bankName":@"广发银行"};
    [methodTest setValuesForKeysWithDictionary:keyValuesDic];
    NSLog(@"setValuesForKeysWithDictionary:===%@",methodTest.bankName);
    
    //访问数组
    [methodTest setValue:@[@1,@2,@3,@4,@5] forKey:@"dayArray"];
    NSLog(@"dayArray:===%@",[methodTest valueForKey:@"dayArray"]);
    NSLog(@"dayArray@mutableArrayValueForKeyPath:===%@",[methodTest mutableArrayValueForKey:@"dayArray"]);
    
   
    // 聚合运算符测试
//    [self aggregation_operators_test];
    //数组运算符测试
//    [self arrayOperator];
    //嵌套数组
//    [self arrayNesting];
    //嵌套set
    [self setNesting];
    // Do any additional setup after loading the view.
}

//聚合运算符 @avg、@count、@max、@min、@sum
- (void)aggregation_operators_test{
    NSMutableArray *testArray = [NSMutableArray array];
    for (int i = 0; i<10; i++) {
        JSTeather *teather = [[JSTeather alloc]init];
        NSDictionary *dic = @{
            @"name":[NSString stringWithFormat:@"酷走天涯_%d",i],
            @"age":@(18+i),
            @"nick":[NSString stringWithFormat:@"Julian_%d",i],
            @"height":@(170 + i),
        };
        [teather setValuesForKeysWithDictionary:dic];
        [testArray addObject:teather];
    }
    NSLog(@"testArray====%@", testArray);
    //返回一个数组,包含对每个接收方的元素调用-valueForKey:的结果
    NSLog(@"height===%@", [testArray valueForKey:@"height"]);
    
    //身高平均值
    float avg =[[testArray valueForKeyPath:@"@avg.height"] floatValue];
    NSLog(@"avg height===%f",avg);
    //元素个数
    int count = [[testArray valueForKeyPath:@"@count"] intValue];
    NSLog(@"@count.height===%d", count);
    //求和敏
    int sum = [[testArray valueForKeyPath:@"@sum.height"] intValue];
    NSLog(@"%d", sum);
    //最大值
    int max = [[testArray valueForKeyPath:@"@max.height"] intValue];
    NSLog(@"@max.height===%d", max);
    //最小值
    int min = [[testArray valueForKeyPath:@"@min.height"] intValue];
    NSLog(@"@max.height===%d", min );
}

// 数组操作符 @distinctUnionOfObjects @unionOfObjects
- (void)arrayOperator{
    NSMutableArray *teatherArray = [NSMutableArray array];
    for (int i = 0; i < 10; i++) {
        JSTeather *teather = [[JSTeather alloc] init];
            NSDictionary* dic = @{
                @"name":[NSString stringWithFormat:@"酷走天涯_%d",i],
                @"age":@(18+i),
                @"nick":[NSString stringWithFormat:@"Julian_%d",i],
                @"height":@(170 + i%3),
            };
        [teather setValuesForKeysWithDictionary:dic];
        [teatherArray addObject:teather];
    }
    NSLog(@"testArray====%@", teatherArray);
    NSLog(@"height====%@", [teatherArray valueForKey:@"height"]);
    // 返回操作对象指定属性的集合, 不去重
    NSArray* arr1 = [teatherArray valueForKeyPath:@"@unionOfObjects.height"];
    NSLog(@"@unionOfObjects.height== %@", arr1);
    // 返回操作对象指定属性的集合 -- 去重
    NSArray* arr2 = [teatherArray valueForKeyPath:@"@distinctUnionOfObjects.height"];
    NSLog(@"@distinctUnionOfObjects.height== %@", arr2);
    
}

// 嵌套集合(array&set)操作 @distinctUnionOfArrays @unionOfArrays @distinctUnionOfSets
- (void)arrayNesting{
    NSMutableArray *teatherArray1 = [NSMutableArray array];
    for (int i = 0; i < 10; i++) {
        JSTeather *teather = [[JSTeather alloc] init];
            NSDictionary* dic = @{
                @"name":[NSString stringWithFormat:@"酷走天涯_%d",i],
                @"age":@(18+i),
                @"nick":[NSString stringWithFormat:@"Julian_%d",i],
                @"height":@(170 + i),
            };
        [teather setValuesForKeysWithDictionary:dic];
        [teatherArray1 addObject:teather];
    }
    
    NSMutableArray *teatherArray2 = [NSMutableArray array];
    for (int i = 0; i < 10; i++) {
        JSTeather *teather = [[JSTeather alloc] init];
            NSDictionary* dic = @{
                @"name":[NSString stringWithFormat:@"酷酷_%d",i],
                @"age":@(18+i),
                @"nick":[NSString stringWithFormat:@"Son_%d",i],
                @"height":@(180 + i%3),
            };
        [teather setValuesForKeysWithDictionary:dic];
        [teatherArray2 addObject:teather];
    }
    
    // 嵌套数组
    NSArray* nestArr = @[teatherArray1, teatherArray2];
    //嵌套数组执行valueForKey方法,返回结果也是嵌套数组,调用的是NSArray的分类方法
    NSArray *test = [nestArr valueForKey:@"height"];
    NSLog(@"嵌套数组height===%@",test);
    //不去重
    NSArray* arr = [nestArr valueForKeyPath:@"@distinctUnionOfArrays.height"];
    NSLog(@"@distinctUnionOfArrays.height== %@", arr);
    // 去重
    NSArray* arr1 = [nestArr valueForKeyPath:@"@unionOfArrays.height"];
    NSLog(@"@unionOfArrays.height== %@", arr1);
}

- (void)setNesting{
    NSMutableSet *teatherSet1 = [NSMutableSet set];
    for (int i = 0; i < 10; i++) {
        JSTeather *teather = [[JSTeather alloc]init];
        NSDictionary* dic = @{
            @"name":[NSString stringWithFormat:@"酷走天涯_%d",i],
            @"age":@(18+i),
            @"nick":[NSString stringWithFormat:@"Julian_%d",i],
            @"height":@(170 + i),
        };
        [teather setValuesForKeysWithDictionary:dic];
        [teatherSet1 addObject:teather];
    }
    NSLog(@"personSet1== %@", [teatherSet1 valueForKey:@"height"]);
    
    NSMutableSet *teatherSet2 = [NSMutableSet set];
    for (int i = 0; i < 10; i++) {
        JSTeather *teather = [[JSTeather alloc]init];
        NSDictionary* dic = @{
            @"name":[NSString stringWithFormat:@"酷走天涯_%d",i],
            @"age":@(18+i),
            @"nick":[NSString stringWithFormat:@"Julian_%d",i],
            @"height":@(180 + i%3),
        };
        [teather setValuesForKeysWithDictionary:dic];
        [teatherSet2 addObject:teather];
    }
    //NSSet会自动合并相同项,此处调用的是NSSet的分类方法
    NSSet *test =[teatherSet2 valueForKey:@"height"];
    NSLog(@"personSet2=== %@", test);
    // 嵌套set
    NSSet* nestSet = [NSSet setWithObjects:teatherSet1, teatherSet2, nil];
    
    NSArray* arr1 = [nestSet valueForKeyPath:@"@distinctUnionOfSets.height"];
    NSLog(@"@distinctUnionOfSets.height== %@", arr1);
}

@end
Copy the code

(6) Representing non-object Values, such as constructs

// JSTeather *myT = [[JSTeather alloc] init]; ThreeFloats floats = {1.,2.,3.}; NSValue *value = [NSValue valueWithBytes:&floats objCType:@encode(ThreeFloats)]; [myT setValue:value forKey:@"threeFloats"]; NSValue *value1 = [myT valueForKey:@"threeFloats"]; NSLog(@" structure @valueForKey===%@",value1); ThreeFloats th; [value1 getValue:&th]; NSLog(@" @getValue===%f-%f-%f",th.x,th.y,th.z);Copy the code

The Patterns of Accessor Search.

The official Apple documentation makes it clear that the default implementation of the NSKeyValueCoding protocol provided by NSObject maps key-based accessor calls to the underlying properties of an object using an explicitly defined set of rules. These protocol methods search their own object instances with a key argument to find accessors, instance variables, and associated methods that follow a particular naming convention.

· Search Pattern for the Basic Getter

  • The default implementation of valueForKey: performs the following process:
  1. Search the instance for the first accessor method found named GET, is, or _. If found, call it, and then use the result for step 5. Otherwise, go to the next step.

  2. If no simple access method is found, search the instance for methods whose names match countOf and objectInAtIndex:(corresponding to the original method defined by the NSArray class) and AtIndexes:(corresponding to the NSArray method objectsAtIndexes:). If the first and at least one of the other two are found, create a collection proxy object that responds to all of the NSArray methods and returns it. Otherwise, go to Step 3. The proxy object then converts any NSArray message it receives into a combination of countOf, objectInAtInd

  3. If no simple access method or array access method group is found, look for three methods named countOf, enumeratorOf, and memberOf :(corresponding to the basic method defined by the NSSet class). If all three methods are found, create a collection proxy object that responds to all NSSet methods and return it. Otherwise, go to Step 4. The proxy object then transforms any NSSet message it receives into a combination of countOf, enumeratorOf, and memberOf: messages that are passed to the object that created it.

  4. If you don’t find a simple way to access or set access method group, and the receiver class methods accessinstancevariablesdirect returns YES, search called _, _is in this order, or is the instance variables. If yes, obtain the value of the instance variable and go to Step 5. Otherwise, go to Step 6.

  5. If the retrieved property value is an object pointer, simply return the result. If the value is a scalar type supported by NSNumber, store it in an NSNumber instance and return the value. If the result is a scalar type that NSNumber does not support, convert to an NSValue object and return that object.

  6. If all of the above methods fail, valueForUndefinedKey: is called. By default this raises an exception, but a subclass of NSObject might provide a response that specifies the key.

· Search Pattern for the Basic Setter:

  • The default implementation of setValue:forKey: performs the following process:
  1. Look for the first accessor named set: or _set. If found, call it with the input value for the passed parameter, and then complete.

  2. If you don’t find a simple accessor, and class methods accessinstancevariablesdirect returns YES, name lookup for _, _is,, or is the instance variables. If found, set the variable directly with the input value (or unwrapped value) and finish.

  3. If found no accessor or instance variables, call setValue: forUndefinedKey:. By default this raises an exception, but a subclass of NSObject might provide a response that specifies the key.

· Search Pattern for Mutable Arrays

  • The default implementation of mutableArrayValueForKey: executes the following process:
  1. The first thing we’re going to do is look for methods named insertObject:inAtIndex: and removeObjectFromAtIndex: And removeObjectAtIndex: method), or a method name such as INSERT :atIndexes: And removeAtIndexes:(insertObjects:atIndexes: and removeObjectsAtIndexes: methods corresponding to NSMutableArray).

    If the object has at least one insertion method and at least one removed, return a proxy object, some combination of response message sending NSMutableArray insertObject: inAtIndex: removeObjectFromAtIndex:, Insert :atIndexes:, and removeAtIndexes: Original mutableArrayValueForKey Recipient: message. The object that receives the mutableArrayValueForKey: message also implements an optional alternative object method, Name like replaceObjectInAtIndex: withObject: or replaceAtIndexes: with: proxy objects will be at the right time to use these features to get the best performance.

  2. If the object does not have a mutable array method, look for the accessor method set whose name matches the pattern:

  3. If neither variable array method, but could not find the visitor, and the recipient’s response to accessinstancevariablesdirect YES, search the name in the order as _ or instance variables.

    If such an instance variable is found, return a proxy object that forwards each NSMutableArray message it receives to the value of the instance variable, which is typically an instance of NSMutableArray or one of its subclasses.

  4. If the above methods have failed, it returns a mutable object collection agent, when it receives a NSMutableArray news, it would send a setValue: forUndefinedKey: message to the receiver.

    The default implementation of setValue:forUndefinedKey raises NSUndefinedKeyException, but subclasses can resend this method

· Search Pattern for MutableOrdered Sets

  • MutableOrderedSetValueForKey: default implementation and execution of process: