Displaying a number as a string - ios

I receive a NSDictionary using AFNetworking. that dictionary has many values.
one of these I think is an INT or NSNumber, dont know what's the automatic conversion. The numbers expected are 2 and 3 but somehow I always get a very long number... I tried all the things I know and could find but I cant get it to show the right number in the
cell.numberOfLikes.text
These are all the things I've tried with no success. I would appreciate some guidance
NSLog(#"%i",_myDownloadedInfo[#"routines"][indexPath.row][#"routine"][#"routineDownloads"]);
NSLog(#"%i",[NSNumber numberWithInt:_myDownloadedInfo[#"routines"][indexPath.row][#"routine"][#"routineDownloads"]]);
cell.numberOfDownloads.text = [NSString stringWithFormat:#"%i",_myDownloadedInfo[#"routines"][indexPath.row][#"routine"][#"routineDownloads"]];
cell.numberOfLikes.text =_myDownloadedInfo[#"routines"][indexPath.row][#"routine"][#"routineDownloads"]);

The %i format specified is for basic, integer data types. Since you have (or try to create) an NSNumber object, you can use %# to log it. %# is used for Objective-C objects in format specifiers.
But that doesn't help when you want to assign the NSNumber to your text field. You need to convert the number to an NSString. Ideally you should use an NSNumberFormatter to convert the NSNumber to an NSString.
Do this:
NSNumber *likesNumber = _myDownloadedInfo[#"routines"][indexPath.row][#"routine"][#"routineDownloads"];
NSString *numberText = [NSString stringWithFormat:#"%d". [likesNumber intValue]];
NSLog(#"Number: %#", numberText);
cell.numberOfLikes.text = numberText;

Several points.
First, the first argument of NSLog is a format specifier. It is entirely equivalent to the format specifier used in [NSString stringWithFormat:] and there's rarely a need for both.
Next, data in Objective-C can be individual int values, char values, char* values (which are C strings), float values, and Objective-C object values. (Plus a few assorted long, unsigned, etc values that you rarely use.)
An NSString is an Objective-C object, as is an NSNumber. An NSInteger, on the other hand, is an alias for a particular size of int and generally interchangeable with int. Very often people get confused with NSNumber (object) vs NSInteger (scalar int) -- they are not the same.
In an NSLog or stringWithFormat specifier you use % followed by one or more characters to indicate how a value (in the following list of values) is to be formatted. %d or %i is an int. (%d is preferred.) %f is a simple floating-point value (but the formatting of these can get more complicated). %s is a C-style string (ie, a char* value). %# is used for formatting an Objective-C object. You use %#, in particular, to format an NSString or (to get the default presentation) an NSNumber.
It's important to understand how %# works in a format string. When the format interpreter encounters it, it interprets the next item in the value list as a pointer to an Objective-C object and invokes the description method of that object. An NSString just returns itself as the result of description, while an NSNumber returns an NSString that represents the character representation of the number's value. Other objects (all Objective-C objects support description, if only by default) return either a simple identification of the object type or a representation of the object's internal values.
So, if you have an NSNumber, you can directly format it with %#, or you can extract the numeric value (eg, [someNSNumber intValue]) and then format that value appropriately (eg, %d). A reason for doing the latter would be if you wanted to specify the column width for the number (eg, %5d, to format the number into a 5-position field).
See here for some (gory) details on the various format specifiers.

Hint: %i is the conversion specifier for int.
one of these I think is an INT or NSNumber, dont know what's the automatic conversion
Now go back and read the documentation of NSArray, think about whether or not it can contain ints, then proceed reading.
So the objects in the dictionary are instances of NSNumber -> they're Objective-C objects -> they are implemented using pointers. Poor NSLog() tries to convert the pointer value to an integer. Either use %# to get the description of the number, or %i and [theNumber intValue] to print its integer value.

Related

Using sqlite3_column_text() to fetch interger value

I have a table with TEXT, INTEGER, REAL and other data types.
I wrote a generic sql function to read results for all queries using sqlite3_column_text() like so:
char *dataAsChar = (char *) sqlite3_column_text(compiledStatement, ii);
Although I should be using sqlite3_column_int etc. to read the numeric values, the above code seems to work for me. I get the number values as string which I later convert to int using [*numberAsString* intValue].
Since I am using a generic function to read all my db values, this is very convenient for me. But is there something that can go wrong with my code?
I could use sqlite3_column_type for each column to determine the type and use appropriate function. Am I correct in assuming that sqlite3_column_text basically returns the column value in TEXT format and does not necessarily need the value itself for be TEXT?
The only situation where I can see this implementation failing is with BLOB data type.
The documentation says:
These routines attempt to convert the value where appropriate. […]
The following table details the conversions that are applied:
Internal Type Requested Type Conversion
NULL TEXT Result is a NULL pointer
INTEGER TEXT ASCII rendering of the integer
FLOAT TEXT ASCII rendering of the float
BLOB TEXT Add a zero terminator if needed

Correct way to retrieve a NSInteger property from another class?

I am making a (sort of) trading card game , using SpriteKit. I created a Card class, and each card has a rank :
// in Card.h
#property NSInteger cardRank;
In one of my another class (Game class), i'm trying to retrieve this value. I create a Card instance, and display the value in the console (testing purpose) :
Card *tmpCard = [[Card alloc] init];
NSLog(#"%#", tmpCard.cardRank);
When I use %# in the NSLog, I get the right value for the cardRank, but an Xcode warning saying that "Values of type nsinteger should not be used as format arguments" and that I should cast to "long".
If I cast to long… :
NSLog(#"%ld", (long)tmpCard.cardRank);
… I got no error, but not the right value for cardRank (it displays something like "140378469207968").
Could someone explain me why I got this result ?
I am probably making a rookie mistake but couldn't understand it myself in the las few days.
Get a good book about the C language, and look at format strings. The format strings in Objective-C are exactly the same, except for %# which expects an object.
The correct way to print NSInteger and NSUInteger is %zd (which works fine on 32 and 64 bit). Anyway, if you turn warnings on in Xcode (as you should) and if you turn warnings into errors in Xcode (as you should), the compiler will tell you where you are wrong and even make suggestions how to fix it.
BTW. If you use %# to print an NSInteger, I expect a crash. Your post doesn't seem to contain the truth. When you have questions, report very, very precisely and correctly what you are doing. 'It displays something like "140378469207968"' is useless. Show exactly what it displays.
Log int with %d
Log NSInteger with %zd
Log NSUInteger with %tu
You can find String Format Specifiers on Apple doc.
BTW, NSLog(#"%ld", (long)tmpCard.valeurTop); will for sure not show you "the right value for cardRank" as you're asking for valeurTop...
%d format specifier is used for NSInteger type values but since iOS supports both 32 & 64 bits, 64 bit NSInteger is of type long, which can be printed with %ld format specifier.
For a reference %# is used for NSString values.
BTW you are printing the wrong variable hence it prints garbage value.

NSSet full of NSStrings. When I print the set to the console, the results are unexpected

Here's what happens:
Internal database stuff: one class has a string property on it, that stores a phone number. This number is set using the code
CFBridgingRelease(ABMultiValueCopyValueAtIndex(ABRecordCopyValue(record, kABPersonPhoneProperty), 0));
My function: finds all objects of this type, and stores phone numbers of each object in an NSMutableSet.
Debug: I print the description of the set to the console.
Results:
Some of the set's objects look as expected (the majority actually): "+64 27 0124 975"
Some are missing quotation marks: 027 7824 565
Some have weird unicode symbols: "021\U00a0026\U00a017788"
My question:
Why the difference - what does it mean, and do I need to fix anything?
NSLog with %# – as I assume you are using – has some intelligence in how it presents NSStrings as it calls the description method. If the string has anything other than alphanumerics, such as the '+' or '\' above, it will use quotes. The string with unicode characters simply has its characters encoded as shown, and they are automatically converted into this lossless format. You should be able to convert it to something prettier for the console if you really need to with something like this:
NSLog(#"%#", [NSString stringWithCString:[myString.description cStringUsingEncoding:NSASCIIStringEncoding] encoding:NSNonLossyASCIIStringEncoding]);

NSNumberFormatter returning null in Xamarin.iOS + ShinobiChart

I'm trying to get a string parsed into a NSNumber that has the % character in the end where I can use the in the ShinobiChart value property of the series.
Given the following code, I'm creating the NSNumberFormatter:
var formatter = new NSNumberFormatter ();
formatter.NumberStyle = NSNumberFormatterStyle.Percent;
var locale = new NSLocale ("en_US");
formatter.Locale = locale;
Now, I'll try to use the formatter to get the value for the chart slice label:
var value = formatter.NumberFromString (answer.RepliesShare.ToString () + "%");
This will give me the value 0.33... The point is, if I remove the "%" from the string, I'll get null on the value.
So, I need get a NSNumber that has the value of (i.e.) 30%(in other words, numberString+"%").
How can I get it?
To be more clear, I'm trying to achieve this:
Since ShinobiChart takes a Value of Type NSNumber and my RepliesShare is a decimal I'm trying just convert my decimal from 33.00 to 33%. The ShinobiChart don't take a string, otherwise I would have it handled. I found that NSNumber can be formatted with NSNumberFormatted so I thought I can use it since the Chart takes a number.
NSNumberFormatters do 2 things (amongst others):
Translate a formatted numeric NSString into an NSNumber (#"25.4%" → #"0.254")
Translate an NSNumber into a formatted NSString (#"0.254" → #"25.4%")
It's not terribly clear from your question, but I think you're trying to do the latter of these two options, but you're using the method for the first.
The following will take an NSNumber object and turn it into a %age formatted string:
var formatter = new NSNumberFormatter();
formatter.NumberStyle = NSNumberFormatterStyle.Percent;
formatter.Locale = NSLocale.CurrentLocale;
var value = formatter.stringFromNumber(new NSNumber(0.254));
This will result in value being an NSString representing 25.4%.
Provided that RepliesShare property on your answer object is an NSNumber then you can do the following to get the string you require:
var value = formatter.stringFromNumber(answers.RepliesShare);
Hope that helps.
Note: Rather than using new NSLocale ("en_US") here I used NSLocale.CurrentLocale. This will ensure that the resultant string is formatter appropriately for the current user's device. The most obvious effect that this will have with percentages is that in some European countries, a comma , is used as the decimal separator instead of a period ..
A SChartDonutSeries (and consequently SChartPieSeries) object has a LabelFormatString property. This takes a string and is used to format those labels. It has the same syntax as is used in NSNumberFormatter. Therefore, to get the behaviour you want, set the LabelFormatString after you've created the series object in your SChartDataSource subclass:
var series = new SChartDonutSeries();
series.LabelFormatString = "%0.2f%%";
This will format numbers as 2 decimal placed with a percentage sign on the end. i.e. 25.462 → 25.46%. Adjust the format string appropriately to get the format you desire. Remember that to get a % sign to appear you need to escape it - %%.
Further details on creating an appropriate format string are available here:
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/Strings/Articles/formatSpecifiers.html
I think you're misunderstanding what NSNumberFormatter does. It has nothing at all to do with NSNumber objects.
NSNumberFormatter is an object for working with strings that happen to contain numeric values. It is not for working with NSNumber.
Since ShinobiChart takes a Value of Type NSNumber and my RepliesShare is a decimal I'm trying just convert my decimal from 33.00 to 33%.
You do not want to convert anything, just give 33.00 as a decimal type to ShinobiChart. I think Xamarin will convert your C# decimal to an NSNumber automatically.
If it doesn't work, try giving new NSNumber(33.00) to ShinobiChart. There should be no percents anywhere. You definitely do not want to create an NSNumberFormatter

CFStringTokenizer's token range in a UTF8 C string

I'm using CFStringTokenizer to break a load of text into words, but I'm having difficulty bridging whatever encoding CFString is using and UTF8. Consider this:
NSString *theString = #"Lorem ipsum dolor sit amet!";
const char *theCString = [theString cStringUsingEncoding:NSUTF8StringEncoding];
tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault,
(__bridge CFStringRef)theString,
CFRangeMake(0, [theString length]),
kCFStringTokenizerUnitWordBoundary,
locale);
while ((tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)) != kCFStringTokenizerTokenNone) {
tokenRange = CFStringTokenizerGetCurrentTokenRange(tokenizer);
memcpy(resultPtr, theCString+tokenRange.location, tokenRange.length);
}
Unfortunately the range reported by the tokenizer is incorrect when trying to read from the C string if any non-ascii characters have been encountered. How can I go about getting the correct range from the tokenizer to be able to pull the correct chars from my C string?
To clarify, the memcpy stuff is a tad more complex than above, and is necessary for performance on my target device, the iPhone. So I can't even do anything like create a CFString substring and convert that, I need the range in the C string. Is there any way to do that without reimplementing various word boundary libraries to get it working for the various different locales I need it to work with? (which is as many as possible, so I can't just iterate through looking for ' ' unfortunately..)
Alec
NSStrings and CFStrings deal in UTF-16, not UTF-8, but that isn't the real problem.
Your code has two problems:
You're assuming that the C string's indexes correspond to the source string's indexes.
You're copying and converting the entire string to a UTF-8 C string at once.
#1 is the cause of the range mismatches, and #2 causes potentially high memory usage, depending on the length and content of the string. (UTF-8 can take as many as four bytes per character in some alphabets—and then add one for the C string terminator.)
You can solve both of these problems in a single change.
Create an NSMutableData to hold the output. For each token, set the data's length to the range's length; then, tell the string to get bytes within the desired range in the desired encoding and store them in the data's mutableBytes buffer. NSString has a method with a very long selector (briefly, getBytes:::::::) that you will want to use for this.
Since you use the range that is relative to the string exclusively with the string, there is no index/range mismatch, and each token will be output correctly.
If you really need a C string, you can set the data's length to the range's length + 1, then set the last byte to '\0' with a separate assignment after getting the token bytes. (Without the separate assignment, the byte may hold a previous value.)

Resources