Convert from pounds to kilograms, possibly using Core Data - objective-c

In my app, numbers are displayed as pounds. I need to add an option to use kilograms instead. Does anyone know how to go about this? I'm using Core Data to store numbers. I know I can do it all manually by using an if statement then doing a conversion, but there must be better way.
EDIT
Actually, I think I ran into a huge problem. It isn't as simple as converting numbers. Because I am using a picker and I want to offer international imperial support, The picker should display whole, sensible numbers in kg. If I just convert the numbers to kg, I will get decimal numbers which people will not know how to use. Any suggestions?

https://github.com/davedelong/DDUnitConverter
NSNumber *weightInPounds = [NSNumber numberWithInt:42];
NSNumber *weightInKilos = [[DDUnitConverter massUnitConverter] convertNumber:weightInPounds fromUnit:DDMassUnitUSPounds toUnit:DDMassUnitKilograms];
Pretty simple.

I would suggest using a custom NSFormatter to convert your numbers into strings for display. You would always store your data in one format, while providing the ability to display it in any format. You will need a simple setting (stored via NSUserDefaults) to tell the formatter what format to use. Some benefits of this are that you only have to deal with this while displaying the numbers. Since you already have to convert the numbers to strings to display them, there will be very few changes to your code. Also, you won't have to change your core data stores at all, since the setting is stored in the app's preferences. You can even subclass NSNumberFormatter for automatic formatting of the number after conversion. Here is an example implementation:
- (NSString *)stringForObjectValue:(NSNumber *)number {
double val = [number doubleValue];
BOOL isKGs = [[NSUserDefaults standardUserDefaults] boolForKey:#"wantsKGs"];
if(isKGs) val *= 0.45359237;
NSString *str = [super stringForObjectValue:[NSNumber numberWithDouble:val]];
if(isKGs) return [str stringByAppendingString:#" kg"];
return [str stringByAppendingString:#" lbs"];
}
For more information about custom formatters, see Creating a Custom Formatter.

there are so many ways you could do this.
I'd have to make some assumptions about your app, but if you want to have the option to change (globally) from lbs to kgs then i would probably have a settings dialog in your app so that a user can persist their decision to see things in lbs or kgs, i would then persist this in settings for your app and use this setting as part of your app's initialization. then, wherever you show a value of lbs or kgs you just need to check for the user defined setting and adjust the values accordingly (and probably any labels in the app as well) this would be as simple as having a check in the code that retrieves the values from core date
Check setting persist this as a globally accessible piece of state; this could be a member in your app delegate, a singleton that contains settings or simply requesting the setting wherever you need to check it. Then, in code that access the lbs data, check the setting, if its set to kg do the calculation and return that back from the data access code to the view.

It may be a good idea to code it to work always with the units and scaling as variables.
The units and scaling would be "lbs" and 1.0, or "kgs" and 0.45359237, or whatever.

Related

Writing objects to plain text in NSUserDefaults

How can I write an object to NSUserDefaults as plain text?
I've written a unit conversion system for a scientific application that basically operates around the principal of "unit objects". These objects represent a specific unit with a specific value in a given domain. The domain is represented by the class name, since everything is organized so that a time unit is literally called "TimeUnit" and a length unit is literally called "LengthUnit".
The current value of a "unit" is represented by a double, and the "unit" itself (ie, "meters", "kelvin", "hours", "pounds", etc) is represented by an NSString.
I need to be able to write these objects to NSUserDefaults.
I've already implemented a system using NSCoding and NSKeyedArchiver. This works great, I can store and retrieve units from NSUserDefaults and everything works.
The problem is that the output from NSKeyedArchiver is too big. The base64 encoded data you get from it is this gigantic chunk of characters, which is impossible to change through a plain text editor and somewhat difficult to debug. I know you can override this to a certain extent by using NSPropertyListXMLFormat_v1_0 with NSKeyedArchiver's setOutputFormat, but even that produces a fairly verbose output with a whole bunch of stuff I don't really care about (I know all that data is there for a reason, but I'm guessing that's because NSKeyedArchiver is designed to handle a lot of different situations).
It would be much easier if I could encode these objects using my own format. Something almost like:
class_name:double_value:unit_name
So a temperature unit with a value of 22 degrees celsius would become:
TemperatureUnit:22:celsius
What is the best way of achieving something like this? Should I be subclassing NSCoder? Will this let me store the objects as a plain text string in NSUserDefaults and not a base64 encoded chunk of binary data?
For something like this you could add "serialize" and "deserialize" methods (or whatever names you want). The former returns a string and the latter takes a string and returns your object.
+ (MyUnitClass *)deserialize:(NSString *)encodedString {
// split string, create new object, assign values
}
- (NSString *)serialize {
return [NSString stringWithFormat:#"%#:%f:%#", self.classname, self.double_value, self.unit_name];
}
Now you can call serialize on one of your objects and store the string in NSUserDefaults. Use deserialize to create an object from a string you have stored in NSUserDefaults.

Bundle declarations into one statement or not?

Given the following Objective-C example, is it simply a matter of style and ease of reading to keep separate statements or to bundle them into one? Are there any actual benefits of either? Is it a waste of memory to declare individual variables?
NSDictionary *theDict = [anObject methodToCreateDictionary];
NSArray *theValues = [theDict allValues];
NSString *theResult = [theArray componentsJoinedByString:#" "];
or
NSString *theResult = [[[anObject methodToCreateDictionary] theValues] componentsJoinedByString:#" "];
I take the following into consideration when I declare a separate variable:
If I might want to see its value in the debugger.
If I am accessing the variable more than once.
If the line is too long.
There is no practical difference between the two approaches, however.
Also, you haven't asked directly about this, but be aware, when you access objects using dot notation, for example:
myObject.myObjectProperty1.myObjectProperty1Property;
If you are going to access myObjectProperty1Property more than once, it can be advisable to assign it to a local named variable. If you don't, the look-up will be executed more than once.
Now I can't emphasise enough, for many if not most situations this time saving is so infinitesimal as to seriously call into question whether it is worth even spending the time doing extra typing for the assignation! So why am I raising this? Because having said that - stylistic "anality" apart (I just made up a new word) - if the section of code you are writing is running in a tight loop, it can be worth taking the extra care. An example would be when writing the code which populates the cells in a UICollectionView that contains a large number of cells. Additionally, if you are using Core Data and you are using the dot notation to refer to the properties of NSManagedObject properties, then there is far greater overhead with each and every look-up, in which case it is much more surely worth taking the time to assign any values referred to by "nested" dot notation calls to a local variable first.

Ordering NSStrings that are numbers of a particular format (ex 3:23.123)?

I have NSStrings that represent times of the format mm:ss.SSS in my app. I am trying to generate a list of "fastest times" and I'm struggling trying to figure out what data types to use to order these numbers.
What is the easiest way to order these strings from least to greatest amount of time? I'm assuming converting to a numbered data type would do the trick, but what data type should I be using? I need to preserve the mm:ss.SSS formatting.
If you have NSString objects you can convert to NSDate objects (such as these, presumably, which you could, for example, convert into ISO 8601 format using a suitable offset), then you can sort an NSArray instance of NSDate objects very easily (example) and pick from the top or bottom of the list, depending on whether you sort in descending or ascending order.
The advantage of this approach is that you are working with standard date processing functions, which can result in less code and less debugging. Reinventing the wheel may get you a faster solution, but it can also introduce bugs.
You can also use (abuse ?) localizedStandardCompare: for that purpose, because that method compares numbers embedded in the string according to their numerical value:
NSArray *times = #[ #"11:22.333", #"2:44.555" ];
NSArray *sortedTimes = [times sortedArrayUsingSelector:#selector(localizedStandardCompare:)];
NSLog(#"%#", sortedTimes);
Output:
(
"2:44.555",
"11:22.333"
)
If the strings are well-formed, with leading zeros, form an NSArray and then invoke sortedArrayUsingComparator:. But if you have values like 12:34.567 and 2:34.567, this approach won't work. You'll have to convert, either to double or NSNumber, storing seconds (that is, 2:34.567 converts to 154.567).
Note that these are not NSDate objects. An NSDate marks a particular instant in time, and these appear to be simply durations.
If you use NSNumber, you can still use sortedArrayUsingComparator:. You'll have to write a subclass of NSFormatter, to convert between mm:ss.SSS and NSNumber and back again.
See the documentation for NSComparator for a blocks-based example. You'll also need the Class Reference for NSFormatter. The FormatterKit project on GitHub has some nice NSFormatter sample code.
My advice is to create your own class that represents the datatype for mm, ss and SSS. You can then write your own prettyprint and compare methods for the datatype. The compare method itself would be fairly simple to implement and you can then use that compare method to sort an array of such objects.

How do I store date using NSUserDefaults after I have the number in a variable using Xcode

I'm new and stuck any help would be great! I am using Xcode to build my app.
I have an IBAction "button pressed", this generates random numbers, then I have a bunch of if statements. Ultimately if things match up my long long variable "coins" has a numeric value. Right now I just change that value as in coins = coins + 10 and then display it in a UILabel. I now need to store that value, after all the calculations, whenever the user presses the button. So that their total of "coins" is being added to or subtracted from. Additionally I will want to add and In App Purchase that ads to the "coins" variable. So I know I need a way to store the value, even when the app is closed and re-opened.
Is there a way to use NSUserDefaults to store that value, either within the original IBAction buttonPressed? Also Or any help at all or suggestions would be great! Thanks and sorry if this sounds lame, but I'm on my first app :)
To store a number in NSUserDefaults:
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithUnsignedLongLong:coins] forKey:#"coins"];
To retrieve from NSUserDefaults and store it into coins:
coins = [[[NSUserDefaults standardUserDefaults] objectForKey:#"coins"] unsignedLongLongValue];
This is assuming you've declared coins as being an unsigned long long, and not a signed one. Also, there are convenience methods for storing NSIntegers if you want to go through those.
EDIT: Just realized you want to have IAPs, should've read more carefully. I recommend against storing anything of value (passwords, usernames, purchasable currency, highscores that can be submitted to an online leaderboard, etc) in NSUserDefaults. It's stored as a simple .plist (XML) which could be edited relatively easily as far as I understand.

methods sequence by NSMutableArray/NSMutableDictionary contents (Image multi-effecting)

What I want to do:
I want to implement ability for user to use CIFilters on image. So I need somehow to fix it's sequence. For example if user opens image, then applies CIGaussianBlur, and then CIColorControls and then CISepia, I need to get result like that:
On user opened image apply CIGaussianBlur -> on CIGaussianBlur output image apply CIColorControls - > on CIColorControls output image apply CISepia.
Thats OK. But what if then user turns off CIGaussianBlur? I need then to repeat this effect's sequence just without blur. It would look like this:
On user opened image apply CIColorControls -> on CIColorControls output image apply CISepia.
The question
Is it possible to do something like this:
After applying any effect, add some string in NSMutableArray or NSMutableDictionary. Then when applying another effect, check NSMutableArray or NSMutableDictionary contents like that:
if object at index 0 is equal to "blur", apply blur on source image, then take blur's output image like current effect's input image
And so on? So that effects would be re-applied every time in their sequence made by user.
If it is possible maybe someone could suggest me any solution?
I think that this is a great instance for the factory idea to be used.
You should store your array of filters to process the image as an array - that maintains sort order, and is fairly straightforward to deal with (other than something like a NSCountedSet).
The next logical question to ask, then, is how do we apply the factory pattern here? The most important thing to consider is what type should the context object be? Here are a few thoughts:
Using NSString as a constant identifier.
Probably the simplest to start, its , and easy to understand - the downside is that it's slower than other options, and can get to be quite the complex if-else block, as you cannot use a switch statement on a NSString.
NSNumber, wrapping an enum value.
This is probably one of the better options. You can convert right down to an int variable, which compares quite fast on almost any processor I can imagine, and, if you use ObjC 2.5's fancy literals, you could do something like this:
[filters addObject:#(filterType_gaussianBlur)];
Where filterType_gaussianBlur is an enum constant or something.
Another advantage to using an enum is the support for switch statements out of the box. It cleans up your code if done properly, it's faster than a large if-else block, the only thing to look out for is ensuring that you break properly!
Storing Class objects
This one may require some explaining. In objective-c, you can actually store a reference to the type of an object, CIGaussianBlur, NSString, NSData, etc.
This class "object" allows you to dynamically create an object based just on it's type, for example:
Class cls = nil;
if (stringMutable)
cls = [NSMutableString class];
else
cls = [NSString class];
NSString *mutableOrNot = [[cls alloc] initWithString:#"Hello World!"];
However, the disadvantage to this approach would be the inability to configure the objects after they are initialized, and you must use the same selector (method) to initialize each one. If that is not an issue (I do not use CoreImage), then using the Class approach should be fine.
All in all, use whatever makes sense in the situation. If these filters need no additional configuration after they have been initialized, then approach 3 makes a lot of sense. I personally wouldn't recommend approach 1, unless it really is necessary to use a string. Whenever you can, always try to control the values that an object can have. It makes your life much easier, trust me.