我正在尝试开发一个使用CoreMotion框架的应用程序。我不想继续测试我的应用程序,所以相反我想找到一种技术,允许我发送假,所以我可以尝试很多不同的场景。我希望测试用户步行,驾驶,停车等情况。我不想每次想要测试应用程序时都要出去散步,开车,停车等。
编辑:我知道模拟器中尚不支持CoreMotion。但希望有人能给我一些如何伪造这个
的想法更新:到目前为止我使用方法调配实现了什么。我已经换回了objective-c,因为我最好先尝试用这种语言解决,然后尝试将其翻译成Swift
我已经设置了一个像这样的方法swizzle类
+ (void)swizzleClass:(Class)class method:(NSString*)methodName {
SEL originalSelector = NSSelectorFromString(methodName);
SEL newSelector = NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"override_", methodName]);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method newMethod = class_getInstanceMethod(class, newSelector);
method_exchangeImplementations(originalMethod, newMethod);
}
我为CMMotion和CMAccelerometerData创建了一个类别
- (void) simx_setAcceleration:(CMAcceleration)acceleration {
NSValue *value = [NSValue value:&acceleration withObjCType:@encode(CMAcceleration)];
objc_setAssociatedObject(self, ACCELERATION_IDENTIFIER, value, OBJC_ASSOCIATION_RETAIN);
}
- (CMAcceleration)override_acceleration {
NSValue *value = objc_getAssociatedObject(self, ACCELERATION_IDENTIFIER);
CMAcceleration acc;
[value getValue:&acc];
return acc;
}
然后是CMMotionManager类的类别。
- (void) simx_setAccelerationData:(CMAcceleration )accelerationData
{
NSValue *value = [NSValue value:&accelerationData withObjCType:@encode(CMAcceleration)];
objc_setAssociatedObject(self, HANDLER_IDENTIFIER, value, OBJC_ASSOCIATION_RETAIN);
}
- (CMAccelerometerData *)override_accelerometerData
{
NSValue *value = objc_getAssociatedObject(self, HANDLER_IDENTIFIER);
CMAcceleration acc;
[value getValue:&acc];
CMAccelerometerData *data = [[CMAccelerometerData alloc] init];
//Add
[data simx_setAcceleration:acc];
return data;
}
调整方法就像这样做了
[CESwizzleUtils swizzleClass:[CMMotionManager class]
method:@"INSERT METHOD NAME TO BE SWIZZLED HERE"];
这允许我传递我自己的数据
//Add
CMAccelerometerData *data = [[CMAccelerometerData alloc] init];
[data simx_setAcceleration:acc];
[motionManager simx_setAccelerationData:acc];
所以我可以检索这样的数据
motionManager.accelerometerData.acceleration.x;
我也有方法调高了DeviceMotion类。这是我的快速示例应用程序,它使用方法swizzle技术从加速度计和陀螺仪中提取数据
单击测试按钮后,它会随机生成加速度计和陀螺仪数据并更新标签。
代码看起来像这样
-(IBAction)testing:(id)sender
{
//random double just generates a random double between 0 and 1
CMAcceleration acc;
acc.x = [self randomDouble:0 :1];
acc.y = [self randomDouble:0 :1];
acc.z = [self randomDouble:0 :1];
//Add
CMAccelerometerData *data = [[CMAccelerometerData alloc] init];
[data simx_setAcceleration:acc];
[motionManager simx_setAccelerationData:acc];
//Sim gravity and userAcel
CMAcceleration grav;
grav.x = [self randomDouble:0 :1];
grav.y = [self randomDouble:0 :1];
grav.z = [self randomDouble:0 :1];
CMAcceleration userAcel;
userAcel.x = [self randomDouble:0 :1];
userAcel.y = [self randomDouble:0 :1];
userAcel.z = [self randomDouble:0 :1];
CMDeviceMotion *deviceMotion = [[CMDeviceMotion alloc] init];
[deviceMotion simx_setUserAcceleration:userAcel];
[deviceMotion simx_setGravity:grav];
[motionManager simx_setDeviceMotion:deviceMotion];
accelLabael.text = [NSString stringWithFormat:@"Accelerometer: %.02f %.02f %.02f", motionManager.accelerometerData.acceleration.x,motionManager.accelerometerData.acceleration.y,motionManager.accelerometerData.acceleration.z];
gravityLabel.text = [NSString stringWithFormat:@"Gravity: %.02f %.02f %.02f", motionManager.deviceMotion.gravity.x,motionManager.deviceMotion.gravity.y,motionManager.deviceMotion.gravity.z];
accelSpeedLabel.text = [NSString stringWithFormat:@"Accel: %.02f %.02f %.02f", motionManager.deviceMotion.userAcceleration.x,motionManager.deviceMotion.userAcceleration.y,motionManager.deviceMotion.userAcceleration.z];
}
我正在努力弄清楚如何获得这种方法。我已经调整了许多CoreMotion方法,但需要一点帮助。目前在模拟器上,尽管MotionManager现在存储陀螺仪,加速度计等数据,但这些块方法都不会触发。
[activityManager startActivityUpdatesToQueue:[[NSOperationQueue alloc] init] withHandler: ^(CMMotionActivity *activity){
}];
[motionManager startDeviceMotionUpdatesToQueue:[[NSOperationQueue alloc] init]
withHandler:^ (CMDeviceMotion *motionData, NSError *error) {
}];
我也调整了这些方法
- (BOOL)override_isAccelerometerActive;
- (BOOL)override_isDeviceMotionActive;
-(BOOL)override_isGyroAvailable;
所以他们总是返回true,但仍然不能让这些块被解雇。我想帮助一些帮助,试图找出如何正确调配这些方法,以便我可以开始向模拟器发送和接收模拟数据
编辑:我确实通过添加以下类别来调整加速度计更新方法。到CMMotionManager类
-(void)override_startAccelerometerUpdatesToQueue:(NSOperationQueue *)queue
withHandler:(CMAccelerometerHandler)handler{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Test %.02f %.02f %.02f", self.accelerometerData.acceleration.x,self.accelerometerData.acceleration.y,self.accelerometerData.acceleration.z);
});
}
这很有效,因为我已经调整了加速数据。
然后我通过添加此类别
在CMMotionActivityManager类中尝试了这个-(void)override_startActivityUpdatesToQueue:(NSOperationQueue *)queue
withHandler:(CMMotionActivity *)activity
{
dispatch_async(dispatch_get_main_queue(), ^
{
BOOL walking = [activity walking];
NSLog(@"%i", walking);
});
}
但是我在这里收到此错误
[ NSGlobalBlock 行走]:无法识别的选择器发送到实例 0x1086cf330
任何建议都将不胜感激
更新2:
抱歉迟到的回复,不得不等到今天才试试这个。我根据你的建议更新了方法,现在可以正常使用-(void)override_startActivityUpdatesToQueue:(NSOperationQueue *)queue
withHandler:(CMMotionActivityHandler )activity
{
}
事情是,我需要访问CMMotionActivity以确定它们是否正在行走等原始代码
[activityManager startActivityUpdatesToQueue:[[NSOperationQueue alloc] init] withHandler: ^(CMMotionActivity *activity){
dispatch_async(dispatch_get_main_queue(), ^
{
[activity walking];
});
}];
允许您访问此变量。但是现在我已经调整了它,它现在在我的类别文件中调用我的新声明,该声明不包含CMMotionActivity变量。关于我如何访问这个的任何想法。这有点复杂,但在我最终开始模拟CoreMotion数据之前,这是我的最后一个障碍。我已经模拟了陀螺仪和罗盘数据,我从真实旅程中获得了数据,因此我可以将其输入模拟器。但我需要告诉我用户是走路,跑步,开车等等。
有什么建议吗?
答案 0 :(得分:1)
override_startActivityUpdatesToQueue:withHandler:
的方法签名不正确。 handler
参数应该是CMMotionActivityHandler
块,提供单个CMMotionActivity
参数:
typedef void (^CMMotionActivityHandler)(CMMotionActivity *activity)