【问题标题】:Core Data: Custom Setter Which Does Cascading Calculation Failing核心数据:级联计算失败的自定义设置器
【发布时间】:2012-02-08 07:03:52
【问题描述】:

我有一个名为 Location 的类,它具有以下自动生成的声明,

#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

在objective-c类别中,我创建了两种方法来根据纬度和经度计算其他属性,

- (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]];
}

当我运行我的单元测试时,有一半的时间我得到了这个:

Lat 40.7302133
Lng -74.0003337
RadLat 0.7108763271245849
RadLng -1.291549470639518
CosRadLat 0.7577903652576623
SinRadLat 0.6524980937310535

另一半,我明白了:

Lat 40.7302133
Lng -74.0003337
RadLat 0
RadLng 0
CosRadLat 0
SinRadLat 0

我做错了什么?

单元测试

这是我用来在单元测试中保存上下文的函数,

- (void)saveContext
{
    NSLog(@"%@ saveContext", self.name);

    NSError *saveError = nil; 
    STAssertTrue([self.managedObjectContext save:&saveError], @"Failed to save context to persistent store: %@", saveError);
}

我是这样称呼它的,

// 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];
}

这部分通常有效。发生的情况是,setup 被调用,它运行这个测试,这就是它失败的地方,

- (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);
}

你认为我的单元测试与它有什么关系吗?

【问题讨论】:

  • 你使用NSNumber*来回转换简直是要了我的命!已经直接使用double了!
  • 好吧,因为这是核心数据,我必须将latitude、longitude 等存储为NSNumber*。但是,我确实尝试过在可能的情况下使用double,但并没有改变结果。

标签: objective-c ios core-data ios5 automatic-ref-counting


【解决方案1】:

我注意到您的方法正在生成名为 radLat 的变量,但这也是您的实例的属性 - 我觉得您可能遇到了指针问题。

尝试将方法变量的名称(double radLat 等)更改为不同的,看看是否会改变代码的运行方式。我认为该代码的行为方式与您的预期不同 - 尽管了解更多有关在您的 Location 类上运行的代码会有所帮助。

【讨论】:

  • 我已更新我的代码以反映您的评论和此答案中的更改。我给了你 +1,但我仍然遇到同样的问题。
  • 你确定你的单元测试真正反映了这段特殊的代码,而不是后面的代码吗?
  • 好的。我想到了。当[super setUp] 被调用时,我正在制作另一个Location 并保存它。有一个race condition 正在进行,最后保存的将由fetchLastLocation 返回,并且与我认为是正确的位置相比,但根据谁赢得比赛,一半的时间会出错。谢谢蒂姆,这是我的单元测试!
  • 很高兴你得到它!现在我需要尝试狙击您关于 SO 的所有问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
  • 2016-02-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多