Printing Current Method in Objective-C - objective-c

How do I print the name of the method I am in, in Objective-C?
In Java/C# I could do this using reflection. Is similar possible with Objective-C?

For just printing method name, use
NSLog(#"%#", NSStringFromSelector(_cmd));
To printing method arguments is a complex task.
every message in ObjectiveC is converted to objMsgSend (id self, SEL, arg0...)
We need to walk through stack, and print them out, as we see after _cmd + sizeof(SEL) will give us address to arg0 (but the size and type for arg0 is unknown).
Method method = class_getInstanceMethod([self class], _cmd);
unsigned nargs = method_getNumberOfArguments(method);
void *start = _cmd;
for(unsigned i = 0; i< nargs ; i++) {
char *argtype = method_copyArgumentType(method, i);
//find arg size from argtype
// walk stack given arg zie
free(argtype);
}
Basic implementations should look like this.
So if the arguments are objects, that will be great (as we know the size of argument are 32/64 bit). Otherwise we need to do type encoding, and move cursor by argument's size. Have look https://github.com/holtwick/HOLog , that does exactly what you want, but it works under Simulator only.

Related

compare blocks and functions in objective C

As I am learning objective C, my understanding is new and incomplete. The concept of a block is very similar to a function. They even look almost identical:
FUNCTION named 'multiply'
#import <Foundation/Foundation.h>
int multiply (int x, int y)
{
return x * y;
}
int main(int argc, char *argv[]) {
#autoreleasepool {
int result = multiply(7, 4); // Result is 28.
NSLog(#"this is the result %u",result);
}
}
BLOCK named 'Multiply'
#import <Foundation/Foundation.h>
int (^Multiply)(int, int) = ^(int num1, int num2) {
return num1 * num2;
};
int main(int argc, char *argv[]) {
#autoreleasepool {
int result = Multiply(7, 4); // Result is 28.
NSLog(#"this is the result %u",result);
}
}
I found various statements on the web like:
"Blocks are implemented as Objective-C objects, except they can be put on the stack, so they don't necessarily have to be malloc'd (if you retain a reference to a block, it will be copied onto the heap, though). "
Ray Wenderlich says:
"Blocks are first-class functions"
I have no clue what all this means. My example shows that the same thing is accomplished as a block or a function. Can someone show an example where blocks can do something functions cannot? or vice versa?
Or is it something more subtle, like the way the variable 'result' is handled in memory?
or is one faster/safer?
Can either of them be used as a method in a class definition?
Thank you.
Blocks are Objective-C objects, and functions aren't. In practice, this means you can pass around a block from one piece of code to another like so:
NSArray *names = #[#"Bob", #"Alice"];
[names enumerateObjectsUsingBlock:^(id name, NSUInteger idx, BOOL *stop) {
NSLog(#"Hello, %#", name);
}];
In C, you can achieve similar effects by passing around pointers to functions. The main difference between doing this and using blocks, however, is that blocks can capture values. For instance, in the example above, if we wanted to use a variable greeting:
NSString *greeting = #"Hello";
NSArray *names = #[#"Bob", #"Alice"];
[names enumerateObjectsUsingBlock:^(id name, NSUInteger idx, BOOL *stop) {
NSLog(#"%#, %#", greeting, name);
}];
In this example, the compiler can see that the block depends on the local variable greeting and will "capture" the value of greeting and store it along with the block (in this case, that means retaining and storing a pointer to an NSString). Wherever the block ends up getting used (in this case, within the implementation of [NSArray -enumerateObjectsUsingBlock:]), it will have access to the greetings variable as it was at the time the block was declared. This lets you use any local variables in the scope of your block without having to worry about passing them into the block.
To do the same using function pointers in C, greeting would have to be passed in as a variable. However, this can't happen because the caller (in this case, NSArray) can't know (especially at compile time) exactly which arguments it has to pass to your function. Even if it did, you'd need to somehow pass the value of greeting to NSArray, along with every other local variable you wanted to use, which would get hairy really quickly:
void greet(NSString *greeting, NSString *name) {
NSLog(#"%#, %#", greeting, name);
}
// NSArray couldn't actually implement this
NSString *greeting = #"Hello";
NSArray *names = #[#"Bob", #"Alice"];
[names enumerateObjectsUsingFunction:greet withGreeting:greeting];
Blocks are closures -- they can capture local variables from the surrounding scope. This is the big difference between blocks (and anonymous functions in other modern languages) and functions in C.
Here's an example of a higher-order function, makeAdder, which creates and returns an "adder", a function which adds a certain base number to its argument. This base number is set by the argument to makeAdder. So makeAdder can return different "adders" with different behavior:
typedef int (^IntFunc)(int);
IntFunc makeAdder(int x) {
return ^(int y) { return x + y; }
}
IntFunc adder3 = makeAdder(3);
IntFund adder5 = makeAdder(5);
adder3(4); // returns 7
adder5(4); // returns 9
adder3(2); // returns 5
This would not be possible to do with function pointers in C, because each function pointer must point to an actual function in the code, of which there is a finite number fixed at compile time, and each function's behavior is fixed at compile time. So the ability to create a virtually unlimited number of potential "adders" depending on a value at runtime, like makeAdder does, is not possible. You would instead need to create a structure to hold the state.
A block which does not capture local variables from the surrounding scope, like in your example, is not much different from a plain function, aside from the type.

With NSPointerArray, how to iterate over opaque pointers?

I recently discovering these classes like NSMapTable and NSPointerArray, which work like the traditional collections, but also let you store weak references or plain old C pointers. Unfortunately it looks like you can't use the for...in syntax to iterate over non-NSObject pointers. For example:
typedef struct Segment {
CGPoint bottom, top;
} Segment;
...
NSPointerArray *segments = [[NSPointerArray alloc]
initWithOptions:NSPointerFunctionsOpaqueMemory];
...
Segment *s = malloc(sizeof(Segment));
[segments addPointer: s];
...
for (Segment *s in segments) { // nope...
The compiler does not like that last line. The error:
Selector element type 'Segment *' (aka 'struct Segment *') is not a valid object
So, do I need to do this?
for (int i=0, len=segments.count; i<len; i++) {
Segment *seg = [segments pointerAtIndex:i];
...
That's not the end of the world, but I just want to make sure.
(This might be more of theoretical interest.)
NSPointerArray does conform to the NSFastEnumeration protocol, it is only the
for (id object in collection) language construct that cannot be used with arbitrary pointers which
are not Objective-C pointers.
But you can get a whole bunch of pointers from the array by calling the NSFastEnumeration
method countByEnumeratingWithState:objects:count: directly. This is a bit tricky because
that method need not fill the supplied buffer (as explained here: How for in loop works internally - Objective C - Foundation).
Here is a simple example how this would work:
__unsafe_unretained id objs[10];
NSUInteger count = [segments countByEnumeratingWithState:&state
objects:objs count:10];
// Now state.itemsPtr points to an array of pointers:
for (NSUInteger i = 0; i < count; i++) {
Segment *s = (__bridge Segment *)state.itemsPtr[i];
NSLog(#"%p", s);
}
So this does not help to make the code simpler and you probably want to stick with
your explicit loop.
But for large arrays it might improve the performance because the pointers are "fetched"
in batches from the array instead of each pointer separately.
the for (... in ...) syntax won't work in this case because Segment is a struct, not an Objective C object. Your second for loop should work.

NSString (or NSArray or something) to variable parameter list of C (char *) strings

Is there any easy way to convert an Objective-C holding class of NSStrings into parameters for a function accepting a variable list of char *? Specifically I have a function like:
-(void)someFunction:(NSSomething *) var
that I want to forward to a C function like
void someCFunction(char * var, ...)
Is there an easy way to go about this?
No, you can only do what you want if the number of arguments you're passing is known at compile time. If you just want to convert a single string, use the -UTF8String message:
// Example with two strings
NSString *str1 = ...;
NSString *str2 = ...;
someCFunction([str1 UTF8String], [str2 UTF8String]); // etc.
But if the number of strings will vary at runtime, you'll need to use a different API, if one is available. For example, if there's an API that took an array of strings, you could convert the Objective-C array into a C array:
// This function takes a variable number of strings. Note: in C/Objective-C
// (but not in C++/Objective-C++), it's not legal to convert 'char **' to
// 'char *const *', so you may sometimes need a cast to call this function
void someCFunction(const char *const *stringArray, int numStrings)
{
...
}
...
// Convert Objective-C array to C array
NSArray *objCArray = ...;
int numStrings = [objCArray count];
char **cStrArray = malloc(numStrings * sizeof(char*));
for (int i = 0; i < count; i++)
cStrArray[i] = [[objCArray objectAtIndex:i] UTF8String];
// Call the function; see comment above for note on cast
someCFunction((const char *const *)cStrArray, numStrings);
// Don't leak memory
free(cStrArray);
This would do the trick:
NSString *string = #"testing string"
const char * p1=[string UTF8String];
char * p2;
p2 = const_cast<char *>(p1);
Yes, this can be done, and is explained here:
How to create a NSString from a format string like #"xxx=%#, yyy=%#" and a NSArray of objects?
And here:
http://www.cocoawithlove.com/2009/05/variable-argument-lists-in-cocoa.html
With modifications for ARC here:
How to create a NSString from a format string like #"xxx=%#, yyy=%#" and a NSArray of objects?
Also, variable arguments are not statically or strongly typed, as the other poster seems to be suggesting. In fact, there is no clear indication in the callee of how many arguments you really have. Determining the number of arguments generally breaks down into having to either specify the number by an count parameter, using a null terminator, or inferring it from a format string a la (s)print* . This is frankly why the C (s)print* family of functions has been the source of many errors, now made much much safer by the XCode / Clang / GCC compiler that now warns.
As an aside, you can approach statically typed variable arguments in C++ by creating a template method that accepts an array of an unspecified size. This is generally considered bad form though as the compiler generates separate instances for each size of array seen by by the compiler (template bloat).

Passing and calling dynamic blocks in Objective C

As part of a unit test framework, I'm writing a function genArray that will generate NSArrays populated by a passed in generator block. So [ObjCheck genArray: genInt] would generate an NSArray of random integers, [ObjCheck genArray: genChar] would generate an NSArray of random characters, etc. In particular, I'm getting compiler errors in my implementation of genArray and genString, a wrapper around [ObjCheck genArray: genChar].
I believe Objective C can manipulate blocks this dynamically, but I don't have the syntax right.
ObjCheck.m
+ (id) genArray: (id) gen {
NSArray* arr = [NSMutableArray array];
int len = [self genInt] % 100;
int i;
for (i = 0; i < len; i++) {
id value = gen();
arr = [arr arrayByAddingObject: value];
}
return arr;
}
+ (id) genString {
NSString* s = #"";
char (^g)() = ^() {
return [ObjCheck genChar];
};
NSArray* arr = [self genArray: g];
s = [arr componentsJoinedByString: #""];
return s;
}
When I try to compile, gcc complains that it can't do gen(), because gen is not a function. This makes sense, since gen is indeed not a function but an id which must be cast to a function.
But when I rewrite the signatures to use id^() instead of id, I also get compiler errors. Can Objective C handle arbitrarily typed blocks (genArray needs this), or is that too dynamic?
Given that blocks are objects, you can cast between block types and id whenever you want, though if you cast the block to the wrong block type and call it, you're going to get unexpected results (since there's no way to dynamically check at runtime what the "real" type of the block is*).
BTW, id^() isn't a type. You're thinking of id(^)(). This may be a source of compiler error for you. You should be able to update +genArray: to use
id value = ((id(^)())(gen))();
Naturally, that's pretty ugly.
*There actually is a way, llvm inserts an obj-c type-encoded string representing the type of the block into the block's internal structure, but this is an implementation detail and would rely on you casting the block to its internal implementation structure in order to extract.
Blocks are a C-level feature, not an ObjC one - you work with them analogously to function pointers. There's an article with a very concise overview of the syntax. (And most everything else.)
In your example, I'd make the gen parameter an id (^gen)(). (Or possibly make it return a void*, using id would imply to me that gen generates ObjC objects and not completely arbitrary types.)
No matter how you declare your variables and parameters, your code won't work. There's a problem that runs through all your compiler errors and it would be a problem even if you weren't doing convoluted things with blocks.
You are trying to add chars to an NSArray. You can't do that. You will have to wrap them them as some kind of Objective C object. Since your only requirement for this example to work is that the objects can be inputs to componentsJoinedByString, you can return single-character NSStrings from g. Then some variety of signature like id^() will work for genArray. I'm not sure how you parenthesize it. Something like this:
+ (id) genArray: (id^()) gen;
+ (id) genString {
...
NSString * (^g)() = ^() {
return [NSString stringWithFormat:#"%c", [ObjCheck genChar]];
};
...
}
NSString * is an id. char is not. You can pass NSString * ^() to id ^(), but you get a compiler error when you try to pass a char ^() to an id ^(). If you gave up some generality of genArray and declared it to accept char ^(), it would compile your call to genArray, but would have an error within genArray when you tried to call arrayByAddingObject and the argument isn't typed as an id.
Somebody who understands the intricacies of block syntax feel free to edit my post if I got some subtle syntax errors.
Btw, use an NSMutableArray as your local variable in genArray. Calling arrayByAddingObject over and over again will have O(n^2) time performance I imagine. You can still declare the return type as NSArray, which is a superclass of NSMutableArray, and the callers of genArray won't know the difference.

Objective-C, Simple String input from Console?

I honestly did a) search using key words and b) read the 'questions with similar titles' before asking this.
Also I tried to make this question more concise, but I had a hard time doing that in this case. If you feel the question is too wordy, I get it. Just don't try to answer.
I'm trying to write very simple objective-C programs that mirror the basic assignments in my introductory java class. I worked through an objective-c book over the summer and now I want to do lots of practice problems in objective-c, at the same time as I do java practice problems. I'm avoiding the objective-c GUI environment and just want to focus on working with the language for awhile. I still have a lot to learn about how to figure things out.
The program I'm duplicating from my java homework, is a standard type. I ask the user for number input and string input via the console. I was able to get numeric input from the console using an example I found here using scan f. (I will put the couple code lines below). But I'm unsure on how to get console input and store it in a string (NSString). I'm trying to learn to use the apple documentation and found a reference to a scan type command, but I cannot figure out how to USE the command. The one that seems likely is
scanCharactersFromSet:(NSCharacterSet )scanSet intoString:(NSString *)name;
Here's what I understand and works
int age = 0;
NSLog (#"How old are y'all?");
scanf("%d", &age);
NSLog (#"\n Wow, you are %d !", age);
But I don't understand how to pickup an NSString called 'name'. I THINK I'm supposed to make my 'name'a pointer, because the class is NSString.
(BTW I did try using scanf to pickup the string, but the compiler doesn't like me trying to use scanf in conjunction with name. It says that I shouldn't be using 'scanf' because it's expecting a different kind of data. I'm not sure where I found the data type 'i'. I was looking through my text for different ideas. I'm guessing that scanf is related to 'scanfloat' which clearly deals with numeric data, so this is not a big surprise)
I realize that 'scanf' isn't the right command (and I don't really get why I can't even find scanf in the apple documentation - maybe it's C?)
I'm guessing that scanCharactersFromSet might be the right thing to use, but I just don't understand how you figure out what goes where in the command. I guess I tend to learn by example, and I haven't found an example. I'd like to figure out how to learn properly by reading the documentation. But I'm not there yet.
NSString* name ;
scanf("%i", &name);
//scanCharactersFromSet:(NSCharacterSet *)scanSet intoString:(NSString **)name;
...
My book is oriented towards moving me into a gui environment, so it doesn't deal with input.
Thank you for any pointers you can give me.
Laurel
I would recommend ramping up on C. Objective-c is a thin layer over C and that knowledge will pay for itself over and over.
There's multiple ways in C to read:
http://www.ehow.com/how_2086237_read-string-c.html
For example:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
char str[50] = {0}; // init all to 0
printf("Enter you Last name: ");
scanf("%s", str); // read and format into the str buffer
printf("Your name is %s\n", str); // print buffer
// you can create an NS foundation NSString object from the str buffer
NSString *lastName = [NSString stringWithUTF8String:str];
// %# calls description o object - in NSString case, prints the string
NSLog(#"lastName=%#", lastName);
[pool drain];
return 0;
NOTE: the simple scanf is succeptible to buffer overruns. There's multiple approaches around this. see:
How to prevent scanf causing a buffer overflow in C?
Here is what Objective C looks like:
NSString *FNgetInput() {
#autoreleasepool {
return [[[NSString alloc] initWithData:[[NSFileHandle fileHandleWithStandardInput] availableData] encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
}
}
The way to get data from the standard input (or any other file handle) in cocoa is to use the NSFileHandle class. Check the docs for +fileHandleWithStandardInput
Here's how to get user input using Objective-C in 2020:
main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
char str[50] = {0}; // init all to 0
printf("Enter you Last name: ");
scanf("%s", str); // read and format into the str buffer
printf("Your name is %s\n", str); // print buffer
// you can create an NS foundation NSString object from the str buffer
NSString *lastName = [NSString stringWithUTF8String:str];
// %# calls description o object - in NSString case, prints the string
NSLog(#"lastName=%#", lastName);
return 0;
}
return 0;
}
Compile and run:
$ clang -framework Foundation main.m -o app