Objective C indirect pointer bound to block fails to update direct pointer -
i have function binds indirect pointer block, , returns block later assignment direct pointer, this:
@interface someclass : nsobject @property int anint; @end @implementation someclass @end typedef void(^callbacktype)(int a); - (callbacktype)getcallbacktoassignto:(someclass **)indirectpointer { return ^(int a){ nslog(@"indirectpointer is: %p", indirectpointer); nslog(@"*indirectpointer is: %p", *indirectpointer); (*indirectpointer) = [[someclass alloc] init]; (*indirectpointer).anint = a; nslog(@"after: indirectpointer is: %p", indirectpointer); nslog(@"after: *indirectpointer is: %p", *indirectpointer); }; } - (void)iwillnotdowhatimsupposedto { someclass *directpointer = nil; callbacktype cb = [self getcallbacktoassignto:(&directpointer)]; nslog(@"directpointer pointing to: %p", directpointer); nslog(@"&directpointer pointing to: %p", &directpointer); cb(1); nslog(@"after callback directpointer is: %p", directpointer); nslog(@"after callback &directpointer is: %p", &directpointer); }
the problem while compiles , runs, action of block forgotten when block returns. printout of running [iwillnotdowhatimsupposedto] is:
directpointer pointing to: 0x0 &directpointer pointing to: 0x7fff5ce1d060 --- callback execution starts here indirectpointer pointing to: 0x7fff5ce1d050 *indirectpointer pointing to: 0x0 after assignment: indirectpointer pointing to: 0x7fff5ce1d050 after assignment: *indirectpointer pointing to: 0x61800001e1d0 --- callback returns here, , contents of pointer lost after running callback directpointer pointing to: 0x0 after running callback &directpointer pointing to: 0x7fff5ce1d060
any insights how can make callback work?
idali correct in has fact parameter "pointer autoreleasing" , passing "pointer strong". important understand why relevant here (because in cases not relevant), , has nothing reference counting per se.
you passing argument "pointer strong" (directpointer
someclass * __strong
, , &directpointer
someclass * __strong *
), parameter "pointer autoreleasing". how work? arc handles through technique called "pass-by-writeback".
basically, create temporary variable of "autoreleasing" type, assign strong pointer (if value not null), , call method pointer temporary variable. , after method returns, assigns value of variable out strong variable; approximately this:
someclass * __autoreleasing temporarypointer = directpointer; callbacktype cb = [self getcallbacktoassignto:&temporarypointer]; directpointer = temporarypointer;
note if -getcallbacktoassignto:
method used argument synchronously within own execution, there no difference between someclass * __strong *
parameter , someclass * __autoreleasing *
parameter, pass-by-writeback mechanism ensures changes have been made during execution of method reflected in strong variable tried pass pointer to.
the problem here -getcallbacktoassignto:
method stores pointer pointer data structure (a block) outlives method's execution (the block returned), allows code (the block's body) later use stored pointer try modify pointer points to. pointer points temporary variable no longer supposed used after method's execution. modifying temporary variable not reflecting on original variable.
even worse, undefined behavior. compiler sees temporary variable no longer used after pass-by-writeback scheme, , potentially allowed re-use variable's memory other things. have dangling pointer variable compiler doesn't expect still use. , problem not solved changing parameter type "pointer autoreleasing" "pointer strong" -- though rid of pass-by-writeback, may fix immediate case, fact remains block can returned out of or stored in place can used outside scope of variable pointing to, still result in using dangling pointer. basically, have careful when store or have block capture regular c pointer, because block has no way of ensuring lifetime of variable pointed (unlike if block captures objective-c object pointer, in case retains it).
Comments
Post a Comment