Large UIScrollView with page flipping sometimes crashes
I have a UIScroll view that is kind of odd in the first place because you scroll to the end, and then you flip the page, and you can go back as well, but this is how the client wanted it. For some reason it sometimes crashes (more often on the actual iPad) and it does this without a crash log. I have a feeling it has to be memory related. Is there anyway of preventing this from crashing? Thanks.
#import "viewBookVC.h"
#import "switchVC.h"
#import "switchExVC.h"
#import "mainMenuAppDelegate.h"
#import "exGlobal.h"
@implementation ViewBookVC
UIScrollView *scroll;
UIButton *prevPageButton;
UIButton *nextPageButton;
UIImage *scrollImage;
UIImageView *BGview2;
NSMutableArray *BGList;
NSMutableArray *pagingEnabledArr;
int currentPage = 0;
int maxPages = 0;
// used to put a delay on the previous page touch detection
int prevNextPageDetectDelay = 45;
int prevNextPageDetectDelayCounter = 0;
int nextContentOffsetX;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
currentPage = 0;
maxPages = 0;
prevNextPageDetectDelayCounter = 0;
mainMenuAppDelegate *del = (mainMenuAppDelegate *)[[UIApplication sharedApplication] delegate];
// page list
BGList = [[NSMutableArray alloc] init];
for(int i = 0; i < 31; i++) {
NSString *img = [NSString stringWithFormat:@"Viewbook_%d.png", i];
[BGList addObject:img];
}
maxPages = [BGList count];
// scrolling rules for paging being enabled
pagingEnabledArr = [[NSMutableArray alloc] init];
[pagingEnabledArr addObject:@"YES"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"YES"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"YES"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"YES"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"NO"];
[pagingEnabledArr addObject:@"YES"];
[pagingEnabledArr addObject:@"YES"];
timer_checkScrollPos = [[NSTimer scheduledTimerWithTimeInterval:.005
target:self
selector:@selector(onTimer_checkScrollPos:)
userInfo:nil
repeats:YES] retain];
/////////////
// //
// SCROLL //
// //
/////////////
//scroll view
CGRect scrollContainer = CGRectMake(0, 0, 1024, 768);
scroll = [[UIScrollView alloc] initWithFrame:scrollContainer];
[scroll setBackgroundColor:[UIColor blackColor]];
scroll.contentSize = CGSizeMake(1024, 722);
scroll.showsHorizontalScrollIndicator = YES;
scroll.bounces = NO;
scroll.pagingEnabled = YES;
[self addSubview:scroll];
// get scroll offset
NSLog(@"cOffset(A): %f", scroll.contentOffset.x);
//image to use in scroll
scrollImage = [UIImage imageNamed:@"Viewbook_0.png"];
BGview2 = [[UIImageView alloc] initWithImage:(UIImage *)scrollImage];
BGview2.frame = CGRectMake(0, 23, 1024, 722);
[scroll addSubview:BGview2];
//back button [prev button height was compensated for this button to work]
CGRect backBTNFrame = CGRectMake(10, 30, 140, 52);
UIButton * viewbook_backButton = [[UIButton alloc] init];
viewbook_backButton.frame = backBTNFrame;
UIImage *viewbook_backButtonIMG = [UIImage imageNamed:@"SHIP_button_back.png"];
[viewbook_backButton setImage:viewbook_backButtonIMG forState:UIControlStateNormal];
viewbook_backButton.backgroundColor = [UIColor clearColor];
[self addSubview:viewbook_backButton];
[viewbook_backButton addTarget:self
action:@selector(kill_timers)
forControlEvents:UIControlEventTouchUpInside];
[viewbook_backButton addTarget:del.switchVC
action:@selector(gotoMain)
forControlEvents:UIControlEventTouchUpInside];
[viewbook_backButton release];
//prev button
CGRect prevPageButtonFrame = CGRectMake(0, 70, 312, 698);
prevPageButton = [[UIButton alloc] init];
prevPageButton.frame = prevPageButtonFrame;
prevPageButton.backgroundColor = [UIColor clearColor];
[self addSubview:prevPageButton];
[prevPageButton addTarget:self
action:@selector(prevPage:)
forControlEvents:UIControlEventTouchUpInside];
//next button
CGRect nextPageButtonFrame = CGRectMake(712, 0, 312, 768);
nextPageButton = [[UIButton alloc] init];
nextPageButton.frame = nextPageButtonFrame;
nextPageButton.backgroundColor = [UIColor clearColor];
[self addSubview:nextPageButton];
[nextPageButton addTarget:self
action:@selector(nextPage:)
forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
-(void) onTimer_checkScrollPos:(NSTimer*)timer {
if(currentPage!=0){
nextContentOffsetX = 750;
}else{
nextContentOffsetX = 0;
}
//NSLog(@"cOffset(A): %f", scroll.contentOffset.x);
if(scroll.contentOffset.x >= nextContentOffsetX){
nextPageButton.hidden = NO;
}else{
nextPageButton.hidden = YES;
}
if(scroll.contentOffset.x <= 274){
prevPageButton.hidden = NO;
}else{
prevPageButton.hidden = YES;
}
prevNex开发者_开发技巧tPageDetectDelayCounter += 1;
}
- (void)nextPage:(id)sender {
if(currentPage!=0){
nextContentOffsetX = 750;
}else{
nextContentOffsetX = 0;
}
if(scroll.contentOffset.x >= nextContentOffsetX & prevNextPageDetectDelayCounter>=prevNextPageDetectDelay){
prevNextPageDetectDelayCounter = 0;
currentPage+=1;
if(currentPage >= maxPages){
currentPage = 0;
}
if(currentPage!=0){
scroll.contentSize = CGSizeMake(2048, 722);
BGview2.frame = CGRectMake(0, 23, 2048, 722);
}else{
scroll.contentSize = CGSizeMake(1024, 722);
BGview2.frame = CGRectMake(0, 23, 1024, 722);
}
[UIView beginAnimations:@"flipping view" context:nil];
[UIView setAnimationDuration:0.8];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp
forView:scroll
cache:YES];
[scroll setHidden:NO];
[UIView commitAnimations];
if([pagingEnabledArr objectAtIndex:currentPage]==@"YES"){
scroll.pagingEnabled = YES;
}else{
scroll.pagingEnabled = NO;
}
BGview2.image = [UIImage imageNamed:[BGList objectAtIndex:currentPage]];
// set scroll offset
[scroll setContentOffset:CGPointMake(0,0) animated:NO];
}
}
- (void)prevPage:(id)sender {
if(scroll.contentOffset.x <= 274 & prevNextPageDetectDelayCounter>=prevNextPageDetectDelay){
prevNextPageDetectDelayCounter = 0;
currentPage-=1;
if(currentPage < 0){
currentPage = maxPages-1;
}
if(currentPage!=0){
scroll.contentSize = CGSizeMake(2048, 722);
BGview2.frame = CGRectMake(0, 23, 2048, 722);
}else{
scroll.contentSize = CGSizeMake(1024, 722);
BGview2.frame = CGRectMake(0, 23, 1024, 722);
}
[UIView beginAnimations:@"flipping view" context:nil];
[UIView setAnimationDuration:0.8];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown
forView:scroll
cache:YES];
[scroll setHidden:NO];
[UIView commitAnimations];
if([pagingEnabledArr objectAtIndex:currentPage]==@"YES"){
scroll.pagingEnabled = YES;
}else{
scroll.pagingEnabled = NO;
}
BGview2.image = [UIImage imageNamed:[BGList objectAtIndex:currentPage]];
// set scroll offset
[scroll setContentOffset:CGPointMake(0,0) animated:NO];
}
}
-(void) kill_timers{
NSLog(@"kill viewbook timer");
[timer_checkScrollPos invalidate];
timer_checkScrollPos = nil;
}
- (void)dealloc {
[scroll release];
[BGview2 release];
[BGList release];
[pagingEnabledArr release];
[prevPageButton release];
[nextPageButton release];
[timer_checkScrollPos invalidate];
[timer_checkScrollPos release];
[super dealloc];
}
@end
This does sound like a memory management issue. I suspect that you are loading all of the content into memory although you only display one or two pages at a single time. I suggest using Core Data or XML to load only the data you absolutely need at any given time.
As far as the device being less stable than the simulator, you should note that the simulator is not an emulator. The simulator uses the memory in your Mac and does not have the memory limitations of your iPad.
To debug this, you have a few options:
Try hooking up an iPad to your Mac and watch the console (Cmd+Shift+R). You will see a warning when your app gets a memory warning. A level 1 is often followed by a level 2 which is often followed by a crash. This could help substantiate the existence of an existing problem.
Run your app using the Allocations Instrument to track what could be causing the app to allocate so much memory. The Leaks instrument will help you find memory leaks.
Take advantage of a nifty feature in Xcode called "Build and Analyze". It's pretty good at finding memory leaks. (Build -> Build and Analyze)
Between leaking memory and allocating memory that the system doesn't have to give you, you have probably cause for your crashes.
精彩评论