私はiPhone、SDK 3.1用に開発しています。ユーザーがページをめくるために表示する必要がある約 150 の画像があります。Apple の PageControl サンプルからコードをコピーしましたが、iPhone にロードすると、すばやくスクロールするとアプリケーションがクラッシュします。メモリを節約するためにいくつかの最適化を書き込もうとしましたが、あまり役に立ちません。最適化を改善する必要があるかどうか、または他の問題があるかどうかを誰かに教えてもらえないかと思っていました。関連するコードは以下です。
// ReviewViewController.h
@interface ReviewViewController : UIViewController <UIActionSheetDelegate, UIScrollViewDelegate> {
NSMutableArray *reviewArr;
NSMutableArray *viewControllers;
IBOutlet UIScrollView *scroller;
BOOL dirty;
NSInteger pageCount;
}
@property (retain, nonatomic) NSMutableArray *reviewArr;
@property (retain, nonatomic) NSMutableArray *viewControllers;
@property (assign, nonatomic) UIScrollView *scroller;
//ReviewViewController.m
-(void)clearScroller {
NSArray *subviews = [[NSArray alloc] initWithArray:scroller.subviews];
for (UIView *subview in subviews) {
//NSLog(@"DEBUG - view %d", subview.tag);
[subview removeFromSuperview];
}
[subviews release];
[scroller setContentOffset:CGPointMake(0,0) animated:NO];
}
- (void)initialize:(int)page {
if([reviewArr count] == 0) {
NSLog(@"No more cards on stack");
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 70, 420, 45)];
label.text = @"You have no review cards in your stack";
label.numberOfLines = 2;
label.font = [UIFont systemFontOfSize:20];
[scroller addSubview:label];
[label release];
[back setHidden:YES];
[forward setHidden:YES];
[mathFactAction setHidden:YES];
return;
}
NSLog(@"Initializing..%d", page);
[self setHeading];
[self clearScroller];
[mathFactAction setHidden:NO];
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < reviewArr.count; i++) {
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
// a page is the width of the scroll view
scroller.pagingEnabled = YES;
scroller.contentSize = CGSizeMake(scroller.frame.size.width * reviewArr.count, scroller.frame.size.height);
scroller.showsHorizontalScrollIndicator = NO;
scroller.showsVerticalScrollIndicator = NO;
scroller.scrollsToTop = NO;
scroller.delegate = self;
// pages are created on demand
// load the visible page
// load the page on either side to avoid flashes when the user starts scrolling
if(page > 0) {
[self loadScrollViewWithPage:page - 1];
}
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
}
- (void)checkForDirtyPages {
for (unsigned i = 0; i < [self.viewControllers count]; i++) {
if(i == pageCount-1) continue;
else if(i == pageCount) continue;
else if(i == pageCount+1) continue;
else unloadPage:i;
}
}
- (void)unloadPages {
dirty = FALSE;
[self unloadPage:pageCount-3];
[self unloadPage:pageCount-4];
[self unloadPage:pageCount+3];
[self unloadPage:pageCount+4];
}
- (void)unloadPage:(int)page {
if (page < 0) return;
if (page >= reviewArr.count) return;
// replace the placeholder if necessary
FactViewController *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller != [NSNull null]) {
/*NSArray *subviews = [[NSArray alloc] initWithArray:controller.view.subviews];
for (UIView *subview in subviews) {
//NSLog(@"DEBUG - view %d", subview.tag);
[subview removeFromSuperview];
}
[subviews release]; */
// remove teh innerscroller from viewControllers to conserve memory
[self.viewControllers replaceObjectAtIndex:page withObject:[NSNull null]];
}
}
- (void)loadScrollViewWithPage:(int)page {
if (page < 0) return;
if (page >= reviewArr.count) return;
// replace the placeholder if necessary
FactViewController *controller = [viewControllers objectAtIndex:page];
//UIScrollView *innerScroller = [self.viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null]) {
controller = [[FactViewController alloc] initWithReviewNumber:[reviewArr objectAtIndex:page]];
[self.viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
if (nil == controller.view.superview) {
CGRect frame = scroller.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scroller addSubview:controller.view];
//[self unloadPages];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender {
if(dirty) [self unloadPages];
//[self resetScroller:pageCount-1];
//[self resetScroller:pageCount+1];
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = scroller.frame.size.width;
int page = floor((scroller.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
// pageControl.currentPage = page;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// if we are on a new page
if(page != pageCount) {
dirty = TRUE;
pageCount = page;
[self setHeading];
}
// A possible optimization would be to unload the views+controllers which are no longer visible
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
[self checkForDirtyPages];
}
// FactViewController.m
@interface FactViewController : UIViewController {
IBOutlet UIScrollView *scrollView;
//IBOutlet UILabel *pageNumberLabel;
NSInteger review_id;
}
@property (nonatomic, retain) UIView *scrollView;
//@property (nonatomic, retain) UILabel *pageNumberLabel;
@property (assign, nonatomic) NSInteger review_id;
-(void)unloadImage;
- (id)initWithReviewNumber:(NSNumber *)reviewNumber;
- (int)getMathFactId;
@end
// Load the view nib and initialize the pageNumber ivar.
- (id)initWithReviewNumber:(NSNumber *)reviewNumber {
if (self = [super initWithNibName:@"FactViewController" bundle:nil]) {
self.review_id = [reviewNumber intValue];
}
return self;
}
- (void)dealloc {
//[pageNumberLabel release];
//[card release];
[scrollView release];
[super dealloc];
}
// Set the label and background color when the view has finished loading.
- (void)viewDidLoad {
NSLog(@"(FactVC) view did load");
[self showImage];
[super viewDidLoad];
}
-(void)unloadImage {
[scrollView release];
}
-(void)showImage {
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setMinimumIntegerDigits:2];
NSLog(@"Loading image (%d)", self.review_id);
NSString *img_file = [NSString stringWithFormat:@"%@", [numberFormatter stringForObjectValue:[NSNumber numberWithInt:self.review_id]]];
[numberFormatter release];
NSString *fileLocation = [[NSBundle mainBundle] pathForResource:img_file ofType:@"gif"];
NSData *imageData = [NSData dataWithContentsOfFile:fileLocation];
UIImage *image = [UIImage imageWithData:imageData];
//UIImage *image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:img_file ofType:@"gif"]];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; // inDirectory:@"Resources/questions"
[scrollView addSubview:imageView];
[scrollView setContentSize:CGSizeMake(imageView.frame.size.width, imageView.frame.size.height)];
[imageView release];
}
長くなって申し訳ありませんが、すべてが含まれていることを確認したかったのです。