Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c ObjC内部构件。为什么我的鸭子打字尝试失败了?_Objective C - Fatal编程技术网

Objective c ObjC内部构件。为什么我的鸭子打字尝试失败了?

Objective c ObjC内部构件。为什么我的鸭子打字尝试失败了?,objective-c,Objective C,我尝试使用id在objective-c中创建duck类型。这个概念在理论上看起来不错,但在实践中失败了。我无法在方法中使用任何参数。调用了方法,但参数错误。我对对象和原语的随机值的访问不好。我在下面附上了一个简单的例子 问题: 有人知道为什么方法参数是错误的吗? 在objective-c的引擎盖下发生了什么 注:我对细节感兴趣。我知道如何使下面的例子起作用 一个例子: 我创建了一个简单的类Test,它使用属性id Test传递给另一个类 @implementation Test - (void)

我尝试使用
id
在objective-c中创建duck类型。这个概念在理论上看起来不错,但在实践中失败了。我无法在方法中使用任何参数。调用了方法,但参数错误。我对对象和原语的随机值的访问不好。我在下面附上了一个简单的例子

问题: 有人知道为什么方法参数是错误的吗? 在objective-c的引擎盖下发生了什么

注:我对细节感兴趣。我知道如何使下面的例子起作用

一个例子: 我创建了一个简单的类
Test
,它使用属性
id Test
传递给另一个类

@implementation Test
- (void) aSampleMethodWithFloat:(float) f andInt: (int) i {
    NSLog(@"Parameters: %f, %i\n", f, i);
}
@end
然后在类中执行以下循环:

for (int i=0; i < 10; ++i) {
    float f=i*0.1f;
    [tst aSampleMethodWithFloat:f andInt:i]; // warning no method found.
}
更新:

我意外地发现,当我向带有
for
循环的类添加
aSampleMethodWith…
声明时,警告消失,测试类上的方法被正确调用

更新2: 正如JeremyP所指出的,问题的直接原因是浮点数被视为双浮点数。但有人知道为什么吗?(遵循5why原则:))


根据@eman,调用被转换为简单的C函数调用和编译器指令,以获得
SEL
。因此,@选择器变得混乱。但是为什么呢?编译器在第一个方法调用中具有所有必要的类型信息。有人知道Objective-C内部的信息来源吗?我搜索了Objective-C编程语言,但没有找到答案。

您可以通过这样的分类来消除警告:

@interface NSObject (MyTestCategory)
- (void) aSampleMethodWithFloat:(float) f andInt: (int) i;
@end

如果调用点没有可用的签名,则不知道参数应该具有什么类型。未定义的方法将假定使用
作为参数,而您的方法不会这样做。如果编译器此时看到任何接口,其中存在有问题的方法,则将使用该定义。

默认情况下,浮点值作为双精度值传递,而不是浮点值。编译器不知道,
[tst aSampleMethodWithFloat:f and:i]发生时,它只应传递一个浮点,因此它将f提升为双精度。这意味着,在该方法中,当编译器确实知道它正在处理一个浮点时,f是由传递给该方法的双字节的前四个字节形成的浮点,i是由双字节的后四个字节形成的int

你可以通过以下两种方法解决这个问题

  • 将aSampleMethodWithFloat:andInt:的第一个参数更改为双精度
  • 将测试的接口声明导入到使用它的文件中

注意:在C中使用浮点数时,除了一小部分空间外,没有任何好处。您可以在任何地方都使用双倍。

我认为JeremyP关于双倍与浮点数的问题是正确的。至于实现细节,Objective-C中的消息调度使用
objc\u msgSend(id-theReceiver,SEL-theSelector,…)
C函数(有关一些深层细节,请参阅)。您可以模拟方法分派的相同结果,如下所示:

SEL theSelector = @selector(aSampleMethodWithFloat:andInt:);
objc_msgSend(self.test, theSelector, 1.5f, 5);
SEL
只是一个对应于函数的数字(根据方法签名动态确定)
objc_msgSend
然后查找方法的实际函数指针(类型为IMP)并调用它。由于
objc\u msgSend
具有数量可变的参数,因此它将只使用您传入的数量。如果你要做:

objc_msgSend(self.test, theSelector, 1.5f);

它将正确地使用1.5f,并对另一个变量使用垃圾。由于方法签名通常表示参数的数量,因此在正常使用情况下很难做到这一点

这里的问题在于C和Objective-C之间的分界线。id类型指定任何对象,但int和float不是对象。编译器需要知道所有参数的C类型以及调用的任何方法的返回类型。在没有声明的情况下,它假设一个方法返回id并接受任意数量的id参数。但是id与int和float不兼容,因此无法正确传递该值。这就是为什么当你提供一个声明时它能正确工作的原因——然后它知道你的int是int,你的float是float

如何将
带一个floatParameter:AsampleMethodWithOne FloatParameter:
转发到
带一个float:andInt:aSampleMethodWithFloat:
?您的测试类有一个方法
带一个floatParameter:andInt:AsampleMethod,但您的示例循环调用
带一个floatParameter:AsampleMethod:
。这是故意的吗?@Kristopher为了更好地说明问题,我已经更改了代码几次。我混合了两种版本。让我纠正一下。谢谢@我混合了两个版本的代码。名称现在已更正。您正在导入
测试的标题,对吗?(即使您使用
id
,您也必须这样做,因为否则对象将无法正确分配)。这一点很好,但为什么objective-c会混淆呢?为什么我得到的是警告而不是编译错误?哇。我期待的是INT,OBEJCT,但不是…:)。谢谢。你知道我在哪里可以找到有关目标c的详细信息吗?有什么好的/先进的信息来源吗?你确定?看看@JeremyP的答案。在我将浮点数更改为双倍后,代码开始正常工作。我混合了两个版本的代码。方法名称应为SampleMethodWithFloat:和Int:两处。请参阅更新后的问题。但是,当方法定义不可用时,为什么会混淆呢?为什么它将浮动视为双倍?我想这与C处理未知函数的方式有关,但我很难理解它是如何联系在一起的。比我更懂C的人必须回答这个问题。不过,您的问题的总体答案是,可以将duck类型与Objective-C结合使用,但最肯定的是不能与straight结合使用
objc_msgSend(self.test, theSelector, 1.5f);