I have a function as follows:
-(int)ladderCalc:(NSArray*)amounts percentages:(NSArray*)percentages amount:(int)amount
{
// Do some stuff
return foo;
}
I have declared like this in the header file:
-(int)ladderCalc:(NSArray*)amounts percentages:(NSArray*)percentages amount:(int)amount;
But I am getting an error "implicit declaration of function is invalid in c99" when I try to use the int value returned elsewhere in the same file. Am I not declaring the function correctly?
UPDATE
I am realizing that I am not declaring this in the standardized way, I changed my declaration to MarkGranoff's recommendation (see the changes above) but I am still getting it as a warning this time.
Here is the context of how I am calling this function:
-(int)fooTotal: (int)amount
{
int totalFee = 0;
// Declare arguments
NSArray *percentages = [[NSArray alloc] initWithObjects:firstValue, secondValue, thirdValue, fourthValue, fifthValue, nil];
NSArray *amounts = [[NSArray alloc] initWithObjects:sixthValue, seventhValue, eigthValue, ninthValue, nil];
totalFee = ladderCalc(amounts,percentages,amount);
return totalFee;
}
So, I am still getting a warning even though this seems to make sense as far as Obj-C style is concerned.
I am pretty sure I am not calling this function correctly, I am getting an unrecognized symbol error when I compile the project.
Undefined symbols for architecture i386:
"_ladderCalc", referenced from:
-[FeeCalcLibrary getMFModelTotal:] in FeeCalcLibrary-A83D2A7637F57664.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Try this instead:
-(int)ladderCalc:(NSArray*)amounts percentages:(NSArray*)percentages amount:(int)amount;
and change the signature of the implementation to match. Then you have arguments with names you can reference in the code of the method. Namely: amounts, percentages, and amount.
As #MarkGranoff says.
Objective-C has it's arguments interspersed in the method name.
For the method declaration:
-(int)ladderCalcWithAmounts:(NSArray*)amounts percentages:(NSArray*)percentages amount:(int)amount;
the method name is (the colons are part of the name):
ladderCalc:percentages:amount:
Interspersed in the method name the arguments are:
(NSArray*)amounts
(NSArray*)percentages
(int)amount;
This improved readability over a "C" function call which might be:
int ladderCalcPercentagesAmount(NSArray *amounts, NSArray *percentages, amount);
Technically, Objective-C does not have named parameters, rather interspersed parameters. Named parameters tends to imply that position is not important just the associated names, an example are Python's named parameters.
Related
It seems that the default behavior in XCode is to silently allow redefinition of local variables if they are declared in a deeper scope, but throw an error or warning otherwise. For example, XCode produces an error for "Redefinition of 'var'" if it is redefined in the exact same scope:
- (void) doStuff
{
NSString *var = #"Hello World";
NSString *var = #"Goodbye"; // Error on this line
}
Similarly, if I have an ivar called 'var', and I try to re-declare 'var' in a local method, XCode will produce a warning for "Local declaration of 'var' hides instance variable" when I try to use it:
//MyClass.h
...
#interface MyClass : NSObject
{
NSString *var;
}
...
//MyClass.m
...
- (void) doStuff
{
NSString *var = #"Hello World";
NSLog(#"%#",var); // Warning thrown on this line
}
So far this is what I would expect. However, if var is redefined in a deeper scope, such as an if block or for loop, XCode allows it, and the outer declaration is silently ignored:
NSString *var = #"Hello World";
if (TRUE)
{
int var = 0;
NSLog(#"%d",var); //prints '0', No errors or warnings
}
NSLog(#"%#",var); //prints 'Hello World'
Why is the last example silently allowed, but the other two are caught? Is there some option or flag I can toggle in XCode so that an error or warning would also be created in the last example? If XCode won't catch it for me, is there some code I could write to make sure variables are never redefined? Or is it just my responsibility to make sure I'm not re-using my variable names?
In the build settings (Xcode 5 & 6, at least) you can set a warning for Hidden Local Variables to YES.
The last example is behavior that Objective-C inherits from standard C. A variable's scope is determined by the bracing level. It's been that way since the earliest days for C. It's called variable shadowing, and it's actually pretty useful in ensuring that code keeps working even in the face of API changes in system libraries.
As far as why it's allowed, but the earlier examples aren't, that's a consequence of how Objective-C implements instance variables. The instance variables are essentially treated as local variables of each of the class's methods. So when you declare a local variable in a function that shadows an instance variable, it gets flagged as an error. Basically the first and second cases are treated as equivalent.
To get a warning for these cases, set the LLVM warning option Hidden Local variables to Yes.
I have this code:
- (NSString *) calculate: (uint) position {
static NSArray * localArray = [NSArray arrayWithArray: self.container.objects ];
// some un related code
return obj;
}
The compiler complains saying: "Initializer element is not a compile-time constant". It happened when I added "static" to localArray. But why?
Because [NSArray arrayWithArray: self.container.objects ] isn't a compile-time constant, it's an expression that must be evaluated at runtime. In C and Objective-C, static variables inside functions must be initialized with compile-time constants, whereas C++ and Objective-C++ are more lenient and allow non-compile-time constants.
Either compile your code as Objective-C++, or refactor it into something like this:
static NSArray *localArray = nil;
if (localArray == nil)
localArray = [NSArray arrayWithArray: self.container.objects ];
Which is fairly similar to the code that the compiler would generate under the hood for a static variable initialized with a non-compile-time constant anyways (in actuality, it would use a second global flag indicating if the value was initialized, rather than using a sentinel value like nil here; in this case, we are assuming that localArray will never be nil). You can check out your compiler's disassembly for that if you want.
You just can't initialize a static variable with a non-static value that will be known/modified at runtime.
You should probably do something like this:
static NSArray *localArray = nil;
localArray = ...;
The first instruction will be executed once in your app lifecycle.
The second instruction will be executed every time the calculate: method is called.
Nevertheless, pay attention to the fact that using static variables can lead to buggy behaviors if not done properly so if you feel uneasy with these, you should probably not use them.
Just when I think I'm getting comfortable with Objective-c the mentioned symbols totally throw me down a rabbit hole...
** a double pointer??
& what sort of things can I do with &reference, is a #property? a full on object? weird pointer razzledazzle?
± I see both a + or a - before method declarations; I've seen Java annotate some datatype declarations by manually typing the + and the magic of compiling in Eclipse would change them to a -
I'm likely asking repetitious questions and/or way outta the ballpark on my guesses; thanks for answers/edits.
You're getting into the C portion that objective-c is built on top of.
** is a pointer to a pointer. Since functions in C take arguments by value, it means you can't change the value of the argument in that function. But, by providing a level of indirection and passing a pointer to the pointer, you can change the value.
& means it's a reference. If an argument takes a ** and you have a * variable, pass a reference to it.
Foo *foo;
[self changeFoo: &foo];
- (BOOL)changeFoo: (Foo **)foo
{
// dereference the double pointer and assign a val = alloc init returns a *
*foo = [[Foo alloc] init];
return YES;
}
A common usage in objective-c / cocoa is NSError. It's essentially an out argument.
NSError *err;
BOOL success = [self doSomething:#"Foo" error:&err];
- (BOOL)doSomething:(NSString*)withData error:(NSError**)error
{
}
As you might know, a pointer points to the address of an object and is the way you reference an object. A double pointer is sometimes used in Objective-C, mainly for returning NSErrors, where you want to get back the address, i.e. a pointer, to an error object (NSError) if an error occurred, thus you pass in a pointer assigned to null and the caller can change that pointer so that it points to the address of another pointer which in turn points to an NSError object.
The ampersand (&) is mostly used by the lower level C APIs, e.g. Core Graphics. They are used to reference things, like the current context. As long as most of your code uses square brackets around its method calls you won't see these very often.
Using a + or a - before a method declarations is used to differentiate between class (+) and instance (-) methods. A class methods is called on the class itself (such as alloc), while a instance method is called on an instance of that object (such as init).
- and + before a method declaration designate an instance method and a static class method. To use an instance method you have to create an object of your class before you can call its method, a static method can be called directly from a class type
I am trying to return a subset of my NSMutableArray (MessageArray) with the following code. MessageArray contains an NSDictionary, one of the keys being FriendStatus. I get a strange error which I know is a DUH syntax issue. "error. void value not ignored as it ought to be".
-(NSMutableArray*)FriendMessageArray {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"FriendStatus == 1"];
NSMutableArray *filtered = [MessageArray filterUsingPredicate:predicate];
return filtered;
}
"void value not ignored as it ought to be" means that a method with a signature that starts with (void) is being used to assign a value or object to a variable. What's the signature for filterUsingPredicate? does it start with (void) ?
I'm assuming "MessageArray" is an instance variable (never name instance variables this way; you should have a property called -messages and access it with self.messages). I'l further assume that it is an NSMutableArray or else you'd be getting warnings from the compiler.
NSMutableArray -filterUsingPredicate: modifies the array itself, returning void. The method you want is -filteredArrayUsingPredicate: which returns an array. The fact that the former is a verb and the latter is a noun indicates this fact even without reading the docs. Cocoa naming is extremely consistent, which is why I mention it in the first paragraph. Pay attention to the names and you will have far fewer bugs.
I am trying to write a function which returns a string created from two input strings;
but when I try the function declaration
NSString Do_Something(NSString str1, NSString str2)
{
}
the compiler gets sick. (Worked fine for a different function with int arguments.)
If I change the input arguments to pointers to strings, in also gets sick.
So how do I pass Objective-C objects into a function?
All Objective-C objects being passed to functions must be pointers. Rewriting it like this will fix your compiler error:
NSString *Do_Something(NSString *str1, NSString *str2) { }
Also, please keep in mind that this is a (C-style) function and not an instance method written on an Objective-C object. If you wanted this to actually be a method on an object it would probably look something like this:
NSString *doSomethingWithString1:(NSString *)str1 string2:(NSString *)str2 { }
I say "probably" because you can name it however you want.
Functions are perfectly fine in Objective-C (and in fact earn some of the language's benefits).
See my answer to C function always returns zero to Objective C, where someone was trying what you are and had a problem with the compiler assuming return type. The structure that I set up there is important when you are using functions, just like when you are using objects and methods. Be sure to get your headers right.
To be pedantic, you're using a function definition of:
NSString *DoSomething(NSString *str1, NSString *str2) {
// Drop the _ in the name for style reasons
}
And you should be declaring it in a .h file like so:
NSString *DoSomething(NSString *str1, NSString *str2);
Just like C.
that doesn't work for me. i've just declared in the .h:
NSString *myFunction(NSDecimal *value);
and i type in the .m:
NSString *myFunction(NSDecimal *value){
//code
}
but always i get an error saying expected '(' before '*' token
now is fixed. for some reason... sorry.