I have created a class for using NSURLSession in objective which calls remote server and gets the data.
Server.h File:
@protocol SeverDelegate;
@interface Server : NSObject {
NSString * _urlString;
NSURLSession * _session;
}
@property(nonatomic, weak)id <ServerDelegate> delegate;
+(id) initWithUrl: (NSString *) urlString;
- void getData();
@end
@protocol ServerDelegate<NSObject>
@optional
-(void) success:(Server *) server;
@end
Server.m File:
@implementation Server
@synthesis delegate;
+(id) initWithUrl: (NSString *) urlString {
if (self = [super init]) {
_urlString = urlString;
}
}
-(void) getDataFromServer {
NSURL *url = [NSURL URLWithString: _urlString];
__weak __typeof(self) weakSelf = self;
NSURLSessionDataTask *dataTask = [_session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error != nil) {
}
if (data != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
_responseData = data;
if ([weakSelf.delegate
respondsToSelector:@selector(success:)]) {
[weakSelf.delegate success:self]; // here is memory leak
}
});
}
}];
[dataTask resume];
[_session finishTasksAndInvalidate];
}
This called from another class like this:
Server *request = [Server initWithURL:downloadUrl];
request.delegate = self;
[request getData];
#Pragma mark Delegate method:
-(void) success:(Server *) server {
// do other stuff
}
In order to avoid retain cycle, I have used weakSelf but for passing self after getting data from server, there is memory leak. It can be avoided by using weakSelf here also, but it will not pass the Server object to the delegate method implemented in calling class.
So, what should be done in order to remove the memory leak and pass the server object to delegate method implemented in another class?
You have defined tantalizer incorrectly! This line is VERY WRONG:
+(id) initWithUrl: (NSString *) urlString {
+
means this is a class method not an object method. In this case self
represent a class not an object and class lifetime is eternal. I'm surprised that it compiles and you have access to _urlString
symbol.
Fix it like this:
-(instancetype) initWithUrl: (NSString *) urlString {
if (self = [super init]) {
_urlString = urlString;
}
}
Also when you are calling a delegate you have captured a self
creating permanent strong reference cycle. So it should go like this:
-(void) getDataFromServer {
NSURL *url = [NSURL URLWithString: _urlString];
__weak Server *weakSelf = self;
NSURLSessionDataTask *dataTask = [_session dataTaskWithURL:url
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error != nil) {
// do something here
}
if (data != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
Server *strongSelf = weakSelf;
// _responseData = data; // here you are also using self and creating a cycle since you are accessing object field
id<ServerDelegate> delegate = strongSelf.delegate;
if ([delegate respondsToSelector:@selector(success:)]) {
[delegate success: strongSelf]; // here was a cycle
}
});
}
}];
[dataTask resume];
Disclaimer: this code is still terrible I've just corrected it to get rid of strong reference cycle.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.