2012-06-26 34 views
5

私はUIViewController thatをモーダルに提示しています。メモリ割り当てInstrumentを見ると、ビューが表示されるとメモリ使用量が増えますが、メモリが解放されてもメモリは解放されません。 ビューを開閉し続けると、メモリはちょうど高くなっています。 インストゥルメントはメモリリークを報告しません! これを引き起こす原因は何ですか? View Controllerコードは下にあります(私はdidSelectRowコードをスキップしました)。 Deallocは常に呼び出されます。UITableViewでUIViewControllerのメモリリークが発生する可能性があります

EDIT - ------------- 何かがないようです.H

#import <UIKit/UIKit.h> 
@class OutlineTextUILabel; 

@interface StoreViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> { 

    int starCount; 
    NSMutableArray *_singleUseArray; 
    NSMutableArray *_fullUseArray; 

} 

@property (weak, nonatomic) IBOutlet UITableView *tableView; 
@property (weak, nonatomic) IBOutlet OutlineTextUILabel *starCountLbl; 
- (IBAction)exitBtnPressed:(id)sender; 

.M

#import "StoreViewController.h" 
#import "NSUserDefaults+MPSecureUserDefaults.h" 
#import "PowerUpCell.h" 
#import "OutlineTextUILabel.h" 
#import "PowerUpSingleton.h" 
#import "PowerUp.h" 

#define kPrefsNumberOfStars    @"numberOfStars" 

@interface StoreViewController() 

@end 

@implementation StoreViewController 
@synthesize tableView = _tableView; 
@synthesize starCountLbl; 

#pragma mark View Methods 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    // Display star count 
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; 
    BOOL valid = NO; 
    starCount = [prefs secureIntegerForKey:kPrefsNumberOfStars valid:&valid]; 
    if (!valid) { 
     NSLog(@"Stars Tampered With!"); 
     self.starCountLbl.text = @"Err"; 
    } else { 
     self.starCountLbl.text = [NSString stringWithFormat:@"%d",starCount]; 
    } 

    // Tableview setup 
    CGRect frame2 = CGRectMake(0, 0, 320, 40); 
    UIView *footer = [[UIView alloc] initWithFrame:frame2]; 
    footer.backgroundColor = [UIColor clearColor]; 
    self.tableView.tableFooterView = footer; 
    self.tableView.opaque = NO; 
    self.tableView.backgroundView = nil; 
} 

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:YES]; 

    if (![[PowerUpSingleton sharedList] refreshArray]) { 
     NSLog(@"Error, %s",__FUNCTION__); 
    } else { 
     [self performSelectorOnMainThread:@selector(workOutSingleUseToDisplay) withObject:nil waitUntilDone:YES]; 
     [self performSelectorOnMainThread:@selector(workOutFullUseToDisplay) withObject:nil waitUntilDone:YES]; 
     [self.tableView reloadData]; 
    } 
} 

- (void)workOutSingleUseToDisplay 
{ 
    _singleUseArray = [[NSMutableArray alloc] init]; 
    for (PowerUp *pu in [[PowerUpSingleton sharedList] sharedArray]) { 
     if (!pu.fullUnlock) { 
      [_singleUseArray addObject:pu]; 
     } 
    } 
} 

- (void)workOutFullUseToDisplay 
{ 
    _fullUseArray = [[NSMutableArray alloc] init]; 
    for (PowerUp *pu in [[PowerUpSingleton sharedList] sharedArray]) { 
     if (pu.prefFullName != nil) { 
      [_fullUseArray addObject:pu]; 
     } 
    } 

} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown); 
} 

- (void)viewDidUnload { 
    [self setTableView:nil]; 
    [self setStarCountLbl:nil]; 
    [super viewDidUnload]; 
} 

