Print out the variable name objective-C - iphone

Continued from the last question here: Log method name in Obj-C . I just wondered if there is a way to print out the variable name as well. For example:
NSString *name = "vodkhang";
NCLog(#"%#", name);
and I hope that the output should be:
name: vodkhang
Just to summarize the previous post, currently, I can print out the class name, method name and the line number when I call
NCLog(#"Hello World");
<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world
with
#define NCLog(s, ...) NSLog(#"<%#:%d> %#", __FUNCTION__, __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__])

#define logIntVariable(x) NSLog( #"Value of %s = %d",#x, x)
- (void) myRoutine {
int intValue = 5;
logIntVariable(intValue);
}

Related

JSON result (NSArray): valueForKey doesn't work as expected

I have a NSArray as a result of a web service (JSON) request.
If I print NSLog("%#", jsonResult) the Array it shows up correctly:
(
{
text = “Some text”;
coordinates = “11.333345 - 09.33349”;
}
{
text = “Some text2”;
coordinates = “11.333345 - 09.33349”;
}
{
text = “Some text3”;
coordinates = “11.333345 - 09.33349”;
}
…
)
But If I try to access the value of the key "text" of each entry within the NSArray with my following function, I always get an output like this:
Text )r'ì• (instead of "Some text2, 3 ....")
So I think there is a mismatch of types, but I don't know how to figure out where the problem is.
In Objective-C it works very well.
func getResult(){
self.webService.getResult({ jsonResult in
jsonResult!.enumerateObjectsUsingBlock({ object, index, stop in
var txt : NSString = object.valueForKey("text") as NSString
NSLog("Text %s", txt)
})
NSLog("Ready %#", jsonResult!)
});
}
Any ideas what's going wrong?
UPDATE 1
I figured out, that if I just use NSObject instead of NSString it displays the text correct
var txt : NSObject = object.valueForKey("text") as NSObject
NSLog("%#", txt)
But anyway, I have to cast that NSObject object to NSString or String, to display...
Which encoding is it expecting to display the string...or how to cast this NSObject????
var txt : NSString = object.valueForKey("text") as NSString
NSLog("Text %s", txt)
The problem is the %s format specifier, which is for C-style strings. You need %#, which is for objects.
In Swift, it's recommended to use println(), which does away with format strings altogether:
var txt : NSString = object.valueForKey("text") as NSString
println("Text \(txt)")

how to solve a conditional equation in iOS

I want to solve a conditional equation in iOS:
The equation I get from database is in NSString format, for example:
if((height > 0), (weight+ 2 ), ( weight-1 ) )
As per our understanding, if I parse the above string and separateheight>0condition, it will be in the NSString format. But to evaluate it how do I convert the string to a conditional statement?
Once the conditional statement is obtained the equation can be solved by converting it to a ternary equation as follows:
Bool status;
NSString *condition=#” height>0”;
If(condition)    //But condition is treated as a string and not as a conditional statement.
{
status=True;
}
else
{
status=False;
}
Return status ? weight+ 2 : weight-1;`
Also the equations can dynamically change, so they cannot be hard coded. In short how do I solve this equation which I get as a NSString.
Thank you for your patience!
DDMathParser author here...
To expand on Jonathan's answer, here's how you could do it entirely in DDMathParser. However, to parse the string as-is, you'll need to do two things.
First, you'll need to create an if function:
DDMathEvaluator *evaluator = [DDMathEvaluator sharedMathEvaluator];
[evaluator registerFunction:^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError *__autoreleasing *error) {
if ([args count] == 3) {
DDExpression *condition = [args objectAtIndex:0];
DDExpression *resultExpression = nil;
NSNumber *conditionValue = [condition evaluateWithSubstitutions:vars evaluator:eval error:error];
if ([conditionValue boolValue] == YES) {
resultExpression = [args objectAtIndex:1];
} else {
resultExpression = [args objectAtIndex:2];
}
NSNumber *result = [resultExpression evaluateWithSubstitutions:vars evaluator:eval error:error];
return [DDExpression numberExpressionWithNumber:result];
}
return nil;
} forName:#"if"];
This creates the if() function, which takes three parameters. Depending on how the first parameter evaluates, it either evaluates to the result of the second or third parameter.
The other thing you'll need to do is tell the evaluator what height and weight mean. Since they don't start with a $ character, they get interpreted as functions, and not variables. If they started with a $, then it would be as simple as evaluating it like this:
NSString *expression = #"if(($height > 0), ($weight+ 2 ), ( $weight-1 ) )";
NSDictionary *variables = #{#"height" : #42, #"weight" : #13};
NSNumber *result = [expression evaluateWithSubstitutions:variables evaluator:evaluator error:nil];
However, since they don't start with a $, they're functions, which means you need to tell the evaluator what the functions evaluate to. You could do this by creating functions for both height and weight, just like you did for if:
[evaluator registerFunction:^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError **error) {
return [DDExpression numberExpressionWithNumber:#42];
} forName:#"height"];
Alternatively, you could make it a bit more dynamic and use the functionResolver block of DDMathEvaluator, which is a block that returns a block (woooooo) and would look like this:
NSDictionary *values = #{#"height": #42, #"weight": #13};
[evaluator setFunctionResolver:^DDMathFunction(NSString *name) {
DDMathFunction f = ^(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError **error) {
NSNumber *n = [values objectForKey:name];
if (!n) { n = #0; }
return [DDExpression numberExpressionWithNumber:n];
};
return f;
}];
With those two pieces in place (registering if and providing the values of height and weight), you can do:
NSString *expression = #"if((height > 0), (weight+ 2 ), ( weight-1 ) )";
NSNumber *result = [expression evaluateWithSubstitutions:nil evaluator:evaluator error:nil];
... and get back the proper result of #15.
(I have plans to make DDMathParser allow unknown functions to fall back to provided variable values, but I haven't quite finished it yet)
you will have to write your own interpreter or find one that supports this kind of expressions.
The first part (the condition) can be evaluated by NSPredicate. For the second part (the calculation) you will need some math expression evaluation. Try this out https://github.com/davedelong/DDMathParser. Maybe you can do both with DDMathParser but i am not sure.

Localization with variable and constant definition in header file

How do I use NSLocalizedString in this case when I have a header where I define a few parameters, say:
#define appKey #"appKey1 is: %#"
I think I know that my Localizable.strings should look like that:
"blabla" = "appKey1 is: %#"
but how do I use NSLocalizedString? I read that I need to use stringWithFormat, but not sure how...
thanks!
You would define your constant as:
#define appKey NSLocalizedString(#"appKey1 is: %#", #"appkey constant")
Then it should get picked up by the genstrings tool in the usual way.
In the strings file it would then come out like this:
/* appkey constant */
"appKey1 is: %#" = "appKey1 is: %#";
And you would translate just the right hand side.
String literals are acceptable in NSLocalizedStrings. What you need to do is something like
#define appKey NSLocalizedString(BlahBlah , comments);
"BlahBlah" = "appKey1 is: %#";
(Be sure to end your lines with a semi-colon in Localizable.strings, or it will end up being corrupted).
This is how you would do it normally,
NSString * myString = [NSString stringWithFormat:#"appKey1 is: %#",yourAppKeyString];
Since you have it defined you can use it like so
NSString * myString = [NSString stringWithFormat:appKey,yourAppKeyString];
Either case both would fill your myString like so
yourAppKeyString = #"keyString";
myString = #"appKey1 is: keyString";
NSString * myString = [NSString stringWithFormat: NSLocalizedString(#"appKey", #""),yourAppKeyString];

How to check if NSString is contains a numeric value?

I have a string that is being generate from a formula, however I only want to use the string as long as all of its characters are numeric, if not that I want to do something different for instance display an error message.
I have been having a look round but am finding it hard to find anything that works along the lines of what I am wanting to do. I have looked at NSScanner but I am not sure if its checking the whole string and then I am not actually sure how to check if these characters are numeric
- (void)isNumeric:(NSString *)code{
NSScanner *ns = [NSScanner scannerWithString:code];
if ( [ns scanFloat:NULL] ) //what can I use instead of NULL?
{
NSLog(#"INSIDE IF");
}
else {
NSLog(#"OUTSIDE IF");
}
}
So after a few more hours searching I have stumbled across an implementation that dose exactly what I am looking for.
so if you are looking to check if their are any alphanumeric characters in your NSString this works here
-(bool) isNumeric:(NSString*) hexText
{
NSNumberFormatter* numberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
NSNumber* number = [numberFormatter numberFromString:hexText];
if (number != nil) {
NSLog(#"%# is numeric", hexText);
//do some stuff here
return true;
}
NSLog(#"%# is not numeric", hexText);
//or do some more stuff here
return false;
}
hope this helps.
Something like this would work:
#interface NSString (usefull_stuff)
- (BOOL) isAllDigits;
#end
#implementation NSString (usefull_stuff)
- (BOOL) isAllDigits
{
NSCharacterSet* nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
NSRange r = [self rangeOfCharacterFromSet: nonNumbers];
return r.location == NSNotFound && self.length > 0;
}
#end
then just use it like this:
NSString* hasOtherStuff = #"234 other stuff";
NSString* digitsOnly = #"123345999996665003030303030";
BOOL b1 = [hasOtherStuff isAllDigits];
BOOL b2 = [digitsOnly isAllDigits];
You don't have to wrap the functionality in a private category extension like this, but it sure makes it easy to reuse..
I like this solution better than the others since it wont ever overflow some int/float that is being scanned via NSScanner - the number of digits can be pretty much any length.
Consider NSString integerValue - it returns an NSInteger. However, it will accept some strings that are not entirely numeric and does not provide a mechanism to determine strings which are not numeric at all. This may or may not be acceptable.
For instance, " 13 " -> 13, "42foo" -> 42 and "helloworld" -> 0.
Happy coding.
Now, since the above was sort of a tangent to the question, see determine if string is numeric. Code taken from link, with comments added:
BOOL isNumeric(NSString *s)
{
NSScanner *sc = [NSScanner scannerWithString: s];
// We can pass NULL because we don't actually need the value to test
// for if the string is numeric. This is allowable.
if ( [sc scanFloat:NULL] )
{
// Ensure nothing left in scanner so that "42foo" is not accepted.
// ("42" would be consumed by scanFloat above leaving "foo".)
return [sc isAtEnd];
}
// Couldn't even scan a float :(
return NO;
}
The above works with just scanFloat -- e.g. no scanInt -- because the range of a float is much larger than that of an integer (even a 64-bit integer).
This function checks for "totally numeric" and will accept "42" and "0.13E2" but reject " 13 ", "42foo" and "helloworld".
It's very simple.
+ (BOOL)isStringNumeric:(NSString *)text
{
NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:text];
return [alphaNums isSupersetOfSet:inStringSet];
}
Like this:
- (void)isNumeric:(NSString *)code{
NSScanner *ns = [NSScanner scannerWithString:code];
float the_value;
if ( [ns scanFloat:&the_value] )
{
NSLog(#"INSIDE IF");
// do something with `the_value` if you like
}
else {
NSLog(#"OUTSIDE IF");
}
}
Faced same problem in Swift.
In Swift you should use this code, according TomSwift's answer:
func isAllDigits(str: String) -> Bool {
let nonNumbers = NSCharacterSet.decimalDigitCharacterSet()
if let range = str.rangeOfCharacterFromSet(nonNumbers) {
return true
}
else {
return false
}
}
P.S. Also you can use other NSCharacterSets or their combinations to check your string!
For simple numbers like "12234" or "231231.23123" the answer can be simple.
There is a transformation law for int numbers: when string with integer transforms to int (or long) number and then, again, transforms it back to another string these strings will be equal.
In Objective C it will looks like:
NSString *numStr=#"1234",*num2Str=nil;
num2Str=[NSString stringWithFormat:#"%lld",numStr.longlongValue];
if([numStr isEqualToString: num2Str]) NSLog(#"numStr is an integer number!");
By using this transformation law we can create solution
to detect double or long numbers:
NSString *numStr=#"12134.343"
NSArray *numList=[numStr componentsSeparatedByString:#"."];
if([[NSString stringWithFormat:#"%lld", numStr.longLongValue] isEqualToString:numStr]) NSLog(#"numStr is an integer number");
else
if( numList.count==2 &&
[[NSString stringWithFormat:#"%lld",((NSString*)numList[0]).longLongValue] isEqualToString:(NSString*)numList[0]] &&
[[NSString stringWithFormat:#"%lld",((NSString*)numList[1]).longLongValue] isEqualToString:(NSString*)numList[1]] )
NSLog(#"numStr is a double number");
else
NSLog(#"numStr is not a number");
I did not copy the code above from my work code so can be some mistakes, but I think the main point is clear.
Of course this solution doesn't work with numbers like "1E100", as well it doesn't take in account size of integer and fractional part. By using the law described above you can do whatever number detection you need.
C.Johns' answer is wrong. If you use a formatter, you risk apple changing their codebase at some point and having the formatter spit out a partial result. Tom's answer is wrong too. If you use the rangeOfCharacterFromSet method and check for NSNotFound, it'll register a true if the string contains even one number. Similarly, other answers in this thread suggest using the Integer value method. That is also wrong because it will register a true if even one integer is present in the string. The OP asked for an answer that ensures the entire string is numerical. Try this:
NSCharacterSet *searchSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
Tom was right about this part. That step gives you the non-numerical string characters. But then we do this:
NSString *trimmedString = [string stringByTrimmingCharactersInSet:searchSet];
return (string.length == trimmedString.length);
Tom's inverted character set can TRIM a string. So we can use that trim method to test if any non numerals exist in the string by comparing their lengths.

Obj-C / iPhone: NSArray question

I have an array that looks like this when printed via NSLog:
{
response = "Valid";
updates = (
{
string = "test";
integer = 3493;
},
{
string = "test2";
integer = 55454;
}
);
start-index = 0;
My question is how I can loop through through the "updates" array so that I may print the values for each "string" respectively.
Should be an easy "for" loop or something?
Dave
Assuming you NSLogged data has a type of NSDictionary with name data.
NSArray *updates = [data objectForKey:#"updates"];
for (NSDictionary *update in updates) {
NSLog(#"Update: %# - %#", [update objectForKey:#"string"], [update objectForKey:#"integer"]);
}