Datos principales: configurador personalizado que falla en el cálculo en cascada
-
27-10-2019 - |
Pregunta
Tengo una clase llamada Location
con la siguiente declaración generada automáticamente,
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface Location : NSManagedObject
@property (nonatomic, retain) NSNumber * cosRadLat;
@property (nonatomic, retain) NSNumber * latitude;
@property (nonatomic, retain) NSNumber * longitude;
@property (nonatomic, retain) NSNumber * radLat;
@property (nonatomic, retain) NSNumber * radLng;
@property (nonatomic, retain) NSNumber * sinRadLat;
@end
En una categoría de objetivo-c, he creado dos métodos para calcular las otras propiedades en función de la latitud y la longitud,
- (double)degreesToRadians:(NSNumber *)degrees
{
double radians = ([degrees doubleValue] * M_PI) / 180.0;
return radians;
}
- (void)setLatitude:(NSNumber *)newLat longitude:(NSNumber *)newLng
{
[self setLatitude:newLat];
[self setLongitude:newLng];
// Make calculations
double dblRadLat = [self degreesToRadians:newLat];
double dblRadLng = [self degreesToRadians:newLng];
double dblCosRadLat = cos(dblRadLat);
double dblSinRadLat = sin(dblRadLat);
// and set their values
[self setRadLat:[NSNumber numberWithDouble:dblRadLat]];
[self setRadLng:[NSNumber numberWithDouble:dblRadLng]];
[self setCosRadLat:[NSNumber numberWithDouble:dblCosRadLat]];
[self setSinRadLat:[NSNumber numberWithDouble:dblSinRadLat]];
}
Cuando ejecuto mis pruebas unitarias, la mitad de las veces obtengo esto:
Lat 40.7302133
Lng -74.0003337
RadLat 0.7108763271245849
RadLng -1.291549470639518
CosRadLat 0.7577903652576623
SinRadLat 0.6524980937310535
La otra mitad, obtengo esto:
Lat 40.7302133
Lng -74.0003337
RadLat 0
RadLng 0
CosRadLat 0
SinRadLat 0
¿Qué estoy haciendo mal?
PRUEBA DE UNIDAD
Aquí está mi función que utilizo para guardar el contexto en la prueba unitaria,
- (void)saveContext
{
NSLog(@"%@ saveContext", self.name);
NSError *saveError = nil;
STAssertTrue([self.managedObjectContext save:&saveError], @"Failed to save context to persistent store: %@", saveError);
}
Y así es como lo llamo
// Constants we will check to ensure our calcluations are correct
// 1st Location
double const LAT = 40.7292540;
double const LNG = -73.9988530;
double const RAD_LAT = 0.710859584;
double const RAD_LNG = -1.29152363;
double const SIN_RAD_LAT = 0.652485406;
double const COS_RAD_LAT = 0.75780129;
double const accuracy = 0.00000001;
/** Run before each test. Populates the database with objects to play with.
*/
- (void)setUp
{
NSLog(@"%@ setUp", self.name);
// Creates our persistent store in memory and initializes our managed object context for us.
[super setUp];
// Create a new Location
Location *location = [NSEntityDescription insertNewObjectForEntityForName:@"Location" inManagedObjectContext:self.managedObjectContext];
// Using the setLatitude:longitude: method, which cascades the calculation for all other values
[location setLatitude:[NSNumber numberWithDouble:LAT] longitude:[NSNumber numberWithDouble:LNG]];
// Check if it has properly calculated the values we asked for
double lat = [[location latitude] doubleValue];
double lng = [[location longitude] doubleValue];
double rad_lat = [[location radLat] doubleValue];
double rad_lng = [[location radLng] doubleValue];
double sin_rad_lat = [[location sinRadLat] doubleValue];
double cos_rad_lat = [[location cosRadLat] doubleValue];
STAssertEqualsWithAccuracy(LAT, lat, accuracy, @"Wanted: %f Got: %f", LAT, lat);
STAssertEqualsWithAccuracy(LNG, lng, accuracy, @"Wanted: %f Got: %f", LNG, lng);
STAssertEqualsWithAccuracy(RAD_LAT, rad_lat, accuracy, @"Wanted: %f Got: %f", RAD_LAT, rad_lat);
STAssertEqualsWithAccuracy(RAD_LNG, rad_lng, accuracy, @"Wanted: %f Got: %f", RAD_LNG, rad_lng);
STAssertEqualsWithAccuracy(SIN_RAD_LAT, sin_rad_lat, accuracy, @"Wanted: %f Got: %f", SIN_RAD_LAT, sin_rad_lat);
STAssertEqualsWithAccuracy(COS_RAD_LAT, cos_rad_lat, accuracy, @"Wanted: %f Got: %f", COS_RAD_LAT, cos_rad_lat);
// Saves the managed object context into the persistent store.
[self saveContext];
}
Esta parte suele funcionar.Lo que sucede es que se llama setup
, ejecuta esta prueba y aquí es donde falla
- (Location *)fetchLastLocation
{
NSLog(@"%@ getLastLocation", self.name);
NSMutableArray *mutableFetchResults = [self fetchEntity: @"Location"];
Location *location = (Location *)[mutableFetchResults lastObject];
return location;
}
/** Tests to see if the values stick after saving and fetching
*/
- (void)testCalculatedValuesStick
{
Location *location = [self fetchLastLocation];
NSLog(@"Stick: %@", location);
// Check if it has properly calculated the values we asked for
double lat = [[location latitude] doubleValue];
double lng = [[location longitude] doubleValue];
double rad_lat = [[location radLat] doubleValue];
double rad_lng = [[location radLng] doubleValue];
double sin_rad_lat = [[location sinRadLat] doubleValue];
double cos_rad_lat = [[location cosRadLat] doubleValue];
STAssertEqualsWithAccuracy(LAT, lat, accuracy, @"Wanted: %f Got: %f", LAT, lat);
STAssertEqualsWithAccuracy(LNG, lng, accuracy, @"Wanted: %f Got: %f", LNG, lng);
STAssertEqualsWithAccuracy(RAD_LAT, rad_lat, accuracy, @"Wanted: %f Got: %f", RAD_LAT, rad_lat);
STAssertEqualsWithAccuracy(RAD_LNG, rad_lng, accuracy, @"Wanted: %f Got: %f", RAD_LNG, rad_lng);
STAssertEqualsWithAccuracy(SIN_RAD_LAT, sin_rad_lat, accuracy, @"Wanted: %f Got: %f", SIN_RAD_LAT, sin_rad_lat);
STAssertEqualsWithAccuracy(COS_RAD_LAT, cos_rad_lat, accuracy, @"Wanted: %f Got: %f", COS_RAD_LAT, cos_rad_lat);
}
¿Crees que mi prueba unitaria tiene algo que ver con eso?
Solución
Me di cuenta de que su método está creando variables llamadas radLat, pero eso también es una propiedad de su instancia; siento que puede tener problemas con el puntero.
Intente cambiar el nombre de las variables de su método (double radLat
, etc.) a algo diferente y vea si eso cambia la forma en que se ejecuta su código.Creo que el código no se comporta de la forma esperada, aunque será útil saber más sobre el código que opera en su clase Location
.