• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            逛奔的蝸牛

            我不聰明,但我會很努力

               ::  :: 新隨筆 ::  ::  :: 管理 ::
             

            Cocoa and Objective-C: Up and Running (by me) is now available from O'Reilly.

            Key-Value Coding (KVC) and Generic Programming

            Key-Value Coding (KVC) is a Cocoa protocol for getting and setting values generically. In programming, the term "generically" describes a way of doing things that applies to many different situations.

            Generic code can reduce to total amount of code in a project (which is always good) and helps software to handle situations that the programmer didn't anticipate. Generic, reusable code is emphasized throughout Cocoa.

            For example, here's a non-generic way to set a first name and last name on an object:


            [person setFirstName: @"Scott"];
            [person setLastName:  @"Stevenson"];



            This works fine, but I can use KVC messages to write more generic code:


            [person setValue:@"Scott" forKey:@"firstName"];
            [person setValue:@"Stevenson" forKey:@"lastName"];



            Beginners might wonder what the point is here. In fact, it actually seems like the KVC version requires more typing. Let's choose another scenario where KVC's value is more apparent.

            First, let's define the class:


            @interface CDCPerson : NSObject
            {
                NSString * firstName;
                NSString * lastName;
                NSNumber * phoneNumber;
                NSString * emailAddress;
            }
            - (void) setFirstName:    (NSString *)value;
            - (void) setLastName:     (NSString *)value;
            - (void) setPhoneNumber:  (NSNumber *)value;
            - (void) setEmailAddress: (NSString *)value;
            @end



            Now, some actual code:


            // assume inputValues contains values we want to
            // set on the person

            NSDictionary * inputValues;
            CDCPerson    * person = [[CDCPerson alloc] init];
                                              
            NSEnumerator *e = [inputValues keyEnumerator];
            id dictKey, dictValue;

            while ( dictKey = [e nextObject] )

                dictValue = [inputValues valueForKey: dictKey];
                [person setValue: dictValue forKey: dictKey];
            }



            This snippet of code is generic, meaning that we don't need to change it everytime new instance variables are added to the Person class.

            But it gets better! Here's an even simpler version of the code above:


            // assume inputValues contains values we want to
            // set on the person

            NSDictionary * inputValues;
            CDCPerson    * person = [[CDCPerson alloc] init];

            [person setValuesForKeysWithDictionary: inputValues];



            Intrigued? Here's Apple explanation of what's happening in -setValuesForKeysWithDictionary:


            Sets properties of the receiver with values from keyedValues, using its keys to identify the properties. The default implementation invokes setValue:forKey: for each key-value pair, substituting nil for NSNull values in keyedValues.


            In other words, essentially the same as the first example. But what is -setValue:forKey: actually doing? This is where the KVC magic comes in. It will actually find the -setFirstName:, -setLastName:, -setPhoneNumber: and -setEmailAddress: implementations and call those. If it can't find these, KVC will try quite a few different options before ultimately just setting a value on the instance variable itself.

            KVC can also be used to pull values out of an object:


            // assume person already exists and is populated with values

            CDCPerson * person;

            NSMutableDictionary * outputValues;
            outputValues = [NSMutableDictionary dictionary];

            NSArray * keys;
            keys = [NSArray arrayWithObjects: @"firstName",
                                              @"lastName",
                                              @"phoneNumber",
                                              @"emailAddress",
                                              nil];

            NSEnumerator *e = [keys objectEnumator];
            id key, value;

            while ( key = [e nextObject] )

                value = [person valueForKey: key];
                [outputValues setValue: value forKey: key];
            }




            Or, the simpler version:


            // assume person already exists and is populated with values

            CDCPerson    * person;
            NSArray      * keys;

            keys = [NSArray arrayWithObjects: @"firstName",
                                              @"lastName",
                                              @"phoneNumber",
                                              @"emailAddress",
                                              nil];

            NSDictionary * outputValues;
            outputValues = [person dictionaryWithValuesForKeys: keys];



            Just as with setting values, getting values with -valueForKey: will cause KVC to look for a method the same name as the key:


            // this will cause KVC to look for a method called -firstName;

            NSString * name = [person valueForKey:@"firstName"];



            Key-value coding is key element in Cocoa Bindings and Core Data, so it really pays to understand the basic ideas. KVC can handle keypaths, such as:


            // getting
            [obj valueForKeyPath: @"storage.firstName"];

            // setting
            [obj setValue: @"Scott" forKeyPath: @"storage.firstName"];



            This is similar to doing:


            // getting
            [[obj storage] firstName];

            // setting
            [[obj storage] setFirstName:@"Scott"];



            For more details on Key-value coding, take a look at this page on ADC.
            Design Element
            Key-Value Coding (KVC) and Generic Programming
            Posted Oct 03, 2005 — 11 comments below




             

            SteveJ — Oct 03, 05 403

            In two places where you send the CDCPerson class the allocate message, you don't need the "]" after the class "CDCPerson" and before the message "allocate".

            Scott Stevenson — Oct 03, 05 404 Scotty the Leopard

            Fixed, thanks. I think this was partially due to a smart editing rule in the text editor.

            Daniel Jalkut — Oct 03, 05 405

            Just a vote of confidence for this "experiment." I think you have a great writing style and the formatting of your articles is very accessible. The approach you're taking now could produce a sigfnicant "FAQ-like" resource for newbies and oldbies alike.

            Samo Korosec — Oct 04, 05 406

            Aren't such articles what Cocoa Dev Central is about anyway? Will you repost them there, too?

            Jesper — Oct 04, 05 407

            Samo: Scott uses the CDC prefix for one-off classes in the article, so it seems like the goal is to get it there later on, but to publish it here now so that people can read it in the meantime.

            Scott Stevenson — Oct 04, 05 408 Scotty the Leopard

            Jesper's is basically on the right track. It's easier to experiment quickly here on the blog, and move stuff to CDC once it's cleaned up a bit.

            Samo Korosec — Oct 04, 05 415

            Ah, okies. I've just read over the CDC* stuff not thinking about it. Great idea to post such Cocoa helplets, though.

            Tito Ciuro — Mar 31, 06 997

            Thanks for the article! I'd like to see keypaths explained a little better. For example, if CDCPerson had an NSArray *siblings (with a few CDCPerson), how could we obtain the list the siblings?

            I'd think we would call it via [person valueForKeyPath: @"siblings.firstName"], but I'm not sure if I'd need extra accessors, especially if we start dealing with a fairly nested dictionary. How would that work?

            Thanks again!

            Scott Stevenson — Apr 03, 06 1000 Scotty the Leopard

            I'd think we would call it via [person valueForKeyPath: @"siblings.firstName"]

            That should work fine.

            hisham — Dec 29, 08 6577

            Great. I'm new to KVC and this really helped :)

            Thanks so much,
            Hisham

            Daniel — Mar 20, 09 6626

            "Beginners might wonder what the point is here. In fact, it actually seems like the KVC version requires more typing. Let's choose another scenario where KVC's value is more apparent."

            That's exactly why I was googling for more info. :) Thanks! Good info.




             

            Comments Temporarily Disabled

            I had to temporarily disable comments due to spam. I'll re-enable them soon.




            Technorati Profile
            Copyright © Scott Stevenson 2004-2008

            From: http://theocacao.com/document.page/161

            @import url(http://m.shnenglu.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
            posted on 2011-12-02 00:05 逛奔的蝸牛 閱讀(344) 評論(0)  編輯 收藏 引用 所屬分類: Cocoa
            亚洲愉拍99热成人精品热久久| 国产精品久久久久影院色| 日本久久久久亚洲中字幕| 欧美精品丝袜久久久中文字幕| 青青热久久国产久精品| 亚洲伊人久久成综合人影院| 久久se这里只有精品| 亚洲午夜福利精品久久| 色综合久久天天综线观看| 亚洲精品国产美女久久久| 国产精品久久久久久福利69堂| 97久久精品无码一区二区| 久久久久国产精品| 亚洲人AV永久一区二区三区久久 | 久久久久免费精品国产| 久久久久久久91精品免费观看| 99久久精品国产一区二区| 亚洲AV成人无码久久精品老人| 久久精品国产亚洲一区二区| 精品国产婷婷久久久| 久久精品毛片免费观看| 久久精品国产亚洲沈樵| 久久久精品国产Sm最大网站| 亚洲乱码日产精品a级毛片久久| 久久久久亚洲AV片无码下载蜜桃| 久久九色综合九色99伊人| 亚洲国产综合久久天堂| 精品久久久久久亚洲精品| 久久免费99精品国产自在现线| 久久国产精品99精品国产| 国产精品狼人久久久久影院| 日韩久久无码免费毛片软件| 热re99久久精品国99热| 久久人人爽人人爽人人片AV东京热| 国产V综合V亚洲欧美久久| 久久久久亚洲AV成人网人人软件| 国产精品久久自在自线观看| 久久久久久国产精品美女| 97精品伊人久久久大香线蕉 | 久久天天躁夜夜躁狠狠| 久久精品国产黑森林|