#pragma mark TableView Setup Methods 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return 2; 
} 

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 
{ 
    if (section == 0) { 
     return @"Single Use"; 
    } else if (section == 1) { 
     return @"Use forever"; 
    } 

    return nil; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    if (section == 0) { 
     return [_singleUseArray count]; 
    } else if (section == 1) { 
     return [_fullUseArray count]; 
    } 

    return 0; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSString *cellIdentifier; 
    if (indexPath.section == 0) { 
     cellIdentifier = @"powerUpCellSingleUse"; 
    } else if (indexPath.section == 1) { 
     cellIdentifier = @"powerUpCell"; 
    } 

    PowerUpCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 
    if (cell == nil) { 
     cell = [[PowerUpCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 
    } 

    if (indexPath.section == 0) { 
     PowerUp *tmpPU = [_singleUseArray objectAtIndex:indexPath.row]; 
     cell.descriptionLbl.text = tmpPU.displayName; 
     int cost = tmpPU.costSingle; 
     cell.costLbl.text = [NSString stringWithFormat:@"%d",cost]; 
     if (cost > starCount) { 
      cell.costLbl.textColor = [UIColor redColor]; 
     } else { 
      cell.costLbl.textColor = [UIColor blueColor]; 
     } 
     int howMany = tmpPU.numberOwned; 
     cell.howManyLbl.text = [NSString stringWithFormat:@"%d",howMany]; 

    } else if (indexPath.section == 1) { 
     PowerUp *tmpPU = [_fullUseArray objectAtIndex:indexPath.row]; 
     cell.descriptionLbl.text = tmpPU.displayName; 
     int cost = tmpPU.costFull; 
     cell.costLbl.text = [NSString stringWithFormat:@"%d",cost]; 
     if (cost > starCount) { 
      cell.costLbl.textColor = [UIColor redColor]; 
     } else { 
      cell.costLbl.textColor = [UIColor blueColor]; 
     } 
     if (tmpPU.fullUnlock) { 
      cell.costLbl.textColor = [UIColor greenColor]; 
      cell.costLbl.text = @"---"; 
     } 
    } 

    return cell; 
} 

#pragma mark - 

- (IBAction)exitBtnPressed:(id)sender 
{ 
    [self dismissModalViewControllerAnimated:YES]; 
} 

- (void)dealloc 
{ 
    NSLog(@"%s",__FUNCTION__); 
    self.tableView = nil; 
    self.starCountLbl = nil; 
} 

@end 

EDIT私はARC

を使用していますそうだ。 NSLogをセルのallocに追加しました。セルが作成されても、呼び出されることはありません!

PowerUpCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 
    if (cell == nil) { 
     NSLog(@"new cell"); 
     cell = [[PowerUpCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 
    } 

EDIT 7月1日------ 私はナビゲーションコントローラを追加し、今の代わりに、モーダルのプッシュを使用して、この問題はまだここできました。 私は、インストゥルメントでヒープショットを撮っていますが、ビュー間で前後に移動することで、セルがまだぶら下がっているように見えます。このスクリーンショットでは、 screen shot

+0

inside viewWillあなたはperformOnMainThreadを使用します。これは不要ですが、viewWillAppearはメインスレッドで発生します。 –

+0

私はwaitUntilDone:YESを設定できるので、このメソッドを使用したので、テーブルを描画する前に配列が塗りつぶされました。 – Darren

+0

これを試してください:[self workOutFullUseToDisplay]。あなたはObjective-Cが連続していることを実感していますか? –

答えて

3

あなたがweakとしてあなたIBOutletsを使用しますので、代わりにstrongを使用しての、です。

私は実際には、この種の動作を警告する必要があるので、これはXCode環境の欠陥だと考えています。

ベストプラクティスとして、このような厄介な落とし穴を避けるために、Interface Builderのコードにビューをドラッグして、XCodeにIBOutletを生成させることをお勧めします。これはにオブジェクトを原因として

1)、あなたはゾンビは、あなたがデバッグしている間にオン持っていないことを確認してください:あなたはすでにこれを回避する方法をいくつか見つけましたが、念のために、このことができますように

+0

はい、私は上記のように言いました。また、弱いものより後ろに残す可能性が強いと思った!弱い参照オブジェクトは、ビューを削除すると削除されると思った。 – Darren

+1

それは実際に依存します。 FileOwnerが所有するIBOutletには強力なリンクを使用し、サブビューで使用されるIBOutletには弱いリンクを使用する必要があります。 https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs。html#// apple_ref/doc/uid/10000051i-CH4-SW6 iOS(OS Xではなく)に関連する部分に注意してください。 – Gilbert

+2

私は、あなたの特定のケースでは、UITableViewセルに強いリンクを作成し、tableview(superview)を参照しました。もう一方の端では、UITableview(これは弱い)がセルを参照していましたが、いずれのセルもデアロックできませんでした – Gilbert

0

[EDIT]

あなたのviewWillAppearメソッドでは、あなたがあなたのelse節内を移動する頻度を確認するためにプリントアウトしています。私にはあなたのworkOutSingleUseToDisplayメソッドとworkOutFullUseToDisplayメソッドを呼び出すようです。それらを呼び出すたびに_singleUseArrayと_fullUseArrayを割り当てています。あなたがビューの内外に移動しただけで、それがdeallocを呼び出すわけではなく、現在の配列を自動的に解放するということではありません。私があなたが見ていると思うのは、あなたがビューから外に出ても、2つの配列を解放するのではなく、それらを再割り当てしようとしているということです。

[ORIGINAL] あなたのviewDidLoadでは、あなたはallocを実行します。あなたのdeallocでは、私は[フッターリリース]が表示されません。これはあなたのリークかもしれません!また私は私がanwerを得たかはわからない

+0

私はARCを使用しているため、手動では解放できません。 _singleUseArray = nilを追加しようとしました。 _fullUseArray = nil; フッター= nil; deallocに変更はありません。 – Darren

+1

最初の投稿にARCについて教えてください。答えが確定していると思います。 – Martin

+0

申し訳ありません。それを質問に追加します。 2つの配列のallocをviewDidLoadに移動したので、それらは必ず1回だけ呼び出されますが、メモリパターンは同じです。 ビューコントローラdeallocは、すべてのクローズ時に呼び出されます。 他のアイデアはありますか? – Darren

0

あなた_singleUseArrayや_fullUseArray配列の解放を参照してください、しかし、あなたのコード内で奇妙な何かがあります:

あなたが弱いのプロパティを使用している:

@property (weak, nonatomic) IBOutlet UITableView *tableView; 
@property (weak, nonatomic) IBOutlet OutlineTextUILabel *starCountLbl; 
は、

しかし、the doc(検索が「弱い」)によれば、weakプロポーザルはassignと非常によく似ています。

あなたがDEALLOCでは、あなたが

self.tableView = nil; 
self.starCountLbl = nil; 

が、私はこれらのプロパティの生成セッターがすべてでそれらを解放しないことをかなり確信しています!

しかし、あなたのようなあなたの特性を宣言した場合:

@property (nonatomic, retain) IBOutlet UITableView *tableView; 
@property (nonatomic, retain) IBOutlet OutlineTextUILabel *starCountLbl; 

生成セッターが

(void)setTableView(UITableView *)newTableView { 
    [tableView release]; 
    if(newTableView != nil) 
     tableView = [newTableView retain]; 
} 

ようになるとあなたの特性が解放されるだろう。

+0

私は実際にself.tableView = nilとself.starCountLbl = nilをdeallocに追加しましたが、リリースしていないものを探していました。いずれにしても弱い参照であり、ビューコントローラが解放されたときに解放されるため、実際には必要ありません。 – Darren

0

少なくとも、リーク計測器を使用してメモリリークを監視します。 Allocations計測器は実際にメモリリークを表示しません。 Analyzeを実行すると、リークの原因となる可能性のある行が表示されます。

これはあなたのコードです:、あなたが見

PowerUpCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 
if (cell == nil) { 
    NSLog(@"new cell"); 
    cell = [[PowerUpCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 
} 

cellはこれがdequeueReusableCellWithIdentifier:のためのAPIドキュメントに記載されている... nilになるだろうされていません。

戻り値

関連付けられた識別子を持つUITableViewCellオブジェクト。再利用可能セルキューにそのようなオブジェクトが存在しない場合はnil。あなたは私が思う

NSMutableArray *_singleUseArray; 
NSMutableArray *_fullUseArray; 

を宣言した場合で、

_singleUseArray = [[NSMutableArray alloc] init]; 

_fullUseArray = [[NSMutableArray alloc] init]; 

:漏れがある場合は

とにかく、おそらく彼らは非常に起因していますデフォルトの両方に__strongの資格が割り当てられました私。私は本当にわからないが、これが問題の本当の原因になる可能性がある。代わりにこれを宣言するのはどうですか?以前の参照を削除するnilに最初に割り当てる約

_singleUseArray = [[NSMutableArray alloc] init]; 

_fullUseArray = [[NSMutableArray alloc] init]; 

方法を宣言する前にまた

NSMutableArray * __weak _singleUseArray; 
NSMutableArray * __weak _fullUseArray; 

、?

_singleUseArray = nil; 
_singleUseArray = [[NSMutableArray alloc] init]; 

_fulUseArray = nil; 
_fullUseArray = [[NSMutableArray alloc] init]; 
+0

リークツールを使用しましたが、表示するたびにメモリが増えてもリークは表示されませんでした。 – Darren

+0

アレイのinitを完全に引き出すのにはまだ問題があります:-( – Darren

+0

1つのメモリリークが表示されますが、関係はありません。責任フレーム= [NSURL(NSURL)パス] – Darren

2

が見えますそれらが解除されるべきだと思った後にハングアップします(Edit Scheme - > Run - > Diagnostics)。

2)ARCを使用しているので、ストーリーボードまたはNIBのストーリーボードまたは少なくともプロトタイプのUITableViewセルを想定していますか?その場合、dequeueReusableCellWithIdentifierコールが定義されたcellIdentifierを介してこれらのプロトタイプセルからセルを作成することがわかっているため、NSLog()が呼び出されない理由があります。かなり便利です。

PowerUpCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 
    if (cell == nil) { 
     NSLog(@"new cell"); 
     cell = [[PowerUpCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 
    } 

このUITableViewCellのキャッシュを管理して適切に解放するには、UITableViewに依存する必要があります。あなたのUITableViewがリリースされていないので、彼らはちょうど回っている可能性があります(私はあなたがそれを言っていると思いますが)。

+0

それは私を助けました! @ChrisHこれを投稿していただきありがとうございます。実際にあなたの最初のヒントは、私がいくつかの不可解な動作を追跡するのに役立ちました。このような投稿はStack Overflowをさらに良くします! – scrrr

+0

あなたは何が問題だったのですか?私は私のアプリで何かsimmilarがあるかもしれないと思う。 – Piotr

関連する問題