2017-10-12 86 views
0

我創建了一個在調用遠程服務器並獲取數據的目標中使用NSURLSession的類。從代理傳遞自己導致內存泄漏

Server.h文件:

@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文件:

@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]; 
} 

這從另一個類這樣叫:

Server *request = [Server initWithURL:downloadUrl]; 

    request.delegate = self; 

    [request getData]; 

#Pragma mark Delegate method: 
-(void) success:(Server *) server { 
    // do other stuff 
} 

爲了避免保留週期,我使用weakSelf,但從服務器獲取數據後傳遞自己的內存泄漏。它也可以通過在這裏使用weakSelf來避免,但它不會將Server對象傳遞給在調用類中實現的委託方法。

那麼,應該做些什麼來消除內存泄漏並將服務器對象傳遞給另一個類中實現的委託方法?

回答

0

您已經錯誤地定義了tantalizer! 這條線是非常錯誤:

+(id) initWithUrl: (NSString *) urlString { 

+意味着這是一個類的方法不是一個對象的方法。在這種情況下,self表示一個類不是一個對象,而類的生命週期是永恆的。 我很驚訝,它編譯和你有訪問_urlString符號。

修復這樣的:

-(instancetype) initWithUrl: (NSString *) urlString { 
    if (self = [super init]) { 
     _urlString = urlString; 
    } 
} 

此外,當你調用一個委託你捕捉一個self創建永久很強的參考週期。所以它應該是這樣的:

-(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]; 

聲明:此代碼仍然可怕我剛糾正它,擺脫強大的參考週期。

+0

沒有+(id)initWithUrl:(NSString *)urlString; 我該如何撥打電話? Server * request = [Server initWithURL:downloadUrl]; – bthapa

+0

'Server * server = [[Server alloc] initWithUrl:url];'。你的問題證明你應該閱讀/觀察Objective C基礎知識。 –