CGFloats, floats getting set to zero
I have a custom class Custom.mm in which I am trying to set a float value using a setter in my controller class MainController. The Custom instance is typed as an id because it is an Obj-C++ file and pointing to a proper class at compile time has worked well for me. Everything works fine, the instance is verified. If I set up the amount variable as type int and pass ints it works fine. Same with any other value or object--except floats. For some reason floats (float, CGFloat and the like) are set to 0 in the Custom.mm class. This is not an issue with NSLog or anything--I've checked the amount variable with a breakpoint and everything works but floats.
//Custom.h
@interface Custom : UIView
{
CGFloat amount;
}
@property CGFloat amount;
@end
//Custom.mm
@implementation Custom
@synthesize amount;
- (id) initWithCoder:(NSCoder*)coder
{
开发者_StackOverflow社区 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
I was able to reproduce this on my own; you've run into an interesting phenomenon.
Your problem is that the compiler can't see a definition for the setAmount:
method. As a result, it doesn't know the correct type of the arguments that method is expecting. In such cases, the compiler assumes that all parameters are of type '...', and return values are of type 'id'. But you're passing a CGFloat, not a '...'.
Objective-C is a dynamic language, so even when the compiler doesn't know whether the target method exists, it will happily package up the parameters and try to call it anyway. However, on most architectures the method for passing parameters is dependent on the type of the parameters. Integers and pointer parameters are usually passed in one set of registers, while floating point parameters are passed in another, and structs are usually passed directly on the stack. (Precise details depend on which architecture you're running on.) Since the compiler can't see the definition for the setAmount:
method, it assumes that the parameters are of type ...
. Depending on the architecture, those may be passed in a different set of registers, or even on the stack.
When the setAmount:
method runs, however, it is expecting the passed-in parameters to be in a certain set of registers. Those weren't populated by the caller, of course, and are thus still set to 0. The caller put the new value in one location, but the receiver looked in another. No wonder things are going wrong.
The solution to this is simple: Add #import "Custom.h"
at the top of MainController.m
. Then, the compiler will be able to see the definition of setAmount:
when it's compiling MainController
, and will thus know to put the new values in the place that the receiver is expecting them.
Incidentally, I'll bet that when you were compiling, you were getting a warning; something like
warning: no '-setAmount:' method found
warning: (Messages without a matching method signature
warning: will be assumed to return 'id' and accept
warning: '...' as arguments.)
At least, that's the warning I'm getting. That was the compiler telling you that it didn't know where to put the parameters when making that call, so it just picked something and hoped it worked. In this case, it didn't.
As for ints and other types working correctly, the compiler's guess at the parameter passing style just happened to match what the receiver was expecting. It was a simple matter of luck.
It looks like you haven't assigned a Custom object to the MainController's customInstance
variable, so it's nil. Ask nil for anything and it will give you 0.
精彩评论