ios - ARC Async Block Best Practices -
my application sends lots of messages via http
requests. wrote simple wrapper around http request has primary method fire off request , return nsdata
result.
it looks this:
- (void)sendrequest:(nsurlrequest *)request { [[[nsurlsession sharedsession] datataskwithrequest:request completionhandler:^(nsdata *data, nsurlresponse *response, nserror *error) { nslog(@"---->> request returned"); if (_delegate == nil) return; if (error == nil) { // forward along [_delegate requestreturnedresult:data withresponse:response]; } else { // error occurred [_delegate requestreturnederror:error withresponse:response]; } }] resume]; }
this httprequesthelper
object ivar
of message abstraction object outboundmessage
packages data , sends out.
i think have messagesender
object takes data, creates outboundmessage
object, , sends out.
this abstraction works nicely except think i'm bumping issue arc.
when calls [messagesender send:]
, alloc
outboundmessage
, send out.
what see via nslog
outboundmessage
cleaned (presumably when send
exits, see httprequesthelper
cleaned up. then see nslog
in completion handler of datataskwithrequest
.
this indicates me around request helper cleaned prior http request completing. can imagine, try bubble response via delegate
, exc_bad_access
.
i can think of creative ways prevent deallocation , prevent i'd know conceptually best practices handling pattern of firing off messages enveloping objects clean after request done.
thanks.
update each wrapper object using initwithdelegate:self
style patterns , noticed delegates being saved this:
@property (nonatomic, assign) id<httprequesterdelegate> delegate;
i changed them strong
, seems correct i'm not sure if i'm leaking memory or if there's more optimal approach.
first of all, nsurlsessiondatatask
object, created nsurlsession - datataskwithrequest:completionhandler:
method, retains completionhandler
block object. block object isn't released until block executed when data task finished.
next, blocks capture(retain) local variables automatically. following line in code
if (_delegate == nil)
is same as
if (self.delegate == nil)
if delegate
property strong
@property (nonatomic, strong) id<httprequesterdelegate> delegate;
then self
retained block. in case, self
httprequesthelper
object. httprequesthelper
object , delegate
object live long data task finished. it's safe.
but delegate
property assign
@property (nonatomic, assign) id<httprequesterdelegate> delegate;
it same __unsafe_unretained
. blocks doesn't retain __unsafe_unretained
object @ all. self
wasn't retained, released before data task finished.
added
in case, can use local variable retain delegate
object. because completionhandler uses delegate
object, not httprequesthelper
object itself.
id<httprequesterdelegate> delegate = _delegate; [[[nsurlsession sharedsession] datataskwithrequest:request completionhandler:^(nsdata *data, nsurlresponse *response, nserror *error) { nslog(@"---->> request returned"); /* * use `delegate` instead of `_delegate` */ if (delegate == nil) return; ...
in case, attribute of delegate
property strong or assign, doesn't matter @ all.
Comments
Post a Comment