我有一个自定义类Custom.mm,我试图在我的控制器类MainController中使用setter设置一个浮点值。 Custom实例被输入为id,因为它是一个Obj-C ++文件,并且在编译时指向正确的类对我来说效果很好。一切正常,实例已经过验证。如果我将amount变量设置为int类型并传递ints则可以正常工作。与任何其他值或对象相同 - 浮点数除外。出于某种原因,在Custom.mm类中将float(float,CGFloat等)设置为0。这不是NSLog或其他任何问题 - 我用断点检查了数量变量,一切正常但浮动。
//Custom.h
@interface Custom : UIView
{
CGFloat amount;
}
@property CGFloat amount;
@end
//Custom.mm
@implementation Custom
@synthesize amount;
- (id) initWithCoder:(NSCoder*)coder
{
if ((self = [super initWithCoder:coder]))
{
//set initial value to 1
self.amount = 1.0; //verified as 1.0
}
return self;
}
//MainController.h
@interface MainController : UIViewController
{
IBOutlet id customInstance; //IB points to the CustomView class
}
//MainController.m
@implementation MainController
-(void)viewDidLoad
{
[super viewDidLoad];
//Checking this value in Custom.mm via the debugger shows it as being 0,
//when before it was 1.0.
[customInstance setAmount:2.0];
}
@end
答案 0 :(得分:6)
我能够自己重现这个;你遇到了一个有趣的现象。
您的问题是编译器无法查看setAmount:
方法的定义。因此,它不知道方法所期望的参数的正确类型。在这种情况下,编译器假定所有参数都是“...”类型,返回值的类型为“id”。但是你传递了一个CGFloat,而不是'......'。
Objective-C是一种动态语言,所以即使编译器不知道目标方法是否存在,它仍然会很高兴地打包参数并尝试调用它。 但是,在大多数体系结构中,传递参数的方法取决于参数的类型。整数和指针参数通常在一组寄存器中传递,而浮点参数在另一组寄存器中传递,而结构通常直接在堆栈上传递。 (精确的细节取决于您正在运行的体系结构。)由于编译器无法查看setAmount:
方法的定义,因此它假定参数的类型为...
。根据体系结构的不同,这些寄存器可以在不同的寄存器集中传递,甚至可以在堆栈中传递。
然而,当setAmount:
方法运行时,它期望传入的参数位于某组寄存器中。当然,调用者没有填充那些,因此仍设置为0.调用者将新值放在一个位置,但接收者查看另一个位置。难怪事情出错了。
解决方法很简单:在#import "Custom.h"
的顶部添加MainController.m
。然后,编译器将能够看到setAmount:
的定义当它正在编译MainController
时,会因此知道将新值放在接收器期望的位置。
顺便说一句,我敢打赌,当你编译时,你会收到警告;
之类的东西warning: no '-setAmount:' method found
warning: (Messages without a matching method signature
warning: will be assumed to return 'id' and accept
warning: '...' as arguments.)
至少,这是我得到的警告。那是编译器告诉你它在进行调用时不知道在哪里放置参数,所以它只是选择了一些并希望它有效。在这种情况下,它没有。
对于整数和其他类型正常工作,编译器对参数传递样式的猜测恰好与接收者期望的匹配。这是一个简单的运气问题。
答案 1 :(得分:0)
看起来你还没有为MainController的customInstance
变量分配一个Custom对象,所以它没有。问什么都没有,它会给你0。