问题
Is it possible (and if so, safe) to create/use a block which takes a double pointer as an argument?
For instance:
- (void)methodWithBlock:(void (^)(NSError **error))block;
Additional context, research, and questions:
- I'm using ARC.
- When I declare the method above and attempt to call it, XCode autocompletes my method invocation as follows:
[self methodWithBlock:^(NSError *__autoreleasing *error) {}];
What does__autoreleasing
mean here and why is it being added? I presume it has something to do with ARC. - If this is possible and safe, can the pointer still be dereferenced in the block as it would be anywhere else?
- In general, what are the important differences between doing what I'm describing, and simply passing a double pointer as a method parameter (e.g.
- (void)methodWithDoublePointer:(NSError **)error;
)? What special considerations, if any, should be taken into account (again assuming this is possible at all)?
回答1:
The answers are both Yes & No...
At a base level passing pointers to pointers to blocks is no different than passing them to methods; and, with the usual proviso that your pointers must be valid, is perfectly OK.
However that __autoreleasing
is very significant here and is tied up with ARC and pass-by-writeback. Whether using the block will work as expected will be dependent on context as the compiler often uses hidden variables when passing parameters of type NSError * __autoreleasing *
as part of the pass-by-writeback implementation.
If pass-by-writeback is not what you need, or is unsuitable, you may wish to declare you block as taking a different type, such as NSError * __strong *
. Read this answer which explains what happens under the hood, that should help you decide whether in your context the block declaration is good.
In summary (a) declaring the block is fine, but (b) you need to understand how it may be called and may need to change the signature.
回答2:
yes, pointers are always just pointers. you only need to make sure you dereference it before sending it a message (assuming objc object).
Also be aware that the pointer may be nil. always check it before trying to dereference it or what have you.
As @verec mentioned if you are using ARC you should declare the parameter as __autoreleasing
according to the docs
__autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return.
remember id is a pointer to an object so that is saying object**
there is no difference between passing pointers to pointers to methods or blocks.
回答3:
warning: untested
For the sake of argument, let's start with:
typedef NSError * NSErrorPtr ;
- (void) foo: (NSErrorPtr *) errPtr {
*errorPtr = [NSError new] ;
}
errPtr isn't declared either __weak nor __strong.
So, according to ARC, even though its contents is allocated within foo
the responsibility for releasing it has to reside somewhere.
Where?
Note that this not a property of double pointers per se. But of your pattern of allocation.
consider:
int ** arrayOfarrayOfInts = {
{1, 2, 3, 4}
, {5, 6, 7, 8}
} ;
- (void) incrementElement: (int **) elem {
++(**elem) ;
}
- (void) bumpFirstColByOne {
for (int i = 0 ; i < 2 ; ++ i) {
int * arrayOfInt = arrayOfarrayOfInts[i] ;
int ** second = &arrayOfInt[0] ;
[self incrementElement: second] ;
}
}
No __autoreleasing needed here because no allocation is taking place ...
来源:https://stackoverflow.com/questions/19504962/double-pointer-as-objective-c-block-parameter