Re: ARC Retain Cycles
Re: ARC Retain Cycles
- Subject: Re: ARC Retain Cycles
- From: Dave <email@hidden>
- Date: Mon, 21 Apr 2014 15:12:19 +0100
Hi,
Amazing! I ***think*** I’ve found it! You were right, The profiler/leaks analyzer works really well, thanks for the tips!
myNetworkOperation.pResponseNetworkDelegate or the corresponding class was the culprit!
There is a delegate handler which makes passing and calling simple delegates a doddle. This was originally non ARC.
There is a property defined:
@property (nonatomic,retain) id payloadObject;
This is after I ARCed it, before that it didn’t specify it, e.g. it was (nonatomic). I must have made it retain when I was going through the properties. I’m not sure what the default is? I assume it must have been assign for this to work originally. I did a google for this and found conflicting results, according to the Objective-C Reference Manial, it’s assign. But I’m not sure where the “Offical” Objective-C manual is located to get it from the source.
payloadObject is just used to hold a copy of the object to pass to the delegate method
After changing this, the leaks when down by a massive factor. Basically it was hanging onto *every* response from the server!
I’m about to look through the code and see if I’ve made a similar mistake elsewhere.
There are still a few more small leaks which I’m looking at now, but this is the mainstay - thanks again!
> myDataTask has a block which retains self, and self retains myDataTask leading to a cycle,
I’m a bit confused as it what you mean. Self here is a singleton, or at least there could be N of them (but actually there is only one in this case), but they stay around for the duration of the Application and never get released. In theory they could do I suppose, but there’s no need for them to be at the moment.
NSURLSessionDataTask* myDataTask;
Is declared locally, I thought that it would get released when the “executeSyncRequestWithParameters:” method returns, which is after the code block does:
dispatch_group_leave(myDispatchGroup);
(oops! I’ve just relazied I left out an import chunk of code. The method is a lot bigger that the code I posted because it handling a lot of other cases that are not used for this problem. I’ve posted the code again.
This method is always called on a background thread, it issues a request, then blocks until the response comes back. This seems to work ok and I didn’t see this as a cycle in Leaks.
More later once I have had a chance to do some more digging.
Once thing I’m not sure about is if
dispatch_group_t myDispatchGroup;
Should be a local or property or if it matters. Originally it was a property, but I changed it. I wondering if I should have left it alone?
All the Best
Dave
-(JMNetworkCommandResponse*) executeSyncRequestWithParameters:(JMNetworkRequestParams*) theRequestParameters
{
JMNetworkCommandResponse* myNetworkResponse;
long myTimeOutStatus;
dispatch_group_t myDispatchGroup;
NSURL* myURL;
NSMutableURLRequest* myURLRequest;
NSURLSessionDataTask* myDataTask;
NSString* myParameterString;
NSData* myBodyData;
JMNetworkRequestHTTPDataMethod myTransferMethod;
JMNetworkOperationiOS7* myNetworkOperation;
myURL = [[NSURL alloc] initWithString:theRequestParameters.pRequestURLString];
if (myURL == nil)
return nil;
myNetworkOperation = [self newOperationWithRequestParameters:theRequestParameters];
myDispatchGroup = dispatch_group_create();
dispatch_group_enter(myDispatchGroup);
myDataTask = [self.pNetworkCommandURLSession dataTaskWithURL:myURL completionHandler:^(NSData* theResponseData,NSURLResponse* theURLResponse,NSError* theErrorInfo)
{
JMNetworkCommandResponse* myNewNetworkResponse;
NSHTTPURLResponse* myHTTPURLResponse;
NSInteger myHTTPStatus;
myHTTPURLResponse = (NSHTTPURLResponse*) theURLResponse;
myHTTPStatus = myHTTPURLResponse.statusCode;
myNewNetworkResponse = [self newNetworkResponseWithRequestParameters:theRequestParameters andURLResponse:theURLResponse andResponseData:theResponseData andErrorInfo:theErrorInfo];
[self setNetworkResponse:myNewNetworkResponse withRequestID:theRequestParameters.pRequestID];
[myNetworkOperation.pResponseNetworkDelegate performDelegateSelectorOnMainThreadWithObject:myNewNetworkResponse];
dispatch_group_leave(myDispatchGroup);
}
];
[myDataTask resume];
// dispatch_release(myDispatchGroup);
//************************************************************************************************************************************************
myTimeOutStatus = dispatch_group_wait(myDispatchGroup,dispatch_time(DISPATCH_TIME_NOW,kLTWNetworkOperationTimeOutPeriodNS));
if (myTimeOutStatus != 0)
{
myNetworkResponse = [self newErrorNetworkResponseWithErrorCode:kLTWNetworkManagerSyncTimeoutError andErrorMessage:NSLocalizedString(@"kLTWNetworkManagerSyncTimeoutError",@"executeSyncRequestWithParameters - Sync Request Timed Out")];
[self setNetworkResponse:myNetworkResponse withRequestID:theRequestParameters.pRequestID];
dispatch_group_leave(myDispatchGroup);
}
//************************************************************************************************************************************************
//**
//** Extract the Response from the Dictionary and Reset the Request
//**
myNetworkResponse = [self getNetworkResponseWithRequestID:theRequestParameters.pRequestID];
[self removeNetworkResponseWithRequestID:theRequestParameters.pRequestID];
return myNetworkResponse;
}
On 21 Apr 2014, at 13:39, Roland King <email@hidden> wrote:
> myDataTask has a block which retains self, and self retains myDataTask leading to a cycle, would be my first thought. If nothing else also holds onto that, you'd expect leaks to find it and give you a nice diagram showing how it all hangs together, I believe leaks tracks dispatch_* (although I've never tried it, they are full ARC'y objects now).
>
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden