Я пытаюсь разработать приложение, использующее платформу CoreMotion. Я не хочу постоянно бегать, чтобы протестировать свое приложение, поэтому вместо этого я хотел бы найти метод, который позволит мне отправить подделку, чтобы я мог опробовать множество различных сценариев. Я хочу протестировать такие сценарии, как ходьба пользователя, вождение, остановка и т. д. Я не хочу выходить на улицу, ходить, ехать, останавливаться и т. д. каждый раз, когда хочу протестировать приложение.
Редактировать: я знаю, что CoreMotion еще не поддерживается в симуляторе. Но надеялся, что кто-нибудь подскажет, как это подделать.
ОБНОВЛЕНИЕ: чего я достиг до сих пор, используя метод swizzling. Для этого я переключился обратно на target-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;
}
Swizzling методов делается следующим образом
[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 walk]: нераспознанный селектор отправлен в экземпляр 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. Я уже смоделировал данные гироскопа и компаса, и у меня есть данные из реальных путешествий, так что я могу передать их в симулятор. Но мне нужно, чтобы он сказал мне, идет ли пользователь, бежит, едет и т. д.
Какие-либо предложения?