How to log arguments in runtime? - objective-c

I created a new function to log every method from a class in runtime.
The problem that I have is in this line :
id value = va_arg(stackFrame, id);
Doesn't convert the type of object inside the arguments.
Any idea on what I'm doing wrong? Is there another way to do this?
void DebugArguments ( id self, SEL _cmd,...)
{
id receiver = self;
SEL receiverSelector = _cmd;
va_list stackFrame;
va_start(stackFrame, _cmd);
NSMethodSignature *signature
= [receiver methodSignatureForSelector:receiverSelector];
NSUInteger count = [signature numberOfArguments];
NSUInteger index = 2;
for (; index < count; index++)
{
id value = va_arg(stackFrame, id);
if (!value)
{
NSLog(#"Arguments: %#",value);
}
}
va_end(stackFrame);
}

I call the function InitDebug from a class like this : -
(void)MyTest:(NSString *)string {
InitDebug(self, _cmd); } I hope
to log the Argument string from the
method MyTest.
In the future, it is helpful to show all the code.
In any case, you can't do that; when you call InitDebug(...), you are pushing a new frame onto the stack and va_arg() will decode in the context of that frame, not the surrounding frame. Nor can you "go up the stack" and start grubbing about in the arguments of the calling frame as there is no guarantee that the calling frame is even preserved at that point.
If you really want to do something like this, you would probably want to subclass NSProxy and use it is a proxy between the caller and whatever object you want to log. You could then leverage the built-in forwarding mechanism of Objective-C to muck about with the arguments.

Related

How can I define a method with multiple optional arguments in Obj-C

I want to be able to update two sets of identical buttons with one function. Also I don't want to update all the buttons, only some of them.
Can I have a function like this?:
-(void) updateFields{
updateButton1 : (Bool) x
updateButton2 : (Bool) y
updateButton3 : (Bool) z }
The implementation will look like this:
[button1_1 setEnabled:x];
[button1_2 setEnabled:x]; //called only if updateButton1 is given an argument
[button2_1 setEnabled:y];
etc...
What about passing an array of button and an array of boolean wrapped in a NSNumber?
- (void)updateButton:(NSArray *)buttons withArray:(NSArray *)enablers {
// buttons is an array of UIButton
// enablers is an array of NSNumber created from boolean value
// Security check
if(buttons.count != enabler.count) {
NSLog(#"Error: array have different dimensions");
return;
}
// Enable buttons
for(int i=0; i<buttons.count; i++) {
UIButton *button = (UIButton *)[buttons objectAtIndex:i];
BOOL enable = [[enablers objectAtIndex:i] boolValue]
[button setEnabled:enable];
}
}
This may not be possible with primitive data types unless you create objects from them and put them in NSArray or NSDictionary. Other option can be to create a custom object and pass that as argument.
- (void)selectButton:(SelectedButton *)iButton {
if (iButton.type = A) {
// Handle A
} else if (iButton.type = B) {
// Handle B
} else if (iButton.type = C) {
// Handle C
}
}
i think the syntax you're going for makes more sense as a C function
however note that in this example the parameters are NOT optional.
void updateButtons(BOOL btn1, BOOL btn2, BOOL btn3){
button1.enabled = btn1
button2.enabled = btn2
button3.enabled = btn3
}
It's possible to create an Objective-C method with a variable argument list, as Matt Gallagher explains in Variable argument lists in Cocoa. Variable argument lists are even used in the Foundation framework, e.g. +[NSArray arrayWithObjects:...].
That said, it's probably a lot less work to pass the list of buttons in your method as an array, particularly given the ease with which one can now create arrays using object literals:
[foo updateFields:#[button1, button2, button3]];

How can I create a block that 'wraps' a target/selector pair?

I love blocks, and they are very cool.
However, I find that blocks can clutter up my code and make it harder to read without folding all of them up inside Xcode (which I don't like doing).
I like splitting my code into logical methods (selectors) to keep it easier to read, but it appears (on the surface) that this isn't readily possible with frameworks like dispatch, AFNetworking, and several others.
I also don't care for the delegate approach, as that means I cannot name my methods as I would like to, instead relying on what other people think I need.
So, without writing a bunch of glue code like this:
-(void) reloadData {
...
[[EventsManager instance] data:YES async:^(NSArray *events) { [self processEvents:events] }];
...
}
I could instead do something like this:
-(void) reloadData {
...
[[EventsManager instance] data:YES async:createBlock(self, #selector(processEvents:))];
...
}
Which is easier to read (to me).
With the power that we have with objective-c, and it's runtime, this should be possible, no? I haven't seen anything like this out there, though.
I liked your answer from an academic standpoint; +1 and, clearly, you learned something.
From a practical perspective, it seems like an awful lot of added fragility for very little reduction in typing while it also leads to some information loss at the call site.
The advantage of this is that it is exactly explicit:
-(void) reloadData {
...
[[EventsManager instance] data:YES async:^(NSArray *events) { [self processEvents:events] }];
...
}
Reading that, one sees that the asynchronous callback block is required to process the arguments and that the processEvents: method on self will be used to do the actual work.
The expression createBlock(self, #selector(processEvents:)) is a lossy representation of the same; it loses the explicit argumentation of the callback and the mapping between that argumentation and the method being invoked (I often see callback blocks like the above with multiple arguments where there is some lightweight logic and/or argument processing before invoking the method).
Note also that processing a non-varargs call site as a varargs when called is a violation of the C standard and will not work on certain ABIs with certain lists of arguments.
Yes, this is indeed possible, but this solution is ABI-specific (not guaranteed to work on all platforms), and makes extensive use of the information available at run-time about methods.
What we first must do is get information about the method we are wrapping with the block. This is done via NSMethodSignature, which contains information such as:
Number of arguments
Size (in bytes) of each argument
Size of return type
This allows us to wrap (almost) any method with no specific code for that method, thus creating a re-usable function.
Secondly, we need a way to safely dispatch method calls at run-time. We do this via NSInvocation, which grants us the ability to create a dynamic, and safe, method call at run-time.
Thirdly, we need to have a block that can take any number of arguments passed in, and the dispatch that. This is done via C's va_list APIs, and should work for 99% of methods.
Finally, we need to get the return value, and be able to return that from our block. This is the part of the entire operation that is possible to not work, because of weirdness with returning structs and such with the Objective-C runtime.
However, as long as you keep to primitive types and Objective-C objects, this code should work great for you.
A couple of things to note about this implementation:
It is reliant upon undefined behavior with casting of block & function types, however, because of the calling conventions of iOS and Mac, this should not pose any issues (unless your method has a different return type than what the block expects).
It also relies upon undefined behavior with the result of calling va_arg with a type that may not be what is passed - however, since the types are of the same size, this should never be an issue.
Without any further ado, here is an example of the code, followed by the implementation:
#interface MyObj : NSObject
-(void) doSomething;
#end
#implementation MyObj
-(void) doSomething
{
NSLog(#"This is me, doing something! %p", self);
}
-(id) doSomethingWithArgs:(long) arg :(short) arg2{
return [NSString stringWithFormat:#"%ld %d", arg, arg2];
}
#end
int main() {
// try out our selector wrapping
MyObj *obj = [MyObj new];
id (^asBlock)(long, short) = createBlock(obj, #selector(doSomethingWithArgs::));
NSLog(#"%#", asBlock(123456789, 456));
}
/* WARNING, ABI SPECIFIC, BLAH BLAH BLAH NOT PORTABLE! */
static inline void getArgFromListOfSize(va_list *args, void *first, size_t size, size_t align, void *dst, BOOL isFirst) {
// create a map of sizes to types
switch (size) {
// varargs are weird, and are aligned to 32 bit boundaries. We still only copy the size needed, though.
// these cases should cover all 32 bit pointers (iOS), boolean values, and floats too.
case sizeof(uint8_t): {
uint8_t tmp = isFirst ? (uint32_t) first : va_arg(*args, uint32_t);
memcpy(dst, &tmp, size);
break;
}
case sizeof(uint16_t): {
uint16_t tmp = isFirst ? (uint32_t) first : va_arg(*args, uint32_t);
memcpy(dst, &tmp, size);
break;
}
case sizeof(uint32_t): {
uint32_t tmp = isFirst ? (uint32_t) first : va_arg(*args, uint32_t);
memcpy(dst, &tmp, size);
break;
}
// this should cover 64 bit pointers (Mac), and longs, and doubles
case sizeof(uint64_t): {
uint64_t tmp = isFirst ? (uint64_t) first : va_arg(*args, uint64_t);
memcpy(dst, &tmp, size);
break;
}
/* This has to be commented out to work on iOS (as CGSizes are 64 bits)
// common 'other' types (covers CGSize, CGPoint)
case sizeof(CGPoint): {
CGPoint tmp = isFirst ? *(CGPoint *) &first : va_arg(*args, CGPoint);
memcpy(dst, &tmp, size);
break;
}
*/
// CGRects are fairly common on iOS, so we'll include those as well
case sizeof(CGRect): {
CGRect tmp = isFirst ? *(CGRect *) &first : va_arg(*args, CGRect);
memcpy(dst, &tmp, size);
break;
}
default: {
fprintf(stderr, "WARNING! Could not bind parameter of size %zu, unkown type! Going to have problems down the road!", size);
break;
}
}
}
id createBlock(id self, SEL _cmd) {
NSMethodSignature *methodSig = [self methodSignatureForSelector:_cmd];
if (methodSig == nil)
return nil;
return ^(void *arg, ...) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setTarget:self];
[invocation setSelector:_cmd];
NSUInteger argc = [methodSig numberOfArguments];
va_list args;
va_start(args, arg);
for (int argi = 2; argi < argc; argi++) {
const char *type = [methodSig getArgumentTypeAtIndex:argi];
NSUInteger size;
NSUInteger align;
// get the size
NSGetSizeAndAlignment(type, &size, &align);
// find the right type
void *argument = alloca(size);
getArgFromListOfSize(&args, arg, size, align, argument, argi == 2);
[invocation setArgument:argument atIndex:argi];
}
va_end(args);
[invocation invoke];
// get the return value
if (methodSig.methodReturnLength != 0) {
void *retVal = alloca(methodSig.methodReturnLength);
[invocation getReturnValue:retVal];
return *((void **) retVal);
}
return nil;
};
}
Let me know if you have any issues with this implementation!

How to implement whileTrue control flow method with Obj-C Blocks?

Is it possible to implement something like a Smalltalk-style whileTrue: method in Objective-C using blocks? Specifically, instead of:
int count = 0;
while (count < 10)
{
NSLog(count);
count++;
}
I'd like to be able to do (via a wrapper on the bool primitive called OOBoolean) something like...
__block int count = 0;
[[OOBoolean booleanWithBool: count < 10] whileTrueDo: ^() {
NSLog(count);
count++;
}];
I'm having trouble understanding how this would be implemented though...
Here you have a couple of ideas,
Assuming your bool wrapper implements boolValue, a naive implementation could be:
-(void) whileTrueDo:(void (^)(void)) block{
while ([self boolValue]) {
block();
}
}
In order for the wrapper to change its bool value after each iteration, the block must be able to actually change the variable that is used to calculate the boolean condition. So, in your case, by setting the __block type modifier to count, and increasing count in each block execution, you should be able to make it work.
The problem is, if you create your wrapper by sending the evaluated condition, as you stated in your question, you wont be able to change its bool value in each iteration. So, I would change the way the wrapper is created and the whileTrueDo: naive implementation so the boolean wrapper uses an evaluation block.
__block int count = 0;
OOBooleanBlock evaluationBlock = ^BOOL{
return count < 10;
};
[[OOBoolean booleanWithBlock:evaluationBlock] whileTrueDo: ^() {
NSLog(count);
count++;
}];
//In OOBoolean
+(OOBoolean*) booleanWithBlock:(OOBooleanBlock) evaluationBlock{
//Instantiate, set the evaluationBlock ivar and return the ooboolean object.
}
-(void) whileTrueDo:(void (^)(void)) block{
while (self.evaluationBlock()) {
block();
}
}
Remember to use the __block type modifier, otherwise you will enter in an infinite loop.
I haven't tested this, I hope this helps you though.
Cheers

Objective C Function Question

Hey guys, check this out. I have a function that treats for me a string. No matter what it does, i just want to knwo if is possible to this function return the result for the place that it was executed. I mean, check this:
[self priceFormat:#"1"];
priceLabel.text = price;
-(void) priceFormat:(NSString*)price {
price = #"2";
}
I just want to my function treats the string and return it to the same place that it was executed.
Thanks!
Three ways to do this
Way one, using a pointer
- (void)priceFormat:(NSString **)price {
*price = #"2";
}
Wat two, using an instance variable
What you might want instead is an ivar. In the interface (most often the h file) of your class:
NSString *price;
and in the implementation (the m or mm file):
- (void)priceFormat:(NSString *)price {
price = #"2";
}
I have created an example of this here.
If you want the price to be available to other objects as well (not just self), you might want to create a property for it and synthesize it. Then use self.price = #"2"; instead. More on this here: http://MacDeveloperTips.com/objective-c/objective-c-properties-setters-and-dot-syntax.html
Just make sure you make it a copy property (NSString in use)!
Way three using return
Note, that you can also return directly from a method:
- (NSString *)priceFormat:(NSString *)price {
return #"2";
}
priceLabel.text = [self priceFormat:#"1"];

Method in Objective-C that points to an object

I have created a few sprites using a spriteclass and I have loaded them into an array. In my app, I loop over the array checking for particular conditions (position, etc.). I want to create an explosion method that I can pass one of these objects to and then using the pointer pull the position of the object on the screen and show an explosion there. I don't know how to pass the pointer/object that is in my array to the method to be used.
Here is essentially what I had in mind:
for (int i=1; i<4; i++) {
EnemySprite *currentenemy = [enemies objectAtIndex:i-1];
//Blow this guy up
[self explosion:currentenemy]
}
-(void)explosion someobject {
explosion.position = someobject.position
someobject.setHidden=YES;
}
You would write it like this for one param
// definition
-(void) explosion:(EnemySprite*) someObject
{
}
// usage
[self explosion: object];
For two params things are a bit more involved. Consider;
// definition
-(void) explosion:(EnemySprite*) someObject radius:(float)explosionRadius
{
...
if (pos < explosionRadius)
...
}
// usage
[self explosion: object radius:10.0f];
Everything before the : is used for the external name, everything after is the name internal to the function.
This is why you will often see Objective-C functions written with function names that end with the name of the first type:
-(void) explodeSprite:(EnemySprite*) sprite radius:(float)radius;
Both the sprite and radius params then appear to be "named" when the function is written;
[self explodeSprite:sprite radius:10.0f];
Why not make your object the receiver of the explosion?
for (id currentenemy in enemies)
{
[currentenemy explode];
}