Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C - Change the address of a passed-in object pointer

Let's say that I've got a method like:

- (void)reassignPassedObject:(void *)block;

and it's called as in

NSLog(@"self 1: %@", self);
[myController reassignPassedObject:^(){return self;}];
NSLog(@"self 2: %@", self);

I want to reassign the 'self' reference to another object, like this:

- (void)reassignPassedObject:(void *)block {
    id holder = block();

    if ( YES ) {
        id newObject = nil; //or NSString or NSArray
        //do something such that output second log is "self 2: (newObject...)"
    }
}

Is this possible?

It seems like it should be fair game since we're just talking about reassigning pointers. I will worry about release/retain in a specific implementation. The challenge here that confuses me is:

  • It involves id instead of straight pointers
  • It involves a block-passed variable
  • It involves having to somehow reassign the address of the object inside block() where all we have access to is the local holder object.

Ideas?

like image 965
SG1 Avatar asked Aug 02 '11 02:08

SG1


1 Answers

First of all, don't change self inside your code, unless in the beginning of init... via self=[super init...].

And I have no idea why you want to use blocks, or what motivates you to do all this, but if you insist on changing what a pointer points to, the most standard C-based way is to pass the pointer to the variable. e.g.

-(void)changeObjectPointedBy:(id*)p{
        *p=@"foo";
}

Then this can be used as

NSString*q=@"bar";
[self changeObjectPointedBy:&q];
NSLog(@"%@",q); // prints "foo"

Note the extra & and * in the code. Before trying to abuse blocks, I'd recommend you to learn straightforward C.

If you insist on using a block, I would do:

-(void)passMyObjToBlock:(void(^)(id))block
{
     block(@"foo");
}

which can be used as

__block NSString*p=@"bar";
[self passMyObjToBlock:^(id obj){
       p=obj;
}];
NSLog(@"%@",p); //prints "foo"

Or, another way is to

-(void)reassignPassedObject:(id*(^)())block{
     id*holder=block();
     *holder=@"foo";
}

and then

id* pointerToSelf=&self;
[foo reassignPassedObject:^(){return pointerToSelf}];
// self is now @"bar"

Note the distinction between a "pointer to the object" and a "pointer to the pointer to the object". In order to change what is pointed to by self, you need to pass the pointer to self to the function. This is a fundamental limitation of C, and there is no way you can do this without using one pair of & and *.

like image 61
Yuji Avatar answered Sep 30 '22 14:09

Yuji