5

このリンクで説明されているものに基づいたフレームワークに連続したビューをロードする iPhone アプリケーションがあります(基本的にはViewController、メソッドを使用して追加のビューをロード/削除するメインdisplayView)。私のアプリケーションでは、NIB を使用しています(例のリンクではコード化されたビューを使用しています) ViewControllers

Instruments でのデバッグではリークは表示されませんが、セクション (View.xib を含む ViewController) に出入りすると、nib はメモリ内に残るため、数回のイン/アウトの後、メモリが蓄積し始めます。

ペン先がアンロードされていないことはわかっています。これは、ほとんどプログラムで作成されたもの (IB には何もない) と、IB で作成された画像とボタンがあるためです。大きい方が最初にロードされ、小さい方が次にロードされます。インスツルメントへの割り当てが減少することが予想されます。

どうすればこれを防ぐことができますか?

私の構造は次のとおりです。以下にいくつかのコメントがあります。

`MyAppDelegate.h`

#import <UIKit/UIKit.h>

@class RootViewController;

@interface MyAppDelegate : NSObject <UIApplicationDelegate> {
 UIWindow *window;
 RootViewController *viewController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet RootViewController *viewController;

-(void) displayView:(int)intNewView;

@end

`MyAppDelegate.m`

#import "MyAppDelegate.h"
#import "RootViewController.h"

@implementation MyAppDelegate

@synthesize window;
@synthesize viewController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 [window addSubview:viewController.view];
 [window makeKeyAndVisible];
 return YES;
}

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}

-(void) displayView:(int)intNewView {
 [viewController displayView:intNewView];
}

- (void)dealloc {
 [viewController release];
 [window release];
 [super dealloc];
}

@end

このコントローラは、サブビューのロード/削除を処理します:

`RootViewController.h`

#import <UIKit/UIKit.h>

@interface RootViewController : UIViewController {
}

- (void) displayView:(int)intNewView;

@end

`RootViewController.m`

#import "RootViewController.h"
#import "ViewController.h"

@implementation RootViewController

UIViewController *currentView;

- (void) displayView:(int)intNewView {
 NSLog(@"%i", intNewView);
 [currentView.view removeFromSuperview];
 [currentView release];
 switch (intNewView) {
  case 1:
   currentView = [[ViewController alloc] initWithNibName:@"View" bundle:nil];
   break;
 }

 [self.view addSubview:currentView.view];
}

- (void)viewDidLoad {
 currentView = [[ViewController alloc]
   initWithNibName:@"View" bundle:nil];
 [self.view addSubview:currentView.view];
 [super viewDidLoad];
}

- (void)dealloc {
 [currentView release];
 [super dealloc];
}

@end

case私が持っている「詳細」 と同じ数がありViewControllersます(現在は3つcaseですが、これは10以上になります)。この構造の目的は、アプリケーションのある「セクション」から別の「セクション」に簡単に移動することです (NavBar コントローラーまたは TabBar コントローラーは、私の特定のニーズには合いません)。

`ViewController.h`

// Generic View Controller Example

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController {
 UIImageView *_image1;
 UIImageView *_image2;
 NSTimer *_theTimer;
}

@property (nonatomic, retain) IBOutlet UIImageView *image1;
@property (nonatomic, retain) IBOutlet UIImageView *image2;
@property (nonatomic, retain) NSTimer *theTimer;

@end

`ViewController.m`

#import "ViewController.h"
#import "MyAppDelegate.h"

@synthesize image1 = _image1, image2 = _image2, theTimer = _theTimer;

- (void)loadMenu {
 [self.theTimer invalidate];
 self.theTimer = nil;
 MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
 [appDelegate displayView:2];
} 

-(void)setView:(UIView*)aView {
 if (!aView){
  self.image1 = nil;
  self.image2 = nil;
 }
 [super setView:aView];
}

- (void)viewDidLoad {
 //some code
 [super viewDidLoad];
}

- (void)viewDidUnload {
 self.image1 = nil;
 self.image2 = nil;
}

- (void)dealloc {
 NSLog(@"dealloc called");
 [self.theTimer invalidate];
 [self.theTimer release];
 [self.image1 release];
 [self.image2 release];
 [super dealloc];
}

に注目しNSLogdeallocください。これは呼び出されています (コンソールで確認できます) が、nib に必要なメモリが解放されていません (新しい nib がロードされるため、Instruments はセクションを離れるときにメモリ割り当ての増加を示します)。

どんな助けでも大歓迎です。何百万もの異なることを試しましたが、ペン先をアンロードできません。

4

2 に答える 2

6

100 万回の試行を経て、ようやくこのフォーラムにたどり着きました。

それは述べています:

IB で割り当てられた画像は、 を使用して画像ビューに読み込まれるようimageNamedです。imageNamed画像をアンロード可能にする方法でキャッシュします。で画像を読み込んでviewDidLoadinitWithContentsOfFileビューに割り当てることができます。

私が読んだ他の場所imageNamedは悪魔なので、画像をそのようにロードしたくありません。

(ところで、これは私が使用しているiPhone OS 3.1です)

私が最終的に得たのはUIImageView、IBにそのまま残していますが、.image値は空です。変更されたコードは次のようなものです。

- (void)viewDidLoad {
    NSString *path = [NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] resourcePath], @"myImageThatBeforeWasAValueinIB.jpg"];
    UIImage *image = [UIImage imageWithContentsOfFile:path];
    outlet.image = image;
    // do the rest of my stuff as it was
    [super viewDidLoad];
}

- (void)dealloc {
    outlet.image = nil;
    [outlet release], outlet = nil;
    [super dealloc];
}

そして今、すべてが魔法のように機能します!ペン先をアンロードしたり、メモリ警告が表示されたりすると、メモリが回復します。

したがってIBOutlets、 for UIImageViews があり、メモリが懸念される場合 (常にそうだと思います)、IB で必要なすべてを設計し、それらをコンセントに接続するときが来たら、IB のイメージ参照を削除してから作成できます。コード。IB はアプリのレイアウトに非常に適しています。コードですべてのことをしなければならないのは残念ですが、まだテストしていませんが、ペン先を目的の C コードに変換するこの素晴らしいユーティリティも見つけました。

于 2009-10-01T07:47:16.170 に答える
0

dealloc でアウトレット変数を nil に設定しようとしましたか? setView メソッドを正しく実装していますが、dealloc ではなく viewDidUnload メソッドでアウトレット変数を nil に設定しています。hereで説明したように、次のように dealloc を実装する必要があります。

- (void)setView:(UIView *)aView {
    if (!aView) { // view is being set to nil
        // set outlets to nil, e.g.
        self.anOutlet = nil;
    }
    // Invoke super's implementation last
    [super setView:aView];
}

- (void)dealloc {
    // release outlets and set outlet variables to nil
    [anOutlet release], anOutlet = nil;
    [super dealloc];
}

EDIT:アウトレットがUIImageViewsの場合、あなたがする必要があるかもしれません

anOutlet.image = nil;

UIImage のインスタンス イメージ プロパティを設定すると、UIImage のインスタンスの保持カウントが 1 増えるためです。

于 2009-09-27T22:05:56.650 に答える