Var args block argument parsing loses 1 pointer arg - objective-c

Have a function:
-(void) BlockCall:(void (^)(float a, float b, NSObject *object, NSObject *secObject, NSObject *thirdObject)) argBlock
withObject: (NSObject *)object
andSObj:(NSObject *)sobject
andTObj:(NSObject *)tobject
{
object = [[NSObject alloc] init];
sobject = [[NSObject alloc] init];
tobject = [[NSObject alloc] init];
NSLog(#"First object:%#", object);
NSLog(#"Second object:%#", sobject);
NSLog(#"Third object:%#", tobject);
argBlock(15 ,27, object, sobject, tobject);
}
And varardic block:
jvalue (^voidBlock)(va_list args, ...);
voidBlock= ^(va_list args, ...){
va_arg(parsArgs, double);
va_arg(parsArgs, double);
id NSObjectArg = va_arg(parsArgs, id);
id NSObjectArg2 = va_arg(parsArgs, id);
id NSObjectArg3 = va_arg(parsArgs, id);
va_end(parsArgs);
}
If i call this function with correct parameters and pass this block as parameter. I will get strange result. It will read first and second float, then it will read second passed object as first, and third passed object as second. No matter how many primitives before or if there is no primitives reading va_list will always loose first pointer type.
If i will change this block definition to accept fixed args everything will be ok, but with veridic I always loose first pointer arg

This code doesn't really make any sense. Why would you have a function (block) which both takes a va_list (which is an encoding of another function's varargs) and also varargs? That doesn't make sense. Also, where is parsArgs defined? Why is there no va_start? And who is calling this block? Who is passing this va_list and subsequent arguments?

Related

In Objective-C/C, can you write a function that combines 2 blocks?

I often find myself creating a "wrapper" block which just serves to execute a number of other blocks, usually with the same type signature.
Say I have 2 blocks with the same type signature:
MyBlockT block1 = ^(NSString *string, id object) {
//1 does some work
};
MyBlockT block2 = ^(NSString *string, id object) {
//2 does some other work
};
Is there some way to implement the magic function Combine() which would take 2 blocks:
MyBlockT combinedBlock = Combine(block1, block2); //hypothetical function
and be equivalent to doing:
MyBlockT combinedBlock = ^(NSString *string, id object) {
block1(string, object);
block2(string, object);
};
I know this only makes sense with blocks that return void, but that's all I'm interested in.
The Combine function needs only take in 2 blocks, if I have more I can just chain them. I'm at wits end on how to go about implementing this or whether it's even possible.
P.S. I wouldn't mind if the solution involved C macros
EDIT
I'd like to be able to use the resulting block as a method argument, e.g.:
[UIView animateWithDuration:1 animations:someCombinedBlock];
Is this what you are looking for?
MyBlockT CombineBlocks(MyBlockT block1, MyBlockT block2)
{
return [^(NSString *string, id object) {
block1(string, object);
block2(string, object);
} copy];
}
The function creates a new block that calls the two given blocks sequentially.
Now up on GitHub, WoolBlockInvocation!
This is a pair of classes, WSSBlockInvocation and WSSBlockSignature, along with some supporting code, that leverage libffi and the ObjC #encode strings which the compiler generates for Blocks to allow you to invoke a whole list of Blocks with the same set of arguments.
Any number of Blocks can be added to an invocation object, provided their signatures -- meaning return type and number and types of arguments -- match. After setting arguments on the invocation object, the Blocks can be invoked in turn, with the return values, if any, stored for later access.
The piece that you're particularly interested in, sewing that list of Blocks up into a single Block, is provided by the invocationBlock method of WSSBlockInvocation.
- (id)invocationBlock
{
return [^void (void * arg1, ...){
[self setRetainsArguments:YES];
va_list args;
va_start(args, arg1);
void * arg = arg1;
NSUInteger numArguments = [blockSignature numberOfArguments];
for( NSUInteger idx = 1; idx < numArguments; idx++ ){
[self setArgument:&arg atIndex:idx];
arg = va_arg(args, void *);
}
va_end(args);
[self invoke];
} copy];
}
This returns a Block that (ab)uses varargs functionality to defer assigning arguments until that encapsulating Block is actually invoked itself. You can thus do the following:
WSSBlockInvocation * invocation = [WSSBlockInvocation invocationWithBlocks:#[animationBlockOne, animationBlockTwo]];
void (^combinedAnimation)(void) = [invocation invocationBlock];
[UIView animateWithDuration:1 animations:combinedAnimation];
Of course, if you're just worried about Blocks for animations, that take no arguments and have no return value, constructing a wrapper Block is trivial:
void (^combinedAnimation)(void) = ^{
animationBlock();
anotherAnimationBlock();
// etc.
};
You only need my code if you need to wrap a set of Blocks and invoke them all with the same set of arguments.
N.B. I have tested this on OS X on x86_64, but not on any other platform. I hope it works on ARM under iOS, but varargs is famously "not portable" and it may not. Caveat compilor, and let me know if something breaks.
Here is a fun abuse of varargs:
id combine(id block, ...)
{
NSMutableArray *blocks = [NSMutableArray array];
//[blocks addObject:block];
va_list objlist;
va_start(objlist, block);
//while((obj = va_arg(ap, id))) { // }
for(id obj = block; obj; obj = va_arg(objlist, id)) {
[blocks addObject:[obj copy]];
}
va_end(objlist);
void (^wrapper)(id,...) = ^(id arg, ...) {
NSMutableArray *args = [NSMutableArray array];
va_list arglist;
va_start(arglist, arg);
for(id x = arg; x; x = va_arg(arglist, id)) {
[args addObject:x];
}
va_end(arglist);
for(void (^blk)() in blocks) {
blk(args);
}
};
return [wrapper copy];
}
int main() {
NSString *fmt = #"-%d-\n%#\n---";
void (^foo)() = combine(^(NSArray *a){ NSLog(fmt, 1, a); },
^(NSArray *a){ NSLog(fmt, 2, a); }, nil);
foo(#"first", #"second", nil);
return 0;
}
You must define each block to accept an NSArray of arguments, and both the combine and resulting block invocation must have at least one argument and end in nil.
If you know the method signature ahead of time, you can work around the NSArray and block arguments restriction by altering the wrapper block appropriately.
Since you don't mind macros
#define combinedBlock(string, object) \
block1((string), (object) ) \
block2((string), (object) )
if you need to perform 2 or more animations simultaneously then RZViewActions is everything you need. Its code looks like almost as animateWithDuration:... calls but with additional features.
If you need to perform ANY blocks simultaneously then you need something like ReactiveCocoa. But I suggest you PromiseKit (simply because it is easier).

Iterating a va_list when passed as a parameter to a method in Objective-C

I would like to pass a variable argument list from one method (functionOne) to another (functionTwo). Everything works fine, except that I have not been able to figure out how to setup the va_list in functionTwo in a way where I can access the first parameter in the va_list. Using va_arg advances to the second parameter in the va_list. Thx.
- (void)functionOne:(NSString *)configFiles, ... {
va_list args;
va_start(args, configFiles);
[self functionTwo:args];
va_end(args);
}
- (void)functionTwo:(va_list)files {
NSString *file;
while ((file = va_arg(configFiles, NSString *))) {
...
}
}
The first variadic argument is not the argument passed to va_start – it's the one immediately following it. If you want functionTwo: to have access to the configFiles string, you'll need to pass it in explicitly.
See Technical Q&A QA1405: Variable arguments in Objective-C methods.
Methods that take variable arguments are known as variadic methods.
Keep in mind that the implementation of an Objective-C method is just
a block of code, like a C function. The variadic argument macros
described in the stdarg(3) manual page work the same way in a method
as they do in an ordinary function.
Here's an example of an Objective-C category, containing a variadic
method that appends all the objects in a nil-terminated list of
arguments to an NSMutableArray instance:
#import <Cocoa/Cocoa.h>
#interface NSMutableArray (variadicMethodExample)
// This method takes a nil-terminated list of objects.
- (void)appendObjects:(id)firstObject, ...;
#end
#implementation NSMutableArray (variadicMethodExample)
- (void)appendObjects:(id)firstObject, ... {
id eachObject;
va_list argumentList;
if (firstObject) // The first argument isn't part of the varargs list,
{ // so we'll handle it separately.
[self addObject: firstObject];
// Start scanning for arguments after firstObject.
va_start(argumentList, firstObject);
while (eachObject = va_arg(argumentList, id)) // As many times as we can get an argument of type "id"
[self addObject: eachObject]; // that isn't nil, add it to self's contents.
va_end(argumentList);
}
}
#end
A solution that I use for debugging purposes is like
-(void) debug:(NSString*)format, ... {
if (level < MXMLogLevelDebug) return;
if(format == nil) return;
va_list args, args_copy;
va_start(args, format);
va_copy(args_copy, args);
va_end(args);
NSString *logString = [[NSString alloc] initWithFormat:format
arguments:args_copy];
NSString *funcCaller = #"";
NSArray *syms = [NSThread callStackSymbols];
if ([syms count] > 1) {
funcCaller = [syms objectAtIndex:1];
}
NSString *logMessage = [NSString stringWithFormat:#"%# DEBUG: %#", funcCaller, logString];
NSLog(#"%#",logMessage);
}
The side-effect that this can have is that you have to add a guard on the args to be sure is not NULL.

Objective C - what is the usage of a non-void block?

I've seen many blocks with void return type. But it's possible to declare non-void blocks. Whats the usage of this?
Block declaration,
-(void)methodWithBock:(NSString *(^)(NSString *str))block{
// do some work
block(#"string for str"); // call back
}
Using the method,
[self methodWithBock:^NSString *(NSString *str) {
NSLog(str); // prints call back
return #"ret val"; // <- return value for block
}];
In above block declaration , what exactly is the purpose of NSString return type of the block? How the return value ( "ret val") can be used ?
You can use non-void blocks for the same reason you'd use a non-void function pointer - to provide an extra level of indirection when it comes to code execution.
NSArray's sortUsingComparator provides one example of such use:
NSArray *sorted = [originalArray sortedArrayUsingComparator:(NSComparator)^(id obj1, id obj2){
NSString *lhs = [obj1 stringAttribute];
NSString *rhs = [obj2 stringAttribute];
return [lhs caseInsensitiveCompare:rhs];
}];
The comparator block lets you encapsulate the comparison logic outside the sortedArrayUsingComparator method that performs the sorting.
It's just a return, so you could do something like this to take advantage of the return value and do work on it as well.
-(void)methodWithBlock:(NSString *(^)(NSString *str))block{
// do some work
NSString *string = block(#"string for str"); // call back
// do something with the return string
NSLog(#"%#",string);
}

Objective C +(id) methods

I am quite new to Objective-C in some ways, so I'd like to ask how should I make methods that return the objects themselves. Let me show an example:
In NSArray you can do [NSArray arrayWithObjects:bla,bla,nil];
How I make that kind of method to my own class?
There are two main things going on with that method:
It's a Class method (ie, a + method)
It uses a variable argument list
To make it, you'd probably do something like this:
+ (id)fooWithStuff:(id)stuff, ... NS_REQUIRES_NIL_TERMINATION {
// the "+" means it's a class method
// the "NS_REQUIRES_NIL_TERMINATION" is so that the compiler knows you have to use it like this:
// foo = [ThisClass fooWithStuff:thing1, thing2, thing3, nil];
// (IOW, there must be a "nil" at the end of the list)
va_list args; // declare a "variable list"
va_start(args, stuff); // the list starts after the "stuff" argument
Foo *foo = [[Foo alloc] init]; // create a Foo object
id nextStuff = stuff; // this is the next stuff
while(nextStuff != nil) { // while there is more stuff...
[foo doSomethingWithStuff:nextStuff]; // do something with the stuff
nextStuff = va_arg(args, id); // get the next stuff in the list
// the "id" means that you're asking for something the size of a pointer
}
va_end(args); // close the argument list
return [foo autorelease]; // return the Foo object
}

Objective c implement method which takes array of arguments

Hee
Does anybody know how to implement an method in objective c that will take an array of arguments as parameter such as:
[NSArray arrayWithObjects:#"A",#"B",nil];
The method declaration for this method is:
+ (id)arrayWithObjects:(id)firstObj...
I can't seem to make such method on my own. I did the following:
+ (void) doSometing:(id)string manyTimes:(NSInteger)numberOfTimes;
[SomeClass doSometing:#"A",#"B",nil manyTimes:2];
It will give the warningtoo many arguments to function 'doSometing:manyTimes:'
Thanks already.
The ellipsis (...) is inherited from C; you can use it only as the final argument in a call (and you've missed out the relevant comma in your example). So in your case you'd probably want:
+ (void)doSomethingToObjects:(id)firstObject, ...;
or, if you want the count to be explicit and can think of a way of phrasing it well:
+ (void)doManyTimes:(NSInteger)numberOfTimes somethingToObjects:(id)firstObject, ...;
You can then use the normal C methods for dealing with ellipses, which reside in stdarg.h. There's a quick documentation of those here, example usage would be:
+ (void)doSomethingToObjects:(id)firstObject, ...
{
id object;
va_list argumentList;
va_start(argumentList, firstObject);
object = firstObject;
while(1)
{
if(!object) break; // we're using 'nil' as a list terminator
[self doSomethingToObject:object];
object = va_arg(argumentList, id);
}
va_end(argumentList);
}
EDIT: additions, in response to comments. You can't pass the various things handed to you in an ellipsis to another function that takes an ellipsis due to the way that C handles function calling (which is inherited by Objective-C, albeit not obviously so). Instead you tend to pass the va_list. E.g.
+ (NSString *)doThis:(SEL)selector makeStringOfThat:(NSString *)format, ...
{
// do this
[self performSelector:selector];
// make string of that...
// get the argument list
va_list argumentList;
va_start(argumentList, format);
// pass it verbatim to a suitable method provided by NSString
NSString *string = [[NSString alloc] initWithFormat:format arguments:argumentList];
// clean up
va_end(argumentList);
// and return, as per the synthetic example
return [string autorelease];
}
Multiple arguments (also known as an arglist) can only come at the end of a method declaration. Your doSomething method would look something like this:
+ (void)doNumberOfTimes:(NSInteger)numberOfTimes withStrings:(id)firstArg, ...
{
va_list args;
va_start(args, firstArg);
NSString * argString = firstArg;
while (argString != nil)
{
// do something with argString here
argString = va_arg(args, NSString *);
}
va_end(args);
}
To be called as follows:
[SomeClass doNumberOfTimes:2 withStrings:#"A", #"B", nil];
See also: How to create variable argument methods in Objective-C
I think you're after a variadic function. Here's Apple's documentation: http://developer.apple.com/library/mac/qa/qa2005/qa1405.html