我编写了自己的Objective C类来处理2D向量。
@interface Vector2D : NSObject {
struct _vecdata {
double x;
double y;
double x_norm;
double y_norm;
} _data;
}
@property(nonatomic) double x; //custom getter + setter
@property(nonatomic) double y; //custom getter + setter
@property(nonatomic, readonly) double xNormed; //custom getter
@property(nonatomic, readonly) double yNormed; //custom getter
+ (id)vectorWithX:(double)x_ext andY:(double)y_ext;
- (id)initWithX:(double)x_ext andY:(double)y_ext;
[...]
- (double)length;
@end
#import <math.h>
@implementation Vector2D
+ (id)vectorWithX:(double)x_ext andY:(double)y_ext{
return [[self alloc] initWithX:x_ext andY:y_ext];
}
- (id)initWithX:(double)x_ext andY:(double)y_ext {
if ((self = [super init])) {
_data.x = x_ext;
_data.y = y_ext;
[self normalize];
}
return self;
}
- (void)setX:(double)x {
_data.x = x;
[self normalize];
}
- (double)x {
return _data.x;
}
- (double)xNormed {
return _data.x_norm;
}
//setters and getter for y omitted (same as for x)
[...]
- (void)normalize {
double abs = [self length];
if (abs != 0) {
_data.x_norm = _data.x/abs;
_data.y_norm = _data.y/abs;
}
}
- (double)length {
return sqrt(_data.x*_data.x + _data.y*_data.y);
}
@end
现在我需要将调用的结果包装到对NSNumber的Vector2D实例长度调用。
NSNumber* aNSNum = @([[Vector2D vectorWithX:someXValue andY:someYValue] length]);
因为我稍后会显示aNSNum的值,所以我注意到,所有值(所有NSNumbers都是这样创建的)都在1.40537252E+14
左右(因为我稍后会调用[aNSNum floatValue])。
所以我重新编译并重新运行应用程序,突然所有值都在4.73280427E+14
附近。
所以我想知道,因为Vector的长度应该在0到20000的范围内,但不能更多。 我开始在调试器中玩,以了解发生了什么,并得到以下结果:
(lldb) po [[Vector2D vectorWithX:someXValue andY:someYValue] length]
0x0000000000000001
(lldb) po (double)[[Vector2D vectorWithX:someXValue andY:someYValue] length]
84.693565280958623
(lldb) po (unsigned long)[[Vector2D vectorWithX:someXValue andY:someYValue] length]
1
(lldb) po @([[Vector2D vectorWithX:someXValue andY:someYValue] length])
84.69356528095862
(lldb) po @((double)[[Vector2D vectorWithX:someXValue andY:someYValue] length])
84.69356528095862
(lldb) po @((unsigned long)[[Vector2D vectorWithX:someXValue andY:someYValue] length])
1
(lldb) po aNSNum
140537282189312
(lldb) po [aNSNum floatValue]
1.40537286E+14
(lldb) po (unsigned long)[aNSNum doubleValue]
<Vector2D: 0x7fd162c85800>
(lldb) po (double)[(unsigned long)[aNSNum doubleValue] length]
84.693565280958623
所以真正令人感兴趣的部分是关于倒数第二行。那么为什么指针地址存储在NSNumber中的Vector2D对象而不是调用-length的返回值的值?
从那时起,我尝试将伪造的代码行更改为以下变体:(没有成功)
NSNumber* aNSNum = @((double)[[Vector2D vectorWithX:someXValue andY:someYValue] length]);
NSNumber* aNSNum = @([((Vector2D *)[Vector2D vectorWithX:someXValue andY:someYValue]) length]);
NSNumber* aNSNum = @((double)[((Vector2D *)[Vector2D vectorWithX:someXValue andY:someYValue]) length]);
到目前为止的工作如下:
static SEL lengthSEL;
static IMP lengthIMP;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
lengthSEL = @selector(length);
lengthIMP = class_getMethodImplementation([Vector2D class], lengthSEL);
});
Vector2D* vec = [Vector2D vectorWithX:someXValue andY:someYValue];
double len = ((double (*) (id,SEL))lengthIMP)(vec,lengthSEL);
NSNumber* aNSNum = @(len);
但是希望有人可以帮助我把它带回一个班轮。或者有一个线索,它出错了......
答案 0 :(得分:1)
编辑: 编译器因为返回类型
而感到困惑 + (id)vectorWithX:(double)x_ext andY:(double)y_ext;
是id
;它不知道它将获得的length
方法。将声明更改为
+ (instancetype )vectorWithX:(double)x_ext andY:(double)y_ext;
并观察有多好的东西。 请访问apple docs
了解详情您依靠文字语法@(someNumber)来检测someNumber的类型并正确处理它,在本例中是length方法的(double)返回值。数字文字的规则是here。
我认为安全的做法,而不是强制转换你的变量并希望编译器选择它,就是用显式输入创建数字,即
NSNumber* aNSNum = [NSNumber numberWithDouble:[[Vector2D vectorWithX:someXValue andY:someYValue] length]];
NSNumber文字对于常量等来说是很好的简写,但这似乎是一种使代码更难理解而不是更容易的情况。