Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Objective-C.Programming.pdf
Скачиваний:
14
Добавлен:
21.02.2016
Размер:
8.64 Mб
Скачать

Key-value coding

Key-value coding

Key-value coding is the ability to read and set a property using its name. The key-value coding methods are defined in NSObject, and thus every object has this capability.

Open main.m and find the line:

[a setProductName:@"Washing Machine"];

Rewrite the same line to use key-value coding:

[a setValue:@"Washing Machine" forKey:@"productName"];

In this case, the setValue:forKey: method, as defined in NSObject, will go looking for a setter method named setProductName:. If the object doesn’t have a setProductName: method, it will access the instance variable directly.

You can also read the value of a variable using key-value coding. Add a line to main.m that prints out the product name:

int main (int argc, const char * argv[])

{

@autorelease {

Appliance *a = [[Appliance alloc] init]; NSLog(@"a is %@", a);

[a setValue:@"Washing Machine" forKey:@"productName"]; [a setVoltage:240];

NSLog(@"a is %@", a);

NSLog(@"the product name is %@", [a valueForKey:@"productName"]);

}

return 0;

}

In this case, the valueForKey: method, as defined in NSObject, goes looking for an accessor named productName. If there is no productName method, the instance variable is accessed directly.

If you type the name of the property wrong, you won’t get warning from the compiler, but there will be a runtime error. Make this mistake in main.m:

NSLog(@"the product name is %@", [a valueForKey:@"productNammmme"]);

When you build and run it, you will see an error:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Appliance 0x100108dd0> valueForUndefinedKey:]:

this class is not key value coding-compliant for the key productNammmme.'

Fix the error before you go on.

Why is key-value coding interesting? Anytime a standard framework wants to push data into your objects, it will use setValue:forKey:. Anytime a standard framework wants to read data from your objects, it will use valueForKey:. For example, Core Data is a framework that makes it easy to save your objects to a SQLite database and then bring them back to life. It manipulates your custom databearing objects using key-value coding.

221

Chapter 30 Properties

To prove that key-value coding will manipulate your variables even if you have no accessors, comment out the @property declaration for productName in Appliance.h:

#import <Foundation/Foundation.h>

@interface Appliance : NSObject { NSString *productName;

int voltage;

}

//@property (copy) NSString *productName; @property (nonatomic) int voltage;

//The designated initializer

- (id)initWithProductName:(NSString *)pn;

@end

Also, remove all use of the methods setProductName: and productName from Appliance.m:

@implementation Appliance

@synthesize voltage;

-(id)initWithProductName:(NSString *)pn

{

self = [super init]; if (self) {

productName = [pn copy];

[self setVoltage:120];

}

return self;

}

-(id)init

{

return [self initWithProductName:@"Unknown"];

}

- (NSString *)description

{

return [NSString stringWithFormat:@"<%@: %d volts>", productName, voltage];

}

@end

Build and run the program. Note that even though you have no accessor methods for productName, the variable can still be set and read from other methods. This is an obvious violation of the idea of object encapsulation – methods of an object are public, but the instance variables are delicate and should be kept private. If key-value coding weren’t astonishingly useful, no one would tolerate it.

Non-object types

The key-value coding methods are designed to work with objects, but some properties hold a nonobject type, like an int or a float. For example, voltage is an int. How do you set voltage using key-value coding? You use an NSNumber.

222

Non-object types

In main.m, change the line for setting the voltage from this:

[a setVoltage:240];

to this:

[a setValue:[NSNumber numberWithInt:240] forKey:@"voltage"];

Add an explicit accessor to Appliance.m so that you can see it getting called:

- (void)setVoltage:(int)x

{

NSLog(@"setting voltage to %d", x); voltage = x;

}

Build and run the program.

Similarly, if you ask for the valueForKey:@"voltage", you will get back an NSNumber containing the value of voltage.

223

This page intentionally left blank

31

Categories

Categories let a programmer add methods to any existing class. For example, Apple gave us the class NSString. We don’t get the source code to that class, but categories give us the ability to add new methods to NSString.

Create a new Foundation Command Line Tool called VowelCounter. Then create a new file that is an

Objective-C category. Name the category VowelCounting and make it a category on NSString.

Now open NSString+VowelCounting.h and declare a method that you want to add to the NSString class:

#import <Foundation/Foundation.h>

@interface NSString (VowelCounting)

- (int)vowelCount;

@end

Now implement the method in NSString+VowelCount.m:

#import "NSString+VowelCounting.h"

@implementation NSString (VowelCounting)

- (int)vowelCount

{

NSCharacterSet *charSet =

[NSCharacterSet characterSetWithCharactersInString:@"aeiouyAEIOUY"];

NSUInteger count = [self length]; int sum = 0;

for (int i = 0; i < count; i++) {

unichar c = [self characterAtIndex:i]; if ([charSet characterIsMember:c]) {

sum++;

}

}

return sum;

}

@end

Now use the new method in main.m:

225

Chapter 31 Categories

#import <Foundation/Foundation.h>

#import "NSString+VowelCounting.h"

int main (int argc, const char * argv[])

{

@autorelease {

NSString *string = @"Hello, World!";

NSLog(@"%@ has %d vowels", string, [string vowelCount]);

}

return 0;

}

Build and run the program. Nifty, eh? Categories turn out to be very useful.

It is important to note that only this program has the category. If you want the method available in another program, you must add the file to your project and compile the category in when you build that program.

226

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]