NSInteger used in calculation, warning 'local declaration of '' hides instance' - objective-c

I am a beginner. And I was trying to transform arabic numbers to ordinal numbers by having the following class.
num is NSInteger, while, during the calculation, the warning pop out "local declaration of '' hides instance"
#import "ordinalNumberFormatter.h"
#implementation ordinalNumberFormatter
- (NSString*)ordinalNumberFormatter:(NSInteger)num
{
NSString *ending;
int ones = num % 10; //Warning came out
int tens = floor(num / 10); //Warning came out
tens = tens % 10;
if(tens == 1){
ending = #"th";
}else {
switch (ones) {
case 1:
ending = #"st";
break;
case 2:
ending = #"nd";
break;
case 3:
ending = #"rd";
break;
default:
ending = #"th";
break;
}
}
return [NSString stringWithFormat:#"%d%#", (int)num, ending]; //Warning came out
}
#end

Do you have a class variable called "num" as well? The warning is just saying that you're using the local variable "num" defined in
- (NSString*)ordinalNumberFormatter:(NSInteger)num
And you might instead want to use the "num" defined as the class variable. Maybe change the above "num" to another name and use that name in the method. That'll clear it all up

Related

Is there a way to get the class prefix (at runtime) of a given project?

I want to construct a method which returns as a string the class prefix of the module it is operating in.
For example, if I have project with classes named XYZMessage, XYZBusiness, XYZTransaction... I want a function to return the string XYZ.
I have an implementation which uses the name of the appDelegate (The first capital letters except the last) to do this, but I would like a better way. I would hope that Xcode defines a macro with this value or there's a key in the plist or something more concrete. I don't want to #define CLASS_PREFIX #"XYZ" or anything hard-coded.
EDIT: The Why
The situation is I have a server who provides me the type (i.e. which class to construct) along with the information.
{
"type" : "merchant",
"data" : {
"name" : "Super cool pizza",
"location" : {
"lat" : "123.000",
"lon" : "23.0000"
}
}
I have a class AXQMerchant which will take this (data) payload as it's initializer (unpack the keys/values, match the types to its properties, build sub-objects, etc.)
What I'm trying to avoid is this structure in my API handler:
NSString* objectType = ...; //server provided
NSString* classToConstruct; //our local type
if ([objectType isEqualToString:#"transaction"]) {
classToConstruct = #"AXQTransaction";
} else if ([objectType isEqualToString:#"store"]) {
classToConstruct = #"AXQStore";
... //a series of else-if blocks
} else if ([objectType isEqualToString:#"merchant"]) {
classToConstruct = #"AXQMerchant";
}
id object = [[NSClassFromString(classToConstruct) alloc] initWithPayload:...];
//now do something with object
This section will easily grow unwieldy when my type list is >20 types. What I want to write is:
classToConstruct = [classPrefix() stringByAppendingString:[objectType capitalizedString]];
id object = [[NSClassFromString(classToConstruct) alloc] initWithPayload:...];
For those who are curious; my current implementation is...
str = NSStringFromClass([[UIApplication sharedApplication].delegate class]); //could be [self class], instead...
for (NSUInteger i = 0; i < str.length; i++) {
unichar c = [str characterAtIndex:i];
if (c < 'A' || c > 'Z') { //if c is not a capital we're at prefix end (+1 extra)
return [str substringWithRange:NSMakeRange(0, i - 1)];
}
}
return nil;
This is dispatch_once()'d so I only calculate it when the app is opened the first time.
The project's class prefix seems to be available to an Xcode template file via the replacement string ___VARIABLE_classPrefix:identifier___, so one possibilty would be to create either a custom .pch or header file template. The header can then expose the prefix as either a macro or an NSString.
Use NSStringFromClass to get the class name and then return the first three characters of the string.
NSString *mystr = NSStringFromClass([instance class]);
return [mystr substringToIndex:3];

Applying an IF STATEMENT to my word generator

When I try adding an "if" statement to my word generator I get an error stating "Expected Expression". If I take the if statement out, it works fine but what I want to do is have several word generators and depending on the value of my variable "variable" determine which word generator is accessed.
Example: If "variable" is equal to 1 then the first word generator is accessed. If "variable is equal to 2 then the second word generator is accessed
Below is the code from my implementation file.
#import "ViewController2.h"
#import "ViewController.h"
#import "ViewController3.h"
#interface ViewController2 ()
#end
#implementation ViewController2
-(IBAction)random {
if (int variable = 3) {
int text = rand() %3;
switch (text) {
case 0:
introLabel.text = #"Test 1";
break;
case 1:
introLabel.text = #"Test 2";
break;
case 2:
introLabel.text = #"Test 3";
break;
default:
break;
}
}
}
-(IBAction)backButton:(id)sender {
ViewController *viewController2 = [[ViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:viewController2 animated:YES];
}
-(IBAction)moreButton:(id)sender {
ViewController3 *viewController2 = [[ViewController3 alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:viewController2 animated:YES];
}
Thanks in advance for any help.
Your question is unclear but I think you are talking about the line:
if (int variable = 3) {
That is invalid Objective-C syntax. Perhaps you want:
if (variable == 3) {
This assumes you have an instance variable named variable (which is a terrible name).
So your random method becomes something like:
-(IBAction)random {
if (variable == 1) {
int text = rand() %3;
switch (text) {
case 0:
introLabel.text = #"Test 1";
break;
case 1:
introLabel.text = #"Test 2";
break;
case 2:
introLabel.text = #"Test 3";
break;
default:
break;
}
} else if (variable == 2) {
// process the 2nd word generator here
} else if (variable == 3) {
// process the 3rd word generator here
}
}
Again, you need to add an instance variable named variable and you set that value somewhere appropriate. Or variable can be another local variable assigned the value of rand() like you do with the text variable.

the best way to implement readable switch case with strings in objective-c?

In other dynamic languages like ruby, javascript etc. you can do simply this:
switch(someString) {
case "foo":
//do something;
break;
case "bar":
// do something else;
break;
default:
// do something by default;
}
In objective-c, because it's derived very colsely from c language, you can't do that. My best practice for this is:
#import "CaseDemo.h"
#define foo 1
#define bar 2
static NSMutableDictionary * cases;
#implementation CaseDemo
- (id)init
{
self = [super init];
if (self != nil) {
if (cases == nil) {
// this dict can be defined as a class variable
cases = [[NSMutableDictionary alloc] initWithCapacity:2];
[cases setObject:[NSNumber numberWithInt:foo] forKey:#"foo"];
[cases setObject:[NSNumber numberWithInt:bar] forKey:#"bar"];
}
}
return self;
}
- (void) switchFooBar:(NSString *) param {
switch([[cases objectForKey:param] intValue]) {
case foo:
NSLog(#"its foo");
break;
case bar:
NSLog(#"its bar");
break;
default:
NSLog(#"its default");
break;
}
}
#end
It's seems to be ok, but #define makes foo and bar like a reserved word, and I can't use in my code. If I replace define constants with class constants, this problem is fixed, because in other classes I must use MyClassName before the constant name. But how can I minimize the object allocation for this simple task? Someone have a "better practice" for this?
EDIT:
The code below is what I wanted to do, but it's a little bit unconfortable to get the values of the enum or #define. Because I created an application what have just an input where I can write the string to get that hash and go back to xcode and set the values for the enums. So my problem is I can't do that in runtime time, because of the main behavour of switch case statement... Or if I do that with that NSDictionary way -> its have a lot of overhead compared with this solution.
#import "CaseDemo.h"
typedef enum {
foo = 1033772579,
bar = -907719821
} FooBar;
unsigned int APHash(NSString* s)
{
const char* str = [s UTF8String];
unsigned int len = [s length];
unsigned int hash = 0xAAAAAAAA;
unsigned int i = 0;
for(i = 0; i < len; str++, i++)
{
hash ^= ((i & 1) == 0) ? ( (hash << 7) ^ (*str) * (hash >> 3)) :
(~((hash << 11) + ((*str) ^ (hash >> 5))));
}
return hash;
}
#implementation CaseDemo
- (void) switchFooBar:(NSString *) param {
switch(APHash(param)) {
case foo:
NSLog(#"its foo");
break;
case bar:
NSLog(#"its bar");
break;
default:
NSLog(#"its default");
break;
}
}
#end
NOTE: the hash function can defined elsewhere in common namespace to use it anywhere, typically I create a Utils.h or Common.h for this kind of stuff.
NOTE2: In "real word" we need to use some cryptographic hashing function, but now I used the algorithm by Arash Partow to keep the example simple.
So, my final question: Is there a way to evaluate these values with the preprocessor somehow? I think no, but maybe? :-)
Something like:
// !!!!!! I know this code is not working, I don't want comments about "this is wrong" !!!!
// I want a solution to invoke method with preprocessor, or something like that.
typedef enum {
foo = APHash(#"foo"),
bar = APHash(#"bar")
} FooBar;
UPDATE: I found a "maybe solution" but it seems to be work with g++ 4.6> only. generalized constant expressions may be do it for me. But I'm still testing...
typedef enum {
foo,
bar
} FooBar;
- (void) switchFooBar:(NSString *) param {
switch([[cases objectForKey:param] intValue]) {
case foo:
NSLog(#"its foo");
break;
case bar:
NSLog(#"its bar");
break;
default:
NSLog(#"its default");
break;
}
}
NSString * extension = [fileName pathExtension];
NSString * directory = nil;
NSUInteger index = [#[#"txt",#"png",#"caf",#"mp4"] indexOfObjectPassingTest:^
BOOL(id obj, NSUInteger idx, BOOL *stop)
{
return [obj isEqualToString:extension];
}];
switch (index)
{
case 0:
directory = #"texts/";
break;
case 1:
directory = #"images/";
break;
case 2:
directory = #"sounds/";
break;
case 3:
directory = #"videos/";
break;
default:
#throw [NSException exceptionWithName:#"unkonwnFileFormat"
reason:[NSString stringWithFormat:#"zip file contain nknown file format: %#",fileName]
userInfo:nil];
break;
}
The technique is extracted from production code and modified to use colors for this example. The premise is that a string comes in with the text name of a color from some external feed. This inbound color name is matched against known Crayola color names in the system. If the new color name matches any known Crayola color name strings, the numeric value for HTML hex code equivalent of that Crayola color name is returned.
First use http://www.unit-conversion.info/texttools/crc/ and put all of your known Crayola color names through it to get numerical equivalents. These will be used in the case statements. Then put those values into an enumerated for cleanliness (e.g. LivingColors below). These numbers become equivalent to the actual color name string.
Then at run time the variable text is put through the same function, but internal to your code, to generate the same kind of numeric constant. If the numeric constant from the code matches the statically generated constant, then the text strings that they represent are exactly equal.
The internal code function is crc32() found in zlib.h. This generates a unique number based upon the text put through it just like the web page converter above. The unique number from crc32() can then be used in a common C switch() statement to match against the known colors which were pre-processed into numbers into the enumerated.
To use the native system function crc32() to generate CRC32B values, include the /usr/lib/libz.1.dylib in your project for linking. Be sure to include or #import <zlib.h> in your source that references crc32()
Implement an Objective C category on NSString to make the native NSString class understand the crc32: and htmlColor: messages.
Finally, read/get the name of the color into an NSString object, then send the string the htmlColor: message, it switches to match the 'strings' and returns the HTML hex equivalent value for a Crayola color name.
#import <zlib.h>
#define typedefEnum( enumName ) typedef enum enumName enumName; enum enumName
/**
#see Crayola Web Colors https://www.w3schools.com/colors/colors_crayola.asp
#see CRC32B value generator for static case strings http://www.unit-conversion.info/texttools/crc/ or http://www.md5calc.com
*/
#define typedefEnum( enumName ) typedef enum enumName enumName; enum enumName
typedefEnum( LivingColors ) {
kRedColor = 0xc22c196f, // "Red" is 0xED0A3F in HTML
kBlueberryColor = 0xfbefa670, // "Blueberry" is 0x4F86F7 in HTML
kLightChromeGreenColor = 0x44b77242, // "Light Chrome Green" is 0xBEE64B in HTML
kPermanentGeraniumLakeColor = 0xecc4f3e4, // "Permanent Geranium Lake" is 0xE12C2C in HTML
kIlluminatingEmeraldColor = 0x4828d5f2, // "Illuminating Emerald" is 0x319177 in HTML
kWildWatermelonColor = 0x1a17c629, // "Wild Watermelon" is 0xFD5B78 in HTML
kWashTheDogColor = 0xea9fcbe6, // "Wash the Dog" is 0xFED85D in HTML
kNilColor = 0xDEADBEEF // could use '0' but what fun is that?
};
// generates the CRC32B, same used to check each ethernet packet on the network you receive so it’s fast
- (NSUInteger) crc32 {
NSUInteger theResult;
theResult = (NSUInteger)crc32( 0L,
(const unsigned char *) [self UTF8String],
(short)self.length);
return theResult;
}
/// #return the HTML hex value for a recognized color name string.
- (NSUInteger) htmlColor {
NSUInteger theResult = 0x0;
LivingColors theColorInLivingColor = kNilColor;
theColorInLivingColor = (LivingColors) [self crc32];
// return the HTML value for a known color by effectively switching on a string.
switch ( theColorInLivingColor ) {
case kRedColor : {
theResult = 0xED0A3F;
}
break;
case kBlueberryColor : {
theResult = 0x4F86F7;
}
break;
case kLightChromeGreenColor : {
theResult = 0xBEE64B;
}
break;
case kPermanentGeraniumLakeColor : {
theResult = 0xE12C2C;
}
break;
case kIlluminatingEmeraldColor : {
theResult = 0x319177;
}
break;
case kWildWatermelonColor : {
theResult = 0xFD5B78;
}
break;
case kWashTheDogColor : {
theResult = 0xFED85D;
}
break;
case kNilColor :
default : {
theResult = 0x0;
}
break;
}
return theResult;
}
For the example an Objective C Category was made to add the two methods the existing Cocoa class NSString, rather than subclass it.
The end result is that an NSString object appears to have the ability to natively get a CRC32B value of itself (very handy beyond this example) and can essentially switch() on the color’s name string that possibly came in from the user, a text file, etc. to identify a match much faster than any text string comparison can occur.
Fast, efficient, and reliable, this approach can easily be adapted to any kind of variable text matching to static known value text. Bear in mind that CRC32B checksums are generated by bitwise operations and the C switch statement use bitwise operations optimized at compile time. Remember this is speedy because CRC32B is the highly optimized function used to check each ethernet packet your Mac/iPhone/iPad receives... even when you download multi-gigabyte files like macOS Sierra.

Multiple methods warning

I'm currently learning Objective C and in the process I've made the silly little program below. The program compiles fine - however I get the warning "multiple methods named '-setName:' found".
I've only interfaced and implemented the method once.
What does this warning mean, and how do I correct it?
#import <Foundation/Foundation.h>
// these are the three yoga-exercises we can perform
typedef enum {
kCobra,
kUniversal,
kDog
} ExerciseName;
// translating our variables into human
NSString *nameExercise (ExerciseName nameExercise)
{
switch (nameExercise) {
case kCobra:
return #"Cobra Pose";
break;
case kUniversal:
return #"Universal Stretch";
break;
case kDog:
return #"Dog Pose";
break;
}
return #"no clue!";
} // nameExercise
#interface Exercise : NSObject
{
ExerciseName name;
}
-(void) setName: (ExerciseName) name;
-(void) exerciseDo;
#end
#implementation Exercise
-(void) setName: (ExerciseName) n {
name = n;
} // setName
-(void) exerciseDo {
NSLog(#"Exercise: %#",
nameExercise(name));
}
#end
void executeExercises(id exercises[], int count) {
int i;
for(i=0; i<count; i++) {
id exercise = exercises[i];
[exercise exerciseDo];
}
}
int main (int argc, const char * argv[]) {
id exercises[1];
exercises[0] = [Exercise new]; // initiating an object of class Exercise
[exercises[0] setName:kDog];
executeExercises(exercises, 1);
return 0;
} //main
the meaning of the message is that there are multiple selectors with the name setName: in the translation (that is, it is declared in at least on other place among all included headers). the compiler may choose the wrong selector (which can introduce undefined behavior).
you can typically correct the problem using one (or more) of the following approaches:
1) rename the method to a unique name: e.g. setExerciseName may be ok, if not used in other translations.
2) match the signature of the other selector. e.g. setName:(NSString *)name
3) use type safety:
Exercise * ex = [Exercise new];
[ex setName:kCobra];
4) cast the variable to the type: [(Exercise*)exercise setName:kCobra];
5) restore the type with a new variable: Exercise * ex = exercise;
since you have declared the var as an id, you have erased the type, and it means that the object may respond any visible selector. in general, you should not erase the type in this manner, except when truly necessary.
the best approach i see is a combination of 1 and 3:
[ex setExerciseName:kCobra];

Odd compiler error when using Obj-C objects in a switch statement

I get a compiler error when using an Objective-C object within a switch statement:
switch (myConstant)
{
case 0:
UIViewController *myController = [[[UIViewController alloc] init] autorelease];
[self.navigationController pushViewController:myViewController animated:YES];
break;
case 1:
// stuff
break;
default:
break;
}
The error states:
Expected expression before 'UIViewController'
'myViewController' undeclared (first use in this function)
I understand that the second error is a direct result of the first error, but what I don't understand is why I get the 'expected expression' error in the first place...
If I put a ; at the end of the case 0: line, then it will compile, but I shouldn't have to do this, no?
This will also fail to compile, with the same error:
switch (0)
{
case 0:
int a = 0;
break;
default:
break;
}
However, if I declare the int a; outside of the switch block, then a = 0; compiles fine.
I thought I understood switch statements - clearly I don't. Could someone please explain?
Just add {} within the case if you declare a new variable. The case part of a switch statement is not a correct scope to declare variables in C.
case 0:
{
int a = 0;
break;
}
...