Function to swap pointers in Objective-C - objective-c

- (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.

Related

Pointer to pointer parameter in Swift function

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

Varying Return Type Objective-C or c

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");

Objective-C: Result of casting id to BOOL?

Does the following function return YES if object != nil?
- (BOOL)boolForObject:(id)object {
return (BOOL)object;
}
I've tested with object = [[NSObject alloc] init] but got mixed results.
A pointer is larger than a BOOL, so when you cast it will truncate and take only the 8 least significant bits of the pointer and make it a BOOL. If those bits all happen to be zero then that is equivalent to NO.
So to answer your question, no it does not (well sometimes it will depending on the pointer value)
Here's an example with using Xcode 5.1.1 on 32 bit architecture:
void* p = (void*)0xfeeeff00;
BOOL b = (BOOL)p;
NSLog(#"p=%08x (%lu), b=%08x (%lu)", (uint32_t)p, sizeof p, (uint32_t)b, sizeof b);
It prints out:
p=feeeff00 (4), b=00000000 (1)
What is the actual purpose of your method?
If it's just to check whether an object is nil or not, why not do it like this:
- (BOOL)boolForObject:(id)object
{
return (object != nil);
}
It's more obvious what the result will be.
You could also do:
return !!object;
I don't think so, but
return object != nil;
will.

Is it safe to use pointers to change values in blocks?

I've started using blocks, and one of the first things I encountered is an inability to set values which are captured by the closure. This is fine, I've been using C/C++ a long time. I'll just use pointers!
MyObject* bestObj = nil;
float bestDist= 10000.f;
MyObject **pBestObj = &bestObj;
float* pBestDist = &bestDist;
[self testObjects:class block:^(MyObject* obj){
CGRect r = [obj boundingBox];
// position is captured from outside this code sample
if( CGRectContainsPoint( r, position ) )
{
float dist = GetDistance( obj, position );
if(dist < bestDist)
{
*pBestDist = dist;
*pBestObj = obj;
}
}
}];
return bestObj;
My question is, is this safe? I assume that as long as my pointer points to something that hasn't gone out of scope and that still exists, that it should work. But I'm also assuming that things that take blocks don't ever, say, run them in parallel. I know my code doesn't, but I don't know about, say, using a block with an NSArray enumerateObjectsUsingBlock call.
The 'right' way to do this would be to mark those original variables as block mutable, __block

object_getInstanceVariable works for float, int, bool, but not for double?

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.