恥知らずのウェブエンジニア -web engineer, shameless

これは一歩を踏み出すことができない者たちのブログ

ios WebView を TableCellで表示した際にメモリーリークした時の対処

ついにきた。

iosアプリを開発していたら、
実機テスト中に動作が重くなり、アプリがクラッシュした。

クラッシュしたのは前回実装したテーブル更新機能と、
追加で実装しようとしていたテーブルのデータ追加機能をさわっていた時。
ios UIRefreshControlでテーブルを引っ張ってからの更新 - 恥知らずのウェブエンジニア

xcodeのdebug menuのmemoryをみていくと
データ更新・追加を行うともりもりメモリを食っていく・・・
しばらく放っておいても全然開放されない・・・

まず調べた順番について、

  • これは世に言う循環参照か?!

 ⇒試しにすべてweakに設定したみたが変化なし。っていうか
  strong,weakの使い分けがしっくりきてないがこれはまた別の時に。

  • セルが使い回せていない?!

 ⇒セルを使い回していると思いきやできていない??
下記のようにNSLogmを入れてみる。
結果大丈夫そう・・・

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = @"tableCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil)
    {
        NSLog(@"NO REUSE CELL!!");
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }
        
    return cell;
}
  • もんもんとした。
  • 下のページに行き当たる

 objective c - How to remove a subview from a cell's content view? - Stack Overflow
 ⇒どうやらtable cellの中に入れていた、webViewに問題があるっぽい。
  確かにそう言われるとcellは使い回しているが、
  中のwebViewがそのままならデータの更新・追加の際にもりもりメモリ食うのも納得できる。

下記のようにtagを指定してwebViewを入れる。
そして入れる前に該当のtagがあったら削除するようにしてみた。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = @"tableCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil)
    {
        NSLog(@"NO REUSE CELL!!");
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }
    
    NSString *hogeURL = [NSURL URLWithString:@"hoge.moe"];
    CGRect frame = cell.contentView.bounds;
    frame = CGRectInset(frame, 5, 5);
    //対象tagで削除
    [[cell.contentView viewWithTag:10] removeFromSuperview];
    UIWebView *webView = [[UIWebView alloc] initWithFrame:frame];
    NSString *hogeHTML = [self createMovieHTML:hogeURL frame:frame];
    [webView loadHTMLString:movieHTML baseURL:nil];
    webView.delegate = self;
    //tagをつける
    webView.tag  = 10;
    [cell.contentView addSubview:webView];
    webView = nil;
        
    return cell;
}

これで改善されました!
更新・追加してもメモリが増加し続けることはなくなりました。

とは言え今後、cellの中に画像やテキストなどを入れた時も
いちいちtag付けて消さなきゃいけない・・・?

そんなことはないと思うが、それはその時試してみよう。




感謝致します。
f:id:ogataka50:20140514205008j:plain