Merry Christmas everybody :)
I have a pointer problem. Although I´m familiar with pointer concepts I haven´t used pointers in Objective-C so far the way it´s described here.
I modified it like this:
int countSInteger = 10;
[self setHMSValues:countSInteger];
- (void) setHMSValues: (int*) timeCat {
*timeCat = *timeCat - 1;
}
But now I´receiving a EXC_BAD_ACCESS:
Any Santa hints?
Greetings from Switzerland, Ronald Hofmann
It looks like you want setHMSValues: to calculate and return a value for the integer parameter. However, the parameter is a pointer to an int (int *), and you're passing a plain int with the value of 10. Because pointers are just integer values themselves (with the integer value representing a memory address), the code is trying to set the value at memory location 10; hence, you get a "bad access" error because your program cannot access or change values at memory location 10.
What you should do is pass the address of countSInteger to the method:
[self setHMSValues:&countSInteger];
However, there's a better way to do this. Since you're returning only one value from the method, there's no need for an out parameter. You can change your method to this:
- (int) setHMSValues: (int) timeCat {
return timeCat - 1;
}
and call it like this:
int countSInteger = 10;
countSInteger = [self setHMSValues:countSInteger];
Try:
- (void) setHMSValues: (int*) timeCat {
*timeCat = *timeCat - 1;
}
"countInteger" is declared as an "int *" while the method you're calling into is expecting an "int".
Don't you think you might have better luck if you declare "countInteger" as a plain "int"?
Why use int pointers? Just remove the *
Does Objective-C support pass by reference using & like C++? I haven't checked Objective-C specifically, (never had the need) but in C++ the following is used to tell the compiler to use pass-by-reference:
void count(int &var);
Related
How do you do pointers to pointers in Swift? In Objective-C I had a function which I would call recursively so that I could keep track of the number of recursions, but I'm stumped as to how to achieve this in Swift.
NSNumber *recursionCount = [NSNumber numberWithInteger:-1];
[self doRecursion:&recursionCount];
- (void)doRecursion:(NSNumber **)recursionCount {
// I'm sure this is a terrible way to increment, but I have limited Objective-C experience
// and this worked, so I moved on after failing to find a decent var++ equivalent :-(
int addThis = (int)i + 1;
*recursionCount = [NSNumber numberWithInt:[*recursionCount intValue] + addThis];
[self doRecursion:recursionCount];
}
In the process of cutting this sample down for this post, I've ended up creating a never-ending loop, but you get the idea on how I'm remembering the value with each recursion.
Does anybody know how to do this in Swift? Thanks.
Usage of pointers in swift is highly discouraged.
To change a variable passed as argument to a function, you have to pass it by reference (similar to passing its pointer) using the inout modifier. I've changed the logic of your function to stop after 10 iterations:
func doRecursion(inout recursionCount: Int) -> Int {
if (recursionCount < 10) {
++recursionCount
doRecursion(&recursionCount)
}
return recursionCount
}
Then you can call using:
var counter: Int = -1
let x = doRecursion(&counter) // Prints 10 in playground
Suggested reading: In-Out Parameters
How can I have a method/function that can return any type? For example sometimes the type will need to be float and sometimes it will need to be NSString* so id won't work because float isn't an id. I am not opposed to doing it in a c or c++ function if it's easier.
The reason why I need a dynamic return type is because I'm using objc/runtime to get an Ivar.
I would like some_type to be able to anything:
- (some_type)getIvarWithName:(const char *)name in:(id)obj
{
Ivar ivar(class_getInstanceVariable(object_getClass(obj),name));
return (some_type)ivar;
}
Return a float wrapped in an NSNumber, then you can use the id return type.
To simplify it, you can even use boxing literals, for example:
return #(1.1f);
The first thing to think about is why you would need a function that can return any type. It really doesn't make sense because you wouldn't be able to assign the value to anything, since you don't know the type. Of course, the situation is different when dealing strictly with Obj-C objects, as the language utilizes unknown objects with the id keyword. Unknown objects are like mixing Honeycrisp apples with Macintosh apples (no pun intended), and what you are trying to do is like mixing Honeycrisp apples with airplanes! However, if you want a certain type returned based off of the parameters (such as returning int for int parameters and float for float parameters), then you can overload the functions. Otherwise, then only way that I know of to return absolutely anything would be a void pointer (void *). This would point to a chunk of data that could really be anything. But back to the original problem. What does it represent and how long is it? Good luck!
UPDATE: As other answers mention, you can wrap simple data types (int, float, etc.) in objects such as NSNumbers or NSValues, which will work for your case. But when extending to more general scenarios with complex types such as structs, these generally can't be wrapped in built-in classes. You would need to make your own class using Obj-C.
There is no polymorphism of that kind in Obj-C.
If you know in advance what will be returned then you could use to methods of course.
Retruning id would work when you use an NSNumber for the float value.
You could even introduce a response object that either carries a number or a string and provides (bool) isNumber and (bool) isString methods for later processing.
But what are you really up to? In which context are you using that and what do you really try to achieve. To me it sounds as if there may be better solutions available.
Ofcourse it's weird solution, but you have weird question.
You need enable objective-c++: rename .m-file to .mm
Then yours code will look something like that:
void weird_function(int a)
{
switch (a)
{
case 0: throw #"Hello";
default: throw a;
}
}
void some_code(int a)
{
try
{
weird_function(a);
}
catch (int a)
{
NSLog(#"Catch int: %d", a);
}
catch (NSString* str)
{
NSLog(#"Catch string: %#", str);
}
}
Yours method can be implemented something like that:
union ValueHolder
{
void* voidPtrValue;
int intValue;
float floatValue;
NSString* nssstringValue;
};
- (void)getIvarWithName:(const char *)name in:(id)obj
{
ValueHolder vh;
Ivar ivar = object_getInstanceVariable(obj,name, &vh.voidPtrValue));
if (NULL == ivar)
return;
const char* encoding = ivar_getTypeEncoding(ivar);
if (0 == strcmp(encoding, #encode(int)))
throw vh.intValue;
if (0 == strcmp(encoding, #encode(float)))
throw vh.floatValue;
if (0 == strcmp(encoding, "#\"NSString\""))
throw vh.nsstringValue;
}
I found that using a template in c++ works to have a custom type
The following code works best for my situation:
template <typename _type>
static inline _type & hookVar(id self, NSString*name)
{
Ivar ivar(class_getInstanceVariable(object_getClass(self),[name UTF8String]));
#if __has_feature(objc_arc)
void *pointer(ivar == NULL ? NULL : reinterpret_cast<char *>((__bridge void *)self) + ivar_getOffset(ivar));
#else
void *pointer(ivar == NULL ? NULL : reinterpret_cast<char *>(self) + ivar_getOffset(ivar));
#endif
return *reinterpret_cast<_type *>(pointer);
}
To call the function I just use something like:
NSWindow *win = hookVar<NSWindow*>(self, #"_window");
Is there any way to do the following at compile-time?
int anInteger = 0;
__if_object(anInteger) {
// send object some messages
}
__if_primitive(anInteger) {
// do something else
}
An dummy situation where this could be used is to define the __add_macro below.
#define __add_macro(var, val) __something_goes_here__
int i = 1;
MyInteger* num = [[MyNumber alloc] initWithValue:1]
__add_macro(i, 4);
__add_macro(num, 4);
// both should now hold 5
Clarification/Simplification
I guess there is no way to do this with one macro. But I still need it to warn if the macro is being used on the wrong datatype. Those two types are: object and non-object).
To check if it is an object, this works:
#define __warn_if_not_object(var) if(0){[(var) class];}
What I need:
#define _warn_if_object(var) if(0){__something_here__}
Again, I need this to happen at compile-time. And it can either throw an error or warning.
Thanks
When you declare an int variable you can really only put an int value in it.
While this is Objective-C, and hence C, so you can bypass just about every type protection mechanism that exists, this is not to be advised. Indeed there is no guarantee whatsoever that a, say, NSNumber reference will even fit into an int variable - and more than enough chance that if you try, and bypass any warnings, some bits will just get tossed making the reference invalid.
So, no, while you can tell what class an object reference refers to, you cannot in general tell whether a variable has an integer value or an object reference in it - you shouldn't even try to put these two very different things into the same variable.
Answer 2
Patrick, your comments and clarification seem to suggest you are not trying to do what the question starts out by asking (how do you determine if the value in an int is an object - answered above, you don't), but something rather different...
I think what you're after is function overloading, and as you seem to be trying to use macros, maybe inline functions as well. Clang supports function overloading, here is program fragment which may show you how to solve your problem:
// Clang likes prototypes so let's give it some
// The following declares two overloaded inline functions:
NS_INLINE void __attribute__((overloadable)) byType(int x);
NS_INLINE void __attribute__((overloadable)) byType(NSNumber *x);
// now some simple definitions:
NS_INLINE void __attribute__((overloadable)) byType(int x)
{
NSLog(#"int version called: %d", x);
}
NS_INLINE void __attribute__((overloadable)) byType(NSNumber *x)
{
NSLog(#"NSNumber version called: %#", x);
}
// now call them, automatically selecting the right function
// based on the argument type
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
int x = 5;
NSNumber *y = [NSNumber numberWithInt:42];
byType(x);
byType(y);
}
The above code when run outputs:
int version called: 5
NSNumber version called: 42
Clang 3 compiles the above code inlining the two calls, so you get the same code as using macros.
please don't mix between scalar values and pointers to objects... it will not end well.
if you insist you can do something with Objective-C++
something like
int sum(int,int);
NSNumber * sum(NSNumber *, NSNumber *);
- (void) swapController:(MyViewController*)controller1
with:(MyViewController*)controller2
{
MyViewController *swap = controller2;
controller2 = controller1;
controller1 = swap;
}
Looks like this doesn't work because I'm not passing references. How to do it anyway?
You can do this by passing in pointers to the pointers you want to change:
- (void)swapController:(MyViewController**)controller1 with:(MyViewController**)controller2
{
MyViewController* swap = *controller2;
*controller2 = *controller1;
*controller1 = swap;
}
Not looking for this as an opposing answer here, but rather to complement #Huw's answer.
On implementing his swapController:with: method above, I noticed some issues with ARC and with primitives. ARC will take issue if you're passing a strong id* to an id* ( which it will designate as autoreleased id and other fun warnings).
If you're anything like me, well, one fine day you'll be swapping pointers back and forth in objc and one of those values will be a primitive data type.
If you do end up doing something like that, here's a little helper (like I said earlier) to complement the above answer:
void swapObjcPointerWithC ( void** ptrA, void** ptrB ) {
void *temp = *ptrA;
*ptrA = *ptrB;
*ptrB = temp;
}
...
// Later on
id objA;
int anInt = 10;
swapObjcPointerWithC ( (void*)&objA, (void*)&anInt );
There you go. My two cents.
Note: also works will nil pointers apparently.
I've got object_getInstanceVariable to work as here however it seems to only work for floats, bools and ints not doubles. I do suspect I'm doing something wrong but I've been going in circles with this.
float myFloatValue;
float someFloat = 2.123f;
object_getInstanceVariable(self, "someFloat", (void*)&myFloatValue);
works, and myFloatValue = 2.123
but when I try
double myDoubleValue;
double someDouble = 2.123f;
object_getInstanceVariable(self, "someDouble", (void*)&myDoubleValue);
I get myDoubleValue = 0. If I try to set myDoubleValue before the function eg. double myDoubleValue = 1.2f, the value is unchanged when I read it after the object_getInstanceVariable call. Setting myIntValue to some other value before the getinstancevar function above returns 2 as it should, ie. it has been changed.
then I tried
Ivar tmpIvar = object_getInstanceVariable(self, "someDouble", (void*)&myDoubleValue);
If I do ivar_getName(tmpIvar) I get "someDouble", but myDoubuleValue = 0 still! Then I try ivar_getTypeEncoding(tmpIvar) and I get "d" as it should be.
So to summarize, if typeEncoding = float, it works, if it is a double, the result is not set but it correctly reads the variable and the return value (Ivar) is also correct.
I must be doing something basic wrong that I cant see so I'd appreciate if someone could point it out.
object_getInstanceVariable is a confused little function. It is documented that the last parameter is a void ** parameter—that is, you pass the address of a void * variable and get a pointer to the instance variable—but it is implemented as if it was a void * parameter—that is, you pass the address of the variable that you want to hold a copy of the instance variable. The problem is that the implementation ignores the size of the instance variable and just does a pointer copy. So anything that's the same size as a pointer will work perfectly. If you're running on a 32-bit architecture, only the high 32 bits will be copied. (You should witness the same behavior with a long long instance variable as well.)
The solution is to use the primary API, key-value coding, using -valueForKey:.
The other solution: If you wanted to write a fixed version, say as a category for NSObject, it would look something like this:
#implementation NSObject (InstanceVariableForKey)
- (void *)instanceVariableForKey:(NSString *)aKey {
if (aKey) {
Ivar ivar = object_getInstanceVariable(self, [aKey UTF8String], NULL);
if (ivar) {
return (void *)((char *)self + ivar_getOffset(ivar));
}
}
return NULL;
}
#end
Then your code would look like this:
double myDoubleValue = *(double *)[self instanceVariableForKey:#"someDouble"];
What about using valueForKey:?
NSNumber * value = [self valueForKey:[NSString stringWithUTF8String:ivar_getName(tmpIvar)]];
NSLog(#"Double value: %f", [value doubleValue];
Note: this requires you to have a "someFloat" method. If you want to use setValue:forKey:, you'll also need the "setSomeFloat:" method. This is easily implemented by declaring the ivar as an #property and synthesizing it.