How would I define a mix of Objective-C method parameters? - objective-c

I would like to do something like this in my program:
[obj list error:&error];
But when I try to define the prototype/method, I get compile errors.
I've tried the following definitions:
-(void)list error:(NSError **)error;
-(void)list:() error:(NSError **)error;
nothing seems to work.

Why is the space between list and error in the method signature. If this is the prototype -
-(void) list_error:(NSError **)error;
list_error expects a pointers address to be passed to it. So, this should work.
[obj list_error:&ptr] ; // Assuming ptr is of type NSError* and is initialized.
I think, you are getting confused when to send more than one parameter to a method. Its simple. Method signature should be -
- ( return_type ) splitOne:(type) arg1 splitTwo:(type) arg2 ;
- indicates instance method. Same is the case for class method too but substitued a + instead of -. And so on the method name can be splitted.
Taking an example of fraction, to set a fraction it needs both numerator and denominator. So,
-(void) setNumerator: (int) n setDenominator: (int) d ;
And to call it -
[ obj setNumerator:10 setDenominator:20 ] ;
What is the need to split the method name ?
Normally, in C this function prototype would be -
void setFraction( int a, int b );
But when seeing the prototype, it isn't obvious whether a is numerator or denominator and is the same with b. That is the reason, why in Objective-C method name may be splitted into parts. In the above example of Objective-C, both the setNumerator and setDenominator forms the method name. And when calling, it's quite obvious to the user, the parameter being passed is what. Hope it helps to resolve your problem.

Related

Double pointer as Objective-C block parameter

Is it possible (and if so, safe) to create/use a block which takes a double pointer as an argument?
For instance:
- (void)methodWithBlock:(void (^)(NSError **error))block;
Additional context, research, and questions:
I'm using ARC.
When I declare the method above and attempt to call it, XCode autocompletes my method invocation as follows: [self methodWithBlock:^(NSError *__autoreleasing *error) {}];
What does __autoreleasing mean here and why is it being added? I presume it has something to do with ARC.
If this is possible and safe, can the pointer still be dereferenced in the block as it would be anywhere else?
In general, what are the important differences between doing what I'm describing, and simply passing a double pointer as a method parameter (e.g. - (void)methodWithDoublePointer:(NSError **)error;)? What special considerations, if any, should be taken into account (again assuming this is possible at all)?
yes, pointers are always just pointers. you only need to make sure you dereference it before sending it a message (assuming objc object).
Also be aware that the pointer may be nil. always check it before trying to dereference it or what have you.
As #verec mentioned if you are using ARC you should declare the parameter as __autoreleasing
according to the docs
__autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return.
remember id is a pointer to an object so that is saying object**
there is no difference between passing pointers to pointers to methods or blocks.
The answers are both Yes & No...
At a base level passing pointers to pointers to blocks is no different than passing them to methods; and, with the usual proviso that your pointers must be valid, is perfectly OK.
However that __autoreleasing is very significant here and is tied up with ARC and pass-by-writeback. Whether using the block will work as expected will be dependent on context as the compiler often uses hidden variables when passing parameters of type NSError * __autoreleasing * as part of the pass-by-writeback implementation.
If pass-by-writeback is not what you need, or is unsuitable, you may wish to declare you block as taking a different type, such as NSError * __strong *. Read this answer which explains what happens under the hood, that should help you decide whether in your context the block declaration is good.
In summary (a) declaring the block is fine, but (b) you need to understand how it may be called and may need to change the signature.
warning: untested
For the sake of argument, let's start with:
typedef NSError * NSErrorPtr ;
- (void) foo: (NSErrorPtr *) errPtr {
*errorPtr = [NSError new] ;
}
errPtr isn't declared either __weak nor __strong.
So, according to ARC, even though its contents is allocated within foo the responsibility for releasing it has to reside somewhere.
Where?
Note that this not a property of double pointers per se. But of your pattern of allocation.
consider:
int ** arrayOfarrayOfInts = {
{1, 2, 3, 4}
, {5, 6, 7, 8}
} ;
- (void) incrementElement: (int **) elem {
++(**elem) ;
}
- (void) bumpFirstColByOne {
for (int i = 0 ; i < 2 ; ++ i) {
int * arrayOfInt = arrayOfarrayOfInts[i] ;
int ** second = &arrayOfInt[0] ;
[self incrementElement: second] ;
}
}
No __autoreleasing needed here because no allocation is taking place ...

Variable number of method parameters in Objective C - Need an example

From Objective C Programming Guide (Under the "Object Messaging" section),
Methods that take a variable number of parameters are also possible,
though they’re somewhat rare. Extra parameters are separated by commas
after the end of the method name. (Unlike colons, the commas are not
considered part of the name.) In the following example, the imaginary
makeGroup: method is passed one required parameter (group) and three
parameters that are optional:
[receiver makeGroup:group, memberOne, memberTwo, memberThree];
I tried to create such a method and it shows an error
"Expected ';' after method prototype"
when I try to declare the below function in my interface file(.h file).
- (void) printMyClass: (int) x, (int) y, (int) z;
Can anyone give sample example to create such a method like makeGroup
Thank you
You can see this link.
In your header file define the methods with three dots at the end
-(void)yourMethods:(id)string1,...;
And in you implementation file write the methods body
-(void)yourMethods:(id)string1, ...{
NSMutableArray *arguments=[[NSMutableArray alloc]initWithArray:nil];
id eachObject;
va_list argumentList;
if (string1)
{
[arguments addObject: string1];
va_start(argumentList, string1);
while ((eachObject = va_arg(argumentList, id)))
{
[arguments addObject: eachObject];
}
va_end(argumentList);
}
NSLog(#"%#",arguments);
}
Now call your method
[self yourMethods:#"ab",#"cd",#"ef",#"gf",nil];
NOTE: remember to put nil at the end
The syntax for declaring a method with a variable number of arguments is like this:
- (void) printMyClass: (int) x, ...;
One argument is always the required minimum, the others can be accessed via the va_arg function group. For the exact details, see this tutorial.

Problem declaring and calling internal metthods

How do I declare and use small helper functions inside my normal methods ?
In on of my objective-c methods I need a function to find an item within a string
-(void) Onlookjson:(id) sender{
NSString * res = [[sender gstring] copy];
persInfoBirth.text = getKeyValue(res, #"Birth");
}
I came up with a normal C type declaration for helper function getKeyvalue like this
NSString * getKeyvalue(NSString * s, NSString * key){
NSString *trm = [[s substringFromIndex:2] substringToIndex:[s length]-3];
NSArray *list = [trm componentsSeparatedByString:#";"];
//....
NSString res;
res = [list objectAtIndex:1];
//...
return res;
}
Example input string in s:
s=#"{ Birth = "1910"; Death = "1936"; }";
Anyway I get an exception "unrecognized selector sent to instance" for any of the two first lines in the helper function
How do I declare helper functions that are just to be used internally and how to call them safely ?
regards
Martin
Is this the real code? Do you get zero errors and warnings from the compiler? You must not ignore compiler warnings and you should turn on the Static Analyser in addition to the standard warnings.
There are many things wrong with the above code, most of which are nothing todo with declaring and calling methods. There is no way the above code could compile so maybe it pasted incorrectly or something..
Anyway.. declaring and using methods. Why are using a c function? Unless you have a good reason why not use Objective-c ? If you do have a good reason to use a C function the your definition should be:-
NSString *getKeyvalue( NSString *s, NSString *key ){
...
}
note the arguments. As NSString instances reside in the heap (not on the stack) you always want to pass pointers to them.
You then need to put the declaration in the header file:-
NSString *getKeyvalue( NSString *s, NSString *key )
EDIT:
In Objective-c there is no distinction between normal methods and helper methods, there is only one kind, and you have aleray written one
- (void)onLookJson:(id)sender { .. }
Taking it apart..
All methods begin with + or –, indicating Class method or Instance method. As you are familiar with C++ i guess you know what this means.
(void) is the return type. ie this method doesn't return a value. If it did it might look like (float) or (NSString *) or (id).
onLookJson: is the method name and the method takes 1 argument. Notice that the ':' is actually part of the name. This method is never is any circumstance just 'onLookJson'. An argument must always follow the :, so a method that doesn't take any arguments must not have one.
Ex
- (NSString *)fullName { .. }
This is an instance method, for example of a Person Class, you would call it like:-
NSString *theName = [aPerson fullName];
So
a method name that takes no
arguments is like 'speak'
a method
name that takes 1 argument is like
'speakTo:'
a method name that takes 2
arguments is like 'speakTo: language:'
a method name that takes 3
arguments is like 'speakTo: language: volume:'
etc.
All that is left is to put in the argument types and names.
Your function definition:
NSString *getKeyvalue( NSString *s, NSString *key ){
would become..
- (NSString *)getValue:(NSString *)s key:(NSString *)key { .. }
again, you need to declare it in the header or you will get a compiler warning.
- (NSString *)getValue:(NSString *)s key:(NSString *)key;

Why doesn’t my enum work as a method parameter?

I've used typedef enum in the past with method parameters and had no problem, but today I'm having problems...
h file
typedef enum
{ eGetVarious1,
eGetVarious2,
} eGetVarious;
- (double)getVarious:(eGetVarious)eVar:(NSDate*)pDate;
an m file
you're calling a class method, and declaring an instance method:
instance method:
- (double)getVarious:(eGetVarious)eVar:(NSDate*)pDate;
class method (may not use ivars or instance methods):
+ (double)getVarious:(eGetVarious)eVar:(NSDate*)pDate;
say you want this as an instance method, declare it like this:
- (double)getVarious:(eGetVarious)eVar forDate:(NSDate*)pDate;
and if you were in the scope of implementation of an instance method, then this should work:
double result = [self getVarious:eGetVarious1 forDate:[NSDate date]];
note the reason compiler is reporting an error:
if it has not seen a particular objc selector and you use it, it assumes the undeclared selector's arguments take id (anonymous objc object).
also, enum type should not be promoted to a pointer (although 0 is ok). since the compiler saw no way to match what you're calling: [objc_class* getVarious:eGetVarious<enum_type> :NSDate*] it is right, because you should be calling it as:
General * anInstanceOfGeneral = /* something here */;
NSDate * date = /* something here */;
double result = [anInstanceOfGeneral getVarious:eGetVarious1 forDate:date];

What does the "*" mean in Objective C?

Sometimes I encounter code that has *, sometimes **. Can anyone explain what they mean in Objective C? (I used to be a Java programmer, with experience in C/C++.)
The * denotes that you are using a pointer to a variable, and is most commonly used to store a reference to an Objective-C object, objects which can only live on the heap and not the stack.
Pointers are not a part of Objective-C exclusively, but rather a feature of C (and therefore its derived languages, of which Objective-C is one of them).
If you are questioning the difference between * and **, the first denotes a pointer, whereas the second denotes a pointer to a pointer; the advantage of the latter to the former is that when passing in an object using ** in a method parameter, the method can then change this parameter and the new value is accessible in the calling method.
Perhaps the most common use of ** in Cocoa is when using NSError objects. When a method is called that can return an NSError object on failure, the method signature would look something like this:
- (id)someMethodThatUsesObject:(id)object error:(NSError**)error;
What this means is that the calling function can pass in a pointer to an NSError object, but someMethodThatUsesObject: can change the value of error to another NSError object if it needs to, which can then be accessed by the calling method.
This is often used as a workaround for the fact that functions can only return one value.
A * in Objective-C means exactly the same as in C; and you'll usually see it (or not) in these situations:
// Method signatures:
// Here the asterisk (*) shows that you have a pointer to an NSString instance.
+ (NSString *)stringWithString:(NSString *)aString;
// Method signatures, part two:
// Here the double asterisk (**) signifies that you should pass in a pointer
// to an area of memory (NSError *) where outError can be written.
- (BOOL)writeToURL:(NSURL *) atomically:(BOOL) error:(NSError **)outError;
// Method signatures make for good examples :)
// Here the asterisk is hidden; id is a typedef for void *; and it signifies that
// a pointer to some object of an indeterminate class will be returned
- (id)init;
// And a forth example to round it all out: C strings!
// Here the asterisk signifies, you guessed it, a pointer! This time, it's a
// pointer to the first in a series of const char; terminated by a \0, also known
// as a C string. You probably won't need to work with this a lot.
- (const char *)UTF8String;
// For a bit of clarity, inside example two, the outError is used as follows:
// Here the asterisk is used to dereference outError so you can get at and write
// to the memory it points to. You'd pass it in with:
// NSError *anError;
// [aString writeToURL:myURL atomically:YES error:&anError];
- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)atom error:(NSError **)outError {
// do some writing, and if it went awry:
if (outError != NULL)
*outError = [NSError errorWithName:#"NSExampleErrorName"];
return NO;
}