Domanda

I am wondering if someone could help me how to make connections between measures, for example how can I calculate relation between centimeters and inches like in the picture. This is my app for school project and it is more or less done except that part. So i am reading values from plist, and based on my first column in picker, second and third are displayed. All units and measures are read from plist. With energy, distance, volume etc. as keys.

So what would be easiest way to make connections between measures? My easiest and most amateur idea is to write loooong code, something like this:

if (first column == distance){
    if (second column ==millimeter) {
    case 0: if (third column == millimeter) then result=x*1;
    case 1:if (third column == centimeter) then result=0/100;
      .
      .
      .
    }
    if (second column == centimeter){
    case 0:
    case 1:
      .
      .
      .
    }}

and that would result in like 1000 lines of unnecessary code. Does anyone have better idea? Thanks in advance.

È stato utile?

Soluzione

The whole thing can be done with data, no ifs, no switches... it just needs to be organized a little bit. Consider the following:

@property (strong, nonatomic) NSArray *distanceIndex;
@property (strong, nonatomic) NSArray *weightIndex;

@property (strong, nonatomic) NSArray *distanceConversion;
@property (strong, nonatomic) NSArray *weightConversion;

- (void)initConversions {

    // we get strings in as our units, so we need to convert these to array indexes
    // make up our own convention, meters=0, inches=1, etc

    self.distanceIndex = @[@"meters", @"inches", @"miles"];
    self.weightIndex = @[@"grams", @"ounces", @"pounds"];

    // you might read these from a file, but in code, just to illustrate...
    // the order follows the order of the index.  so the meters line is first
    // and the conversion factors are meters->meters, meters->inches, meters->miles etc.
    // notice the 1.0's on the diagonal, and that numbers reflected across
    // the diagonal are reciprocals

    self.distanceConversion =
        @[ @[@"meters", @[@1.0, @39.37, @0.000621]],
           @[@"inches", @[@0.254, @1.0, @0.00001578]],
           @[@"miles ", @[@1609.0, @63360.0, @1.0]] ];

   // and so on... same thing for self.weightConversions
}

- (double)convertDistance:(double)value from:(NSString *)fromUnits to:(NSString *)toUnits {

    NSUInteger fromIndex = [self.distanceIndex indexOfObject:fromUnits];
    NSUInteger toIndex = [self.distanceIndex indexOfObject:toUnits];

    // throw an exception if passed units that we don't recognize
    NSAssert(fromIndex != NSNotFound && toIndex != NSNotFound, @"could not find units");

    NSArray *conversionRow = self.distanceConversion[fromIndex][1];
    NSNumber *conversionNumber = conversionRow[toIndex];
    double conversion = [conversionNumber doubleValue];

    return value * conversion;
}
- (double)convertWeight:(double)value from:(NSString *)fromUnits to:(NSString *)toUnits {

    // same idea here, if you have the weight conversion data
    return 0;
}

Altri suggerimenti

If I were to write this, I would do this:

For each type of conversion (I'm going to use distance as the example) First pick a standard unit (I'm picking meter) Now take conversion of every unit to meter and save it into a database (or array, plist, whatever).

Example is cm:0.1, km:1000, etc.

Then for each conversion you need to make, just take the conversion numbers of the two, convert the input to meters using the first, and convert to the output using the second.

Example: 5 cm to km, 5 * 0.1 = 0.5 meters. 0.5 / 1000 = 0.0005 km.

That's just how I would approach this

You might want to take an object oriented approach.

Have a base abstract class or interface, that can hold two units called UnitType. It would have 2 properties FromUnit, ToUnit, and a method called Convert:.

Also have another abstract class called Unit. This would have two methods ConvertToStanard:amount and ConvertFromStandard:amount This would convert to a standard unit for each type, say the lowest unit.

So your MeterUnit would look like this

@implementation MeterUnit

-(double) ConvertToStandard:(double) amount
{
    return amount/100;
}

-(double) ConvertFromStandard:(double) amount
{
    return amount*100;
}

@end

And your centimeter unit would just return amount (it's already in centimeters).

@implementation CentimeterUnit

-(double) ConvertToStandard:(double) amount
{
    return amount;
}

-(double) ConvertFromStandard(double) amount
{
    return amount;
}

@end

Now your UnitType's Convert() method would just look like this, since each subclass defines hot to go to/from the standard unit, your DistanceUnitType class doesn't know or care how it is done. It just knows to call ConvertToStandard and ConvertFromStandard:.

-(double) Convert:(double) amount
{
    double stanardUnit = [FromUnit ConvertToStandard:amount];
    return [ToUnit ConvertFromStandard:standardUnit];
}

UnitType might also define the available units and give that to the UIPicker.

And in fact, you could just have two properties on each of your unit's classes and just have your base class call standard function too.

Why is this better? Maybe it isn't, but at least you are only defining each unit once. Where in your nested if/case statement, you need to define each conversion a bunch of times. Plus if you want to add a new one, you need to create a bunch of new entries in you switch statement. But in this case you just define one more class and add it as an available unit for your UnitType. That's it!

Anyways, I'm sure there are lots of mistakes and issues with this, but if this is a class project it's probably good if that's the case. Hopefully it give a guideline on one way of approaching this.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top