2017-10-12 4 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

タンタライザーが正しく定義されていません。 この行は非常に間違っている:

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

+は、これがクラスメソッドではないオブジェクトのメソッドであることを意味します。この場合、selfはオブジェクトではないクラスを表し、クラスのライフタイムは永遠です。 私はそれがコンパイルされ、_urlStringシンボルにアクセスできることに驚いています。あなたは永久的な強い参照サイクルを作成selfをキャプチャしているデリゲートを呼び出しているときにも

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

はこのようにそれを修正します。だから、次のように行く必要があります。

-(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; どうすればこのような電話をかけることができますか? サーバー* request = [サーバーinitWithURL:downloadUrl]; – bthapa

+0

'Server * server = [[Server alloc] initWithUrl:url];'。あなたの質問は、あなたがObjective Cの基本について何かを読んだり、見るべきであることを証明しています。 –

関連する問題