Creating a method with parameter that accepts NSString or int - objective-c

Trying to create a method with only one parameter that may accept NSString or int.
Here's what I did so far:
-(NSString*)LocalizeNumber:(void*)TheNumber{
BOOL IsVarInt = false;
NSString * Num = "";
if(IsVarInt){
Num = [NSString stringWithFormat:#"%i",(int)TheNumber];
}else{
Num = [NSString stringWithFormat:#"%#",(__bridge NSString*)TheNumber];
}
//rest of code...
}
And this is how I call this method:
if passing int:
[self LocalizeNumber:(void*)150];
if passing NSString:
[self LocalizeNumber:#"150"];
The problem is that I still don't know how to know if the parameter "TheNumber" is NSString or int.
Thank you.

While I suggest you rethink your approach, your goal can be achieved as follows:
- (NSString *)localizeNumber:(id)number {
NSString *num = nil;
if ([number isKindOfClass:[NSNumber class]]) {
num = [number stringValue];
} else if ([number isKindOfClass:[NSString class]]) {
num = number;
} else {
// oops - bad value
}
// rest of code using num
}
Then you can call the method as follows:
NSString *someString = #"Hello";
NSString *result = [self localizeNumber:someString];
or:
int someInt = 42;
NSString *result = [self localizeNumber:#(someInt)];

You cannot tell between an object type and a plain primitive. However, you can easily tell between two object types if you pass an int passed in NSNumber wrapper, like this:
-(NSString*)LocalizeNumber:(id)TheNumber {
NSString *Num = #"";
if ([TheNumber isKindOfClass:[NSSTRING class]]) {
Num = [NSString stringWithFormat:#"%#", TheNumber];
} else if ([TheNumber isKindOfClass:[NSNumber class]]) {
Num = [NSString stringWithFormat:#"%i",[TheNumber intValue]];
}
//rest of code...
}

You could use categories to add -stringValue to NSString:
#implementation NSString (LocalizedNumber)
-(NSString*)stringValue
{
return self ;
}
#end
Then you can call:
NSString * localizedNumber = [<number or string object> stringValue]
There is no safe way to tell an int from an NSString reference.

Related

Solution for if else and NSString statement

What NSString do I put for return?
The answer I am looking for is 1 cheese OR 2 cheeses
- (NSString *) numberOfCheesesStringWithCheeseCount:(NSUInteger)cheeseCount
{
if (cheeseCount == 1) {
/* WORK HERE, ASSUMING THERE IS 1 CHEESE */
NSString *phrase = [NSString stringWithFormat:#"%ld", (long)cheeseCount];
NSLog(#"%# cheese", phrase);
} else {
/* WORK HERE, ASSUMING THERE ARE 2+ CHEESES */
NSString *phrase2 = [NSString stringWithFormat:#"%ld", (long)cheeseCount];
NSLog(#"%# cheeses", phrase2);
}
/*
(You will learn more about if/else statements in the next checkpoint.)
*/
return ;
}
How about this?
- (NSString *) numberOfCheesesStringWithCheeseCount:(NSUInteger)cheeseCount
{
NSString *result;
if (cheeseCount == 1)
{
//No real point in building this string piecewise. It will always be
//the same thing, "1 cheese".
result = #"1 cheese";
}
else
{
/* WORK HERE, ASSUMING THERE ARE 2+ CHEESES */
NSString *result = [NSString stringWithFormat:#"%ld cheeses", (long)cheeseCount];
}
NSLog(#"Result = %#", result);
return result;
}
This is not how I’d do this for real, but in the context of your exercise, this would be a good time to learn about variable scope. What you should do is declare an NSString outside of the conditional. That way, when you assign it or change it in the conditional it retains its value. Then assign the phrase inside the conditionals. After you are done, return the phrase.
- (NSString *)numberOfCheesesStringWithCheeseCount:(NSUInteger)cheeseCount
{
NSString *phrase = nil;
if (cheeseCount == 1)
{
phrase = [NSString stringWithFormat:#"%ld cheese", (long)cheeseCount];
NSLog(#"%#", phrase);
}
else
{
phrase = [NSString stringWithFormat:#"%ld cheeses", (long)cheeseCount];
NSLog(#"%#", phrase);
}
return phrase;
}
I honestly don't see the point in having the whole if else statement this can be shortened to just an if statement. I'd recommend changing to something like:
- (NSString *)numberOfCheesesStringWithCheeseCount:(NSUInteger)cheeseCount
{
// We setup our string (phrase) already with the value "1 Cheese"
NSString *phrase = #"1 Cheese";
if (cheeseCount > 1) {
// If the value of cheeseCount is greater than 1 then we update our value.
phrase = [NSString stringWithFormat:#"%ld cheeses", (long)cheeseCount];
}
// Return our value for phrase.
return phrase;
}
This code reads some much simpler then the whole if else statement.
- (NSString *)numberOfCheesesStringWithCheeseCount:(NSUInteger)cheeseCount
{
NSString *phrase = [NSString stringWithFormat:#"%ld cheeses", (long)cheeseCount];
if (cheeseCount == 1)
{
phrase = [NSString stringWithFormat:#"%ld cheese", (long)cheeseCount];
}
NSLog(#"%#", phrase);
return phrase;
}

Why does NSMutablearray keep returning null?

I am generating a random equation say like 2*3+4..... and using DDMathparser to evaluate it. Here I have a class method which is supposed to return a random equation(stored inside a mutable array) only if it evaluates to a integer.
however it keeps returning Null and i can't figure out why. Please help me out.!
#import "Equation.h"
#import "DDMathParser.h"
#implementation Equation
-(NSMutableArray*)randEquation{
NSMutableArray* usableEquation=[[NSMutableArray alloc]init];
while(1){
NSArray *nums = #[#"1", #"2", #"3", #"4", #"5",#"6",#"7",#"8",#"9"];
unsigned index1=arc4random()%9;
NSString* num = [NSString stringWithFormat:#"%#", [nums objectAtIndex:index1]];
NSArray *symbols = #[#"+", #"-", #"*", #"/"];
unsigned index=arc4random()%4;
NSString* symb = [NSString stringWithFormat:#"%#", [symbols objectAtIndex:index]];
NSMutableArray *arrayOfSymbolsAndNumbers = [[NSMutableArray alloc] init];
for( int i=0;i<=10;i++){
if (i%2==0) {
[arrayOfSymbolsAndNumbers addObject:num];
}
else{
[arrayOfSymbolsAndNumbers addObject:symb];
}
}
NSMutableString *stringOfSymbolsAndNumbers=[[NSMutableString alloc]init];
for (NSObject * obj in arrayOfSymbolsAndNumbers)
{
[stringOfSymbolsAndNumbers appendString:[obj description]];
}
usableEquation=arrayOfSymbolsAndNumbers;
NSNumber *result=[stringOfSymbolsAndNumbers numberByEvaluatingString];
float resultFloat = [result floatValue];
float checker=resultFloat;
if (floor(checker)==checker) {
break;
}
else{
continue;
}
}
return usableEquation;
}
#end
NSLog(#"The content of array is%#",[equation randEquation]);
Based on your code, for this log to output The content of array is(null) means that equation is nil. Your randEquation (while not efficient) looks ok, the problem is that you haven't created the equation instance when you run the log statement.

Part of NSString to NSNumber

I need to input x and y co-ordinates into a custom object, the input is with the format "x,y"
I am currently storing the input as an NSString and need to get the integers out of it and into separate NSNumbers. If there is another way to store the input that would be easier, please explain.
I need to store x and y as separate NSNumbers, this also this needs to account for if x and y are 2 digits. i.e. "23,4"
can anyone help?
Use -[NSString componentsSeparatedByString:]
NSArray *numericComponents = [string componentsSeparatedByString:#","];
NSArray *numbers = [numericComponents map:^id(NSString *object) {
return #([object integerValue]);
}];
map here is simply a category method that I've added to NSArray:
#implementation NSArray (JRAdditions)
- (NSArray *)map:(id(^)(id))block {
if([self count] == 0 || block == nil) return self;
NSMutableArray *mapped = [NSMutableArray new];
NSArray *copy = [self copy];
for(id obj in copy) {
id mappedObject = block(obj);
if(mappedObject) {
[mapped addObject:mappedObject];
}
}
return [mapped copy];
}
#end
NSString *str=#"23,4";
NSArray *array=[str componentsSeparatedByString:#","];
NSNumber *xNum=#([array[0] integerValue]);
NSNumber *yNum=#([array[1] integerValue]);
To check if they are two digits :
if ([xNum integerValue]>9 && [xNum integerValue]<100) {
NSLog(#"x is 2 digits");
}
else{
}
if([yNum integerValue]>9 && [yNum integerValue]<100) {
NSLog(#"y is 2 digits");
}
else{
}

Objective-C NSMutableArray

I have filled a NSMutableArray with integer and string values from my database.
The problem is that many values were inserted more than once.
Using the following code I remove duplicate objects
for (id object in originalArray) {
if (![singleArray containsObject:object]) {
[singleArray addObject:object];
}
}
Bus this works only if the objects are exactly the same between them.
Is there a way to remove duplicates based on the integer value?
EDIT (from an OP's comment on a deleted answer)
I have some objects containing int and NSString. For example #"John 13", #"Mary 25", #"Luke 25", #"Joan 13". The NSMutableArray will contain all four names and duplicates of 13, 25. I want to remove the duplicates leaving 13 and 25 only once in the array. I do not care which names will be removed. Care only for the integer values to use them later.
If your elements are all NSNumber objects:
for (int i=0;i<array.count;i++) {
for (int j=i+1;j<array.count;j++) {
if ([array[i] isEqualToNumber:array[j]]) {
[array removeObjectAtIndex:j--];
}
}
}
Or if all objects are either integer NSNumbers or NSStrings containing integer values:
for (int i=0;i<array.count;i++) {
for (int j=i+1;j<array.count;j++) {
if ([array[i] intValue] == [array[j] intValue]) {
[array removeObjectAtIndex:j--];
}
}
}
Try this:
// singleArray is initially empty
for (id object in originalArray)
{
BOOL contains= YES;
for( id single in singleArray)
{
if( [single integerValue]==[object integerValue] )
{
contains= NO;
break;
}
}
if(contains)
{
[singleArray addObject: object];
}
}
no test, tell me if it does not work. assuming objects in the array are string and format is "WORD NUMBER"
Boolean myEqual(const void *value1, const void *value2) {
NSString *str1 = (__bridge NSString *)(value1);
NSString *str2 = (__bridge NSString *)(value2);
NSArray *arr1 = [str1 componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSArray *arr2 = [str2 componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [[arr1 lastObject] isEqual:[arr2 lastObject]];
}
CFHashCode myHash(const void *value) {
NSString *str1 = (__bridge NSString *)(value);
NSArray *arr1 = [str1 componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [[arr1 lastObject] hash];
}
NSMutableArray *array = // your array;
CFSetCallBacks callBacks = kCFTypeSetCallBacks;
callBacks.equal = myEqual;
callBacks.hash = myHash;
CFMutableSetRef set = CFSetCreateMutable(NULL, [array count], &callBacks);
for (id obj in [array copy]) { // copy so can modify the original array
if (CFSetContainsValue(set, (__bridge const void *)(obj))) {
[array removeObject:obj];
} else {
CFSetAddValue(set, (__bridge const void *)(obj));
}
}

Objective-C Category Question

I've created a custom sorting by creating a new category for the NSString class. Below is my code.
#implementation NSString (Support)
- (NSComparisonResult)sortByPoint:(NSString *)otherString {
int first = [self calculateWordValue:self];
int second = [self calculateWordValue:otherString];
if (first > second) {
return NSOrderedAscending;
}
else if (first < second) {
return NSOrderedDescending;
}
return NSOrderedSame;
}
- (int)calculateWordValue:(NSString *)word {
int totalValue = 0;
NSString *pointPath = [[NSBundle mainBundle] pathForResource:#"pointvalues"ofType:#"plist"];
NSDictionary *pointDictionary = [[NSDictionary alloc] initWithContentsOfFile:pointPath];
for (int index = 0; index < [word length]; index++) {
char currentChar = [word characterAtIndex:index];
NSString *individual = [[NSString alloc] initWithFormat:#"%c",currentChar];
individual = [individual uppercaseString];
NSArray *numbersForKey = [pointDictionary objectForKey:individual];
NSNumber *num = [numbersForKey objectAtIndex:0];
totalValue += [num intValue];
// cleanup
individual = nil;
numbersForKey = nil;
num = nil;
}
return totalValue;
}
#end
My question is whether I create a point dictionary to determine the point value associated with each character in the alphabet based on a plist. Then in my view controller, I call
NSArray *sorted = [words sortedArrayUsingSelector:#selector(sortByPoint:)];
to sort my table of words by their point values. However, creating a new dictionary each time the -sortByPoint: method is called is extremely inefficient. Is there a way to create the pointDictionary beforehand and use it for each subsequent call in the -calculateWordValue:?
This is a job for the static keyword. If you do this:
static NSDictionary *pointDictionary = nil
if (pointDictionary==nil) {
NSString *pointPath = [[NSBundle mainBundle] pathForResource:#"pointvalues" ofType:#"plist"];
pointDictionary = [[NSDictionary alloc] initWithContentsOfFile:pointPath];
}
pointDictionary will be persistent for the lifetime of your app.
One other optimization is to build a cache of scores by using this against each of your words:
[dict setObject:[NSNumber numberWithInt:[word calculateWordValue:word]] forKey:word];
Then use the keysSortedByValueUsingSelector: method to extract your list of words (note the selector chould be compare:, since the objects being compared are the NSNumbers).
Finally, the word argument on your method is redundant. Use self instead:
-(int)calculateWordValue {
...
for (int index = 0; index < [self length]; index++)
{
char currentChar = [self characterAtIndex:index];
...
}
...
}
Change your sortByPoint:(NSString *) otherString method to take the dictionary as a parameter, and pass it your pre-created dictionary.
sortByPoint:(NSString *)otherString withDictionary:(NSDictionary *)pointDictionary
EDIT: Won't work because of usage in sortedArrayWithSelector. Apologies. Instead, you may be better off creating a wrapper class for your point dictionary as a singleton which you then obtain a reference to each time your sort function runs.
In calculateWordValue:
NSDictionary *pointDictionary = [[DictWrapper sharedInstance] dictionary];
DictWrapper has an NSDictionary as a property, and a class method sharedInstance (to return the singleton. You have to set that dictionary and pre-initialize it before you do you first sorting.