Double pointer as Objective-C block parameter

被刻印的时光 ゝ 提交于 2019-12-12 07:58:35

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!