知行

值转换器编程指南

值转换器介绍

值转换器描述的是NSValueTransformer类(内建的值转换器),如何写你自己的子类。值转换器主要用来控制器层绑定。

值转换器的角色

值转换器类用于以某种方式变换对象的值。当使用Cocoa blinding并在控制器的模型属性与一个用户界面元素或另一个控制器对象之间,使用值转换器通常是很有用的。通过使用内置的值转换器,或者创建自定义值转换器,可以进一步减少应用程序所需的胶水代码量。

例如,如果一个模型属性是nil,那么经常需要禁用一个用户界面元素。如果该属性是nil,你指定使用一个is not nil转换器绑定,而不是写一个返回YES的方法。值转换器充当“中间人”,如果该属性为nil,提供一个YES给用户界面元素。

值转换在一个值传到用户界面元素的方法setObjectValue:之前立即做完的。同样地,反向转换是在用户界面上的值设置到模型之前得到应用的。查看Blinding message flowCocoa Blinding Programming Topics查看详细的描述。

所有的值转换器都是 NSValueTransformer的子类。除了为子类提供抽象的方法,NSValueTransformer`类维持一个值转换器的名称和对应值转换器对象的映射。

可用的值转换器

除了提供注册你自己的值转换器之外,NSValueTransformer提供了几个内置的值转换器。

内置的值转换器为否定布尔值,测试nilnot nil,归档和解档NSData实例提供设施。

NSNegateBooleanTransformerName

NSNegateBooleanTransformerName值转换器返回一个包含布尔值的NSNumber实例。返回的值是原始值的布尔否定,是可逆的。

这个值转换器在启用或禁用用户界面元素,以及设置复选框和单选按钮的值是有用的。

NSIsNilTransformerName

NSIsNilTransformerName值转换器返回一个包含布尔值的NSNumber实例。如果原始值是nil,返回YES,若否,返回NO。这个值转换器是不可逆的。

这个值转换器通常用来启用或禁用用户界面元素。

NSIsNotNilTransformerName

NSIsNotNilTransformerName值转换器返回一个包含布尔值的NSNumber实例。如果原始值不是nil,返回YES,若否,返回NO。这个值转换器是不可逆的。

这个值转换器通常用来启用或禁用用户界面元素。

NSUnarchiveFromDataTransformerName

NSUnarchiveFromDataTransformerName通过尝试对传的NSData值中的数据进行解档返回一个对象。它的逆向转换返回一个通过归档生成的NSData实例。

这个对象为了转换器的解档和归档必须实现NSCoding协议使用序列化。

这个转换器主要用在NSUserDefaultsController实例。该转换器允许程序存储本地不支持的对象到user default,像NSColor

NSKeyedUnarchiveFromDataTransformerName

NSKeyedUnarchiveFromDataTransformerName通过尝试对传的 NSData 值中的数据进行解档返回一个对象。它的逆向转换返回一个通过归档生成的NSData实例。

这个转换器不同于NSUnarchiveFromDataTransformerName之处在于对象必须实现NSCoding使用 keyed archiving,而不是序列化归档。

这个转换器主要用在NSUserDefaultsController实例。该转换器允许程序存储本地不支持的对象到user default ,像NSColor

注册一个值转换器

为了使用自定义的转换器,必须注册它。

注册一个自定义的值转换器

NSValueTransformer类维持一个值转换器名字和对应值转换对象的映射。注册一个 NSValueTransformer子类的实例,而不是注册子类。这允许一个提供通用功能的值转换器用不同的参数对不容的名字注册多次。例如,你可以写一个乘法转换器并在实例化时指定乘法因子。单独的实例可以被注册为2`倍乘法转换器,十倍乘法转换器等等。

下面是华氏温度到摄氏温度的转换器代码:

1
2
3
4
5
6
7
8
9
FahrenheitToCelsiusTransformer *fToCTransformer;

// create an autoreleased instance of our value transformer
fToCTransformer = [[[FahrenheitToCelsiusTransformer alloc] init]
autorelease];

// register it with the name that we refer to it with
[NSValueTransformer setValueTransformer:fToCTransformer
forName:@"FahrenheitToCelsiusTransformer"];

值转换器通常在程序delegate类中注册,以响应接收initialize:类消息。这使得注册发生在应用程序启动阶段,像加载nib文件那样提供这个值转换器。

在界面编辑器中的可用性

你的NSValueTransformer子类不会自动在IB中列出来。

写一个自定义的值转换器

Foundation 框架提供了几个内置的值转换器。你可以通过子类化 NSValueTransformer 来创建自定义的值转换器。

一个NSValueTransformer子类必须至少实现transformedValueClassallowsReverseTransformationtransformedValue:这三个方法。如果你的值转换器支持反向转换,方法reverseTransformedValue:也是必须要被实现的。

作为示例,我们将创建一个NSValueTransformer子类,FahrenheitToCelsiusTransformer,它转换华氏温度到摄氏温度。这个值转换器是可逆向的,能够转换摄氏温度到华氏温度。

说明返回值的类

一个值转换器子类必须实现transformedValueClass类方法。这个方法返回的是方法transformedValue:返回的对象的类。

这个FahrenheitToCelsiusTransformer返回NSNumber

1
2
3
4
+ (Class)transformedValueClass
{
return [NSNumber class];
}

允许逆向转换

NSValueTransformer子类也必须实现类方法:allowsReverseTransformation。如果该值转换器是可逆,这个方法应当返回YES

华氏温度到摄氏温度的转换器是可逆的,那么代码如下:

1
2
3
4
+ (BOOL)allowsReverseTransformation
{
return YES;
}

转换一个值

方法transformedValue: 实现实际的值转换。它传递转换的对象,并返回转换的结果。返回的结果必须是transformedValueClass返回的类的实例。

为了最大的灵活性,方法transformedValue: 的实现应该准备处理不同类的值。这个华氏温度到摄氏温度转换器可以处理 NSNumberNSString 类的值,通过使用 floatValue 转换这个值到标量。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (id)transformedValue:(id)value
{
float fahrenheitInputValue;
float celsiusOutputValue;

if (value == nil) return nil;

// Attempt to get a reasonable value from the
// value object.
if ([value respondsToSelector: @selector(floatValue)]) {
// handles NSString and NSNumber
fahrenheitInputValue = [value floatValue];
} else {
[NSException raise: NSInternalInconsistencyException
format: @"Value (%@) does not respond to -floatValue.",
[value class]];
}

// calculate Celsius value
celsiusOutputValue = (5.0/9.0)*(fahrenheitInputValue - 32.0);

return [NSNumber numberWithFloat: celsiusOutputValue];
}

反向转换一个值

如果一个NSValueTransformer子类支持逆向转换,它必须实现方法:reverseTransformedValue:

当实现逆向值转换时应该保证不会降低精确度。大部分情况下,传方法transformedValue: 返回的结果到方法reverseTransformedValue:应当返回跟初始值同样的值。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (id)reverseTransformedValue:(id)value
{
float celsiusInputValue;
float fahrenheitOutputValue;

if (value == nil) return nil;

// Attempt to get a reasonable value from the
// value object.
if ([value respondsToSelector: @selector(floatValue)]) {
// handles NSString and NSNumber
celsiusInputValue = [value floatValue];
} else {
[NSException raise: NSInternalInconsistencyException
format: @"Value (%@) does not respond to -floatValue.",
[value class]];
}

// calculate Fahrenheit value
fahrenheitOutputValue = ((9.0/5.0) * celsiusInputValue) + 32.0;

return [NSNumber numberWithDouble: fahrenheitOutputValue];
}

原文地址