我有一个我编写的核心数据验证方法,无法编译。我可以修改方法,因此它编译...但后来我得到运行时错误。该方法的两个版本如下(注意第二个版本中缺少'*')。此版本编译但给出运行时错误“+ [NSCFNumber doubleValue]:无法识别的选择器发送到类0x7fff70a448e8”:
- (BOOL)validateInitialValue:(id *)value error:(NSError **)error {
if ( *value == nil ) {
return YES;
}
if ( [*value doubleValue] < 0.0 ) {
return NO;
}
return YES;
}
此版本提供编译器警告和错误(请参阅下面的警告和错误):
- (BOOL)validateInitialValue:(id *)value error:(NSError **)error {
if ( value == nil ) {
return YES;
}
if ( [value doubleValue] < 0.0 ) {
return NO;
}
return YES;
}
编译器错误和警告:
warning: Semantic Issue: Receiver type 'id *' is not 'id' or interface pointer, consider casting it to 'id'
warning: Semantic Issue: Method '-doubleValue' not found (return type defaults to 'id')
error: Semantic Issue: Invalid operands to binary expression ('id' and 'double')
我终于认为问题可能出在调用代码中:
- (void)setInitialValue:(NSNumber *)initialValue {
[self willChangeValueForKey:@"initialValue"];
[self validateValue:initialValue forKey:@"initialValue" error:nil];
[self setPrimitiveInitialValue:initialValue];
[self didChangeValueForKey:@"initialValue"];
}
我更改了来电者使用'&amp;'在initialValue之前并使用了该方法的第一个版本,一切正常。所以新的调用代码将一行更改为:
[self validateValue:&initialValue forKey:@"initialValue" error:nil];
但是真的有必要拥有'&amp;'?? setPrimitiveInitialValue不使用'&amp;'。我觉得我对Objective-C的理解还没有得到足够的发展,你们所有的大师们都会发现这是一个非常直接的答案的小问题。
答案 0 :(得分:5)
id
本身代表一个指针。因此,当您使用id *
时,实际上是指向指针的指针。 this优秀教程的第一部分解释了这个概念。
有可能,这就是你要找的东西:
- (BOOL)validateInitialValue:(id)value error:(NSError **)error {
if ( value == nil ) {
return YES;
}
if ( [value doubleValue] < 0.0 ) {
return NO;
}
return YES;
}
答案 1 :(得分:4)
你说问题是调用代码是对的。 id *
表示指针到id
值。对象变量本身就是id
,因此您需要一个指向该变量的指针,这是您使用&
得到的。
传递指针的原因是,如果验证方法知道修改值以使其有效的方法,它可以返回YES
并且返回有效值对象(通过设置变量)。因此,例如,如果小于1的数字应该被钳制为0,那么您可以这样做:
- (BOOL)validateInitialValue:(id *)value error:(NSError **)error {
if ( *value == nil ) {
return YES;
}
if ( [*value doubleValue] < 0.0 ) {
return NO;
}
if ( [*value doubleValue] > 0.0 && [*value doubleValue] < 1.0 ) {
*value = [NSNumber numberWithInt:0];
}
return YES;
}
setPrimitiveValue:
不需要在调用上下文中设置变量,因此它只需要id
。 (很少有方法像validateValue:forKey:error:
一样工作。一般来说,如果他们想要返回一个BOOL
来指示他们是否改变了某些东西,他们会这样做,但他们仍然需要一种方法来返回更改后的值同样。)