9

ベースの絵本のベースのページごとに、個別.hの 、.m、およびファイルを使用しています。各ページにはアニメーション、音楽などが読み込まれ、約 4MB のメモリが必要です。Instruments では、各ページが読み込まれるたびに空きメモリが約 4MB 減少します。このメモリは、ページがめくられても決して解放されません。最終的にメモリ警告が表示されます。 インスタンス化された各ページをメモリに保持し、アンロードしないようです。そのため、ページが高速でめくられると、アプリがクラッシュします。.xibUIViewControllerUIPageViewControllerUIPageViewController

UIPageViewController前のページ、現在のページ、次のページの 3 つを除いて、すべてのページをアンロードできるようにしたいと考えています。によってインスタンス化された不要なページをアンロードするにはどうすればよいですかUIPageViewController

UIPageViewController以下は、プルするページの配列です。すべてのページ (Page1、Page2 など) は基本的に、画像ファイルをロードし、基本的なアニメーションを提供し、音楽を追加するだけです。

    //ARRAY OF PAGES    
pageArray = [[NSArray alloc] initWithObjects:
        (id)[[Page1 alloc] initWithNibName:nil bundle:nil],
            [[Page2 alloc] initWithNibName:nil bundle:nil],    
            [[Page3 alloc] initWithNibName:nil bundle:nil],    
            [[Page4 alloc] initWithNibName:nil bundle:nil],    
            [[Page5 alloc] initWithNibName:nil bundle:nil],    
            [[Page6 alloc] initWithNibName:nil bundle:nil], 
            [[Page7 alloc] initWithNibName:nil bundle:nil],
            [[Page8 alloc] initWithNibName:nil bundle:nil],
             // continues all the way up to page 47
             [[Page47 alloc] initWithNibName:nil bundle:nil],
             nil];

の標準的な初期化は省略しましたUIPageViewController。「 」を使用nextPageNumberして上から右のページをプルしpageArray、新しいページ オブジェクトを作成します。

-(void)turnPageForward{

[pageController setViewControllers:[NSArray arrayWithObject:[pageArray objectAtIndex:nextPageNumber]]
                         direction:UIPageViewControllerNavigationDirectionForward
                          animated:YES completion:^(BOOL finished){
                          }];

}

pageIndexに提供した後に nil に設定されるオブジェクト " " (以下を参照) を作成しようとしましたpageController。うまくいきませんでした。ページが進んだ後も、ページはまだ十分にメモリを占有していました。

//PROGRAM PAGE FORWARD

-(void)turnPageForward{

UIViewController * pageIndex =[pageArray objectAtIndex:nextPageNumber];  //nextPageNumber is the next page to load

[pageController setViewControllers:[NSArray arrayWithObject:pageIndex]
                         direction:UIPageViewControllerNavigationDirectionForward 
                          animated:YES completion:^(BOOL finished){
                          }];                                  
pageIndex = nil;                            

}

にページを提供するのと同じ方法を使用して投稿のスタックオーバーフローを調べましたがUIPageViewController、近いものは見つかりませんでした。最も近いのは「ナビゲーションコントローラーで「戻る」ときにARCがメモリを解放しない」でしたが、ビューコントローラーを同じように設定しません。

望ましくないページを nil に設定しようとしたので、ARC はそれらを運良く削除できます。試してみるべき提案や代替パスはありますか? 私はページのカール効果が好きで、水平方向のページのカールを行う良いものを他に見つけることができませんでした.

ありがとう!エリック

4

3 に答える 3

14

「UIPageViewController は、インスタンス化した各ページをメモリに保持しているようです」

いいえ、それらすべての「ページ」(コントローラー)をインスタンス化し、それらを配列に配置することによってそれを行っています(コントローラーのビューは、コントローラーが表示されるまで実際にはロードされないため、ページをめくるとメモリがジャンプしますがインスタンス化されました.しかし、一度それを行うと、コントローラーはそのビューを保持し、アレイはコントローラーを保持します)。現在のページのカウントを保持し、viewControllerBeforeViewController: と viewControllerAfterViewController: の実装でページをインスタンス化する必要があるだけです。そのページから離れると、そのコントローラーは解放されます。読み込みが遅い場合は、

次のような簡単なテストアプリを作成しました。

@implementation ViewController {
    int count;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    count = 1;
    self.pager = [[UIPageViewController alloc]initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationDirectionForward options:nil];
    self.pager.dataSource = self;
    self.pager.delegate = self;
    Page1 *first = [[Page1 alloc] initWithNibName:@"Page1" bundle:nil];
    [self.pager setViewControllers:@[first] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
    [self addChildViewController:self.pager];
    [self.view addSubview:self.pager.view];
    [self.pager didMoveToParentViewController:self];
}


-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
    if (count > 1) {
        NSString *nibName = [@"Page" stringByAppendingFormat:@"%d",count-1];
        UIViewController *prev = [[NSClassFromString(nibName) alloc] initWithNibName:nibName bundle:nil];
        count -= 1;
        return prev;
    }
    return nil;
}

-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
    if (count < 3) {
        NSString *nibName = [@"Page" stringByAppendingFormat:@"%d",count+1];
        UIViewController *next = [[NSClassFromString(nibName) alloc] initWithNibName:nibName bundle:nil];
        count += 1;
        return next;
    }
    return nil;
}

私の例には 3 ページしかありませんが、これを行う 1 つの方法を示しています。3 つのコントローラーの dealloc メソッドにログを記録しました。それらは、コントローラーから離れたときに呼び出されました。

于 2013-02-07T16:50:03.953 に答える
2

この質問は少し古いことは知っていますが、私のアプローチは、ARC を使用していないときに同じ問題に直面している一部の人々を助けることができるかもしれません。

未使用のページを解放する最良の方法は、UIPageViewController の didFinishAnimation メソッドにあると思います。そこに 1 つまたは 2 つの以前のビュー コントローラーがあり、簡単に解放できます。私はこのようにします:

-(void)pageViewController:(UIPageViewController *)thePageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {

    if(completed) {
        for (UIViewController *viewController in previousViewControllers) {
             [viewController release];
        }
     }
}

アクションが完了した場合にのみそれらを解放することが重要です。そうしないと、次のページ変更で解放されたページにアクセスしようとするからです。

お役に立てれば!

于 2013-10-16T12:11:52.507 に答える
0

今回はこの問題に遭遇しました。そして、1時間考えた後、私は解決策を見つけました.

これは私の .h ファイルです

#import <UIKit/UIKit.h>

@interface BKContentViewController : UIPageViewController

@end

そして、私の .m ファイルと viewDidload メソッド

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    self.delegate = self;
    self.dataSource = self;

    [self setViewControllers:[NSArray arrayWithObject:detailContent]
                   direction:UIPageViewControllerNavigationDirectionForward
                    animated:NO
                  completion:NULL];
}

そして最も重要なこと。

#pragma mark - UIPageViewControllerDataSource UIPageViewControllerDelegate

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{
    if (completed) {
        [self setViewControllers:[NSArray arrayWithObject:detailContent]
                       direction:UIPageViewControllerNavigationDirectionForward
                        animated:NO
                      completion:NULL];
    }

}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController{


    if (!detailRight) {
        detailRight = [[DetailContent alloc] init];
        [detailRight setShouldReturn:YES];
        [detailRight setPath:fPath withFileName:fName];
    }
    return detailRight;
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController{

    if (!detailLeft) {
        detailLeft = [[DetailContent alloc] init];
        [detailLeft setShouldReturn:YES];
        [detailLeft setPath:fPath withFileName:fName];
    }

    return detailLeft;
}

- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation{
    UIViewController *currentViewController = [self.viewControllers objectAtIndex:0];
    NSArray *viewControllers = [NSArray arrayWithObject:currentViewController];
    [self setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];

    self.doubleSided = NO;
    return UIPageViewControllerSpineLocationMin;
}

この後、viewContrrlerが3つしかなく、何度もスクロールしてもメモリが増えません。これがあなたを助けることを願っています。

于 2014-07-01T09:04:29.710 に答える