NSTimer is not working fine ..in Animation in iPhone - iphone

im new to iPhone programming..in my app the timer is not working fine.
can anybody help me out please...
The following is the code for animating few images wn we touch or swipe..they fall down
i want to restrict the touches for few seconds with use of timer...
is there another way to do this..?(before using timer its crashing on device,but working fine in the simulator..im trying for solution for crashing..)
// HomeViewController.m
#import "HomeViewController.h"
#implementation HomeViewController
#synthesize dustImage, myAnimatedView;
#synthesize _isAnimating = isAnimating;
float ver_X, ver_Y;
BOOL rotated;
NSTimer *touchTimer;
- (void)viewDidLoad {
[super viewDidLoad];
self.view.frame = [[UIScreen mainScreen] bounds];
//[self playAudio];
}
-(void)blowingTheSparkles:(NSSet *) touches {
if(!isAnimating){
float a, aa;
float b, bb;
CGRect frame1;
myAnimatedView = [UIImageView alloc];
//NSLog(#"touch count...%d",[touches count]);
for (int i=0; i< (int)[touches count]; ++i) {
UITouch* touch = [[touches allObjects] objectAtIndex:i];
CGPoint location = [touch locationInView:dustImage];
NSArray *myImages = [NSArray arrayWithObjects: [UIImage imageNamed:#"starburst1.png"],
[UIImage imageNamed:#"starburst2.png"],
[UIImage imageNamed:#"starburst3.png"],
[UIImage imageNamed:#"starburst4.gif"],
[UIImage imageNamed:#"starburst5.png"],
[UIImage imageNamed:#"starburst6.png"],
[UIImage imageNamed:#"starburst7.png"],nil];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
a=(location.x)-80;
b=(location.y)-80;
ver_X=768;
ver_Y=1024;
frame1 = CGRectMake(a,b,160,160);
#else
a=(location.x)-40;
b=(location.y)-40;
ver_X=320;
ver_Y=480;
frame1 = CGRectMake(a,b,80,80);
#endif
aa= location.x;
bb= location.y;
[myAnimatedView initWithFrame:frame1];
myAnimatedView.animationImages = myImages;
myAnimatedView.animationDuration = 0.25;
myAnimatedView.animationRepeatCount = 0;
[dustImage addSubview:myAnimatedView];
CABasicAnimation *fadeOutAnimation = [CABasicAnimation animationWithKeyPath:#"opacity"];
[fadeOutAnimation setToValue:[NSNumber numberWithFloat:0.3]];
fadeOutAnimation.fillMode = kCAFillModeForwards;
fadeOutAnimation.removedOnCompletion = NO;
//Set up scaling
CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:#"bounds.size"];
[resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(0.0f, frame1.size.height * (1.0f /1.0))]];
resizeAnimation.fillMode = kCAFillModeForwards;
resizeAnimation.removedOnCompletion = NO;
// Set up path movement
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
CGPoint endPoint = CGPointMake(aa ,ver_Y);
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGPathMoveToPoint(curvedPath, NULL, aa, bb);
CGPathAddCurveToPoint(curvedPath, NULL, endPoint.x, bb,endPoint.x, bb,endPoint.x,endPoint.y);
pathAnimation.path = curvedPath;
CGPathRelease(curvedPath);
CAAnimationGroup *group = [CAAnimationGroup animation];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[group setAnimations:[NSArray arrayWithObjects:fadeOutAnimation, pathAnimation, resizeAnimation, nil]];
group.duration = 4.0f;
group.delegate = self;
[group setValue:myAnimatedView forKey:#"myAnimatedView"];
[myAnimatedView.layer addAnimation:group forKey:#"savingAnimation"];
[myAnimatedView startAnimating];
}
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if(!isAnimating)
[self blowingTheSparkles:touches];
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
isAnimating=TRUE;
touchTimer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(sleeping) userInfo:nil repeats:NO];
}
-(void)sleeping{
NSLog(#"....Hiiii");
isAnimating = FALSE;
[touchTimer invalidate];
touchTimer = nil;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if(!isAnimating){
[self blowingTheSparkles:touches];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)dealloc {
[myAnimatedView release];
[super dealloc];
}
#end

You don't seem to be correctly retaining the NSTimer which could be your problem here.
Change it to:
touchTimer = [[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(sleeping) userInfo:nil repeats:NO] retain];
Ideally you should declare touchTimer as a property and synthesize it, but try this first.
Change sleeping to release the timer:
-(void)sleeping{
NSLog(#"....Hiiii");
isAnimating = FALSE;
[touchTimer invalidate];
[touchTimer release];
touchTimer = nil;
}

Related

How to add a magnifier to custom control?

How to add a magnifier to custom control? Control is a child of UIView. (It's a UIWebView - but native magnification functionality doesn't work at some pages.)
UPDATED:
Maybe it's possible to force a draw of magnifier on UIWebView?
1. Add the following files to your project:
MagnifierView.h:
//
// MagnifierView.h
// SimplerMaskTest
//
#import <UIKit/UIKit.h>
#interface MagnifierView : UIView {
UIView *viewToMagnify;
CGPoint touchPoint;
}
#property (nonatomic, retain) UIView *viewToMagnify;
#property (assign) CGPoint touchPoint;
#end
MagnifierView.m:
//
// MagnifierView.m
// SimplerMaskTest
//
#import "MagnifierView.h"
#import <QuartzCore/QuartzCore.h>
#implementation MagnifierView
#synthesize viewToMagnify;
#dynamic touchPoint;
- (id)initWithFrame:(CGRect)frame {
return [self initWithFrame:frame radius:118];
}
- (id)initWithFrame:(CGRect)frame radius:(int)r {
int radius = r;
if ((self = [super initWithFrame:CGRectMake(0, 0, radius, radius)])) {
//Make the layer circular.
self.layer.cornerRadius = radius / 2;
self.layer.masksToBounds = YES;
}
return self;
}
- (void)setTouchPoint:(CGPoint)pt {
touchPoint = pt;
// whenever touchPoint is set, update the position of the magnifier (to just above what's being magnified)
self.center = CGPointMake(pt.x, pt.y-66);
}
- (CGPoint)getTouchPoint {
return touchPoint;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect bounds = self.bounds;
CGImageRef mask = [UIImage imageNamed: #"loupe-mask#2x.png"].CGImage;
UIImage *glass = [UIImage imageNamed: #"loupe-hi#2x.png"];
CGContextSaveGState(context);
CGContextClipToMask(context, bounds, mask);
CGContextFillRect(context, bounds);
CGContextScaleCTM(context, 1.2, 1.2);
//draw your subject view here
CGContextTranslateCTM(context,1*(self.frame.size.width*0.5),1*(self.frame.size.height*0.5));
//CGContextScaleCTM(context, 1.5, 1.5);
CGContextTranslateCTM(context,-1*(touchPoint.x),-1*(touchPoint.y));
[self.viewToMagnify.layer renderInContext:context];
CGContextRestoreGState(context);
[glass drawInRect: bounds];
}
- (void)dealloc {
[viewToMagnify release];
[super dealloc];
}
#end
TouchReader.h:
//
// TouchReader.h
// SimplerMaskTest
//
#import <UIKit/UIKit.h>
#import "MagnifierView.h"
#interface TouchReader : UIView {
NSTimer *touchTimer;
MagnifierView *loop;
}
#property (nonatomic, retain) NSTimer *touchTimer;
- (void)addLoop;
- (void)handleAction:(id)timerObj;
#end
TouchReader.m:
//
// TouchReader.m
// SimplerMaskTest
//
#import "TouchReader.h"
#import "MagnifierView.h"
#implementation TouchReader
#synthesize touchTimer;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.touchTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(addLoop) userInfo:nil repeats:NO];
// just create one loop and re-use it.
if (loop == nil) {
loop = [[MagnifierView alloc] init];
loop.viewToMagnify = self;
}
UITouch *touch = [touches anyObject];
loop.touchPoint = [touch locationInView:self];
[loop setNeedsDisplay];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self handleAction:touches];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self.touchTimer invalidate];
self.touchTimer = nil;
[loop removeFromSuperview];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self.touchTimer invalidate];
self.touchTimer = nil;
[loop removeFromSuperview];
}
- (void)addLoop {
// add the loop to the superview. if we add it to the view it magnifies, it'll magnify itself!
[self.superview addSubview:loop];
// here, we could do some nice animation instead of just adding the subview...
}
- (void)handleAction:(id)timerObj {
NSSet *touches = timerObj;
UITouch *touch = [touches anyObject];
loop.touchPoint = [touch locationInView:self];
[loop setNeedsDisplay];
}
- (void)dealloc {
[loop release];
loop = nil;
[super dealloc];
}
#end
Based on: http://coffeeshopped.com/2010/03/a-simpler-magnifying-glass-loupe-view-for-the-iphone
2. Add the following images:
Used images on the code:
loupe-hi#2x.png:
loupe-mask#2x.png:
Original but centered images with a shadow (not used at this moment):
loupe-shadow-hi#2x.png:
loupe-shadow-mask#2x.png:
3. Replace the main UIView on your xib-file by TouchReader
The magnifier will work automaticaly except controls that captures touch events themselfs (for example, UIWebView). And the code above doesn't support the images with a shadow. Please add new answer to the qustion if you successfully fix this issue.
UPDATED:
Change the following code to add UIWebView support. UIView should remain UIView.
#interface TouchReader : UILongPressGestureRecognizer
And add a gesture to webView:
TouchReader* gestureMagnifier = [[[TouchReader alloc] initWithTarget:self action:#selector(handleMagnifier:)] autorelease];
gestureMagnifier.webView = editSource;
gestureMagnifier.delegate = self;
gestureMagnifier.minimumPressDuration = 0.5;
[webView addGestureRecognizer:gestureMagnifier];
TouchReader.h:
//- (void)handleAction:(id)timerObj;
-(void) handleGestureAction:(CGPoint)location;
TouchReader.m:
-(void)awakeFromNib
{
UILongPressGestureRecognizer * longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[self addGestureRecognizer:longPressGesture];
}
-(void)handleGesture:(UILongPressGestureRecognizer *)longPressGesture
{
CGPoint location = [longPressGesture locationInView:self];
switch (longPressGesture.state) {
case UIGestureRecognizerStateBegan:
self.touchTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(addLoop)
userInfo:nil
repeats:NO];
// just create one loop and re-use it.
if(loop == nil){
loop = [[MagnifierView alloc] init];
loop.viewToMagnify = self;
}
loop.touchPoint = location;
[loop setNeedsDisplay];
break;
case UIGestureRecognizerStateChanged:
[self handleGestureAction:location];
break;
case UIGestureRecognizerStateEnded:
[self.touchTimer invalidate];
self.touchTimer = nil;
[loop removeFromSuperview];
loop=nil;
break;
default:
break;
}
}
- (void)addLoop {
// add the loop to the superview. if we add it to the view it magnifies, it'll magnify itself!
[self.superview addSubview:loop];
}
-(void) handleGestureAction:(CGPoint)location
{
loop.touchPoint = location;
[loop setNeedsDisplay];
}
You don't need the touches... methods any more.

Stop animation when same time remove button from superview

if i tap on button then this button is animate with rotation and add once again in self.view, but i want to when this button is add in view more than 10 in self.view then remove first button, and next animation is not stop, i want to remove button in another thread, but not effect on animation
I Try that code for another thread, but not work properly, animation is stop
-(void)putFruietAtOriginPositionInMainThread:(NSDictionary*)btnDictionary{
//if (!dragFlag) {
[self playSoundEffect:#"abc.mp3" withRepeatCount:0];
//[self.view bringSubviewToFront:btnBag];
//[self.view bringSubviewToFront:bagView];
UIButton *btnFruiet = [btnDictionary objectForKey:#"btnFruiet"];
int position= [[btnDictionary objectForKey:#"position"]intValue];
CGFloat xPosition = [[[dicCenterPoint objectForKey:[NSString stringWithFormat:#"%i",btnFruiet.tag]] objectAtIndex:0]floatValue];
CGFloat yPosition = [[[dicCenterPoint objectForKey:[NSString stringWithFormat:#"%i",btnFruiet.tag]] objectAtIndex:1]floatValue];
btnFruiet.center = self.view.center;
//btnFruiet.enabled = FALSE;
//[self playSoundEffect:#"shapes_collapse.mp3" withRepeatCount:0];
if ([dicFruitTimer count]>0) {
NSTimer *timer = [dicFruitTimer valueForKey:[NSString stringWithFormat:#"%i",btnFruiet.tag]];
if (timer) {
[timer invalidate];
timer=nil;
[dicFruitTimer removeObjectForKey:[NSString stringWithFormat:#"%i",btnFruiet.tag]];
}
}
NSTimer *fruitTimer = [NSTimer timerWithTimeInterval:0.00002 target:self selector:#selector(setFrameOfFruietWithTimer:) userInfo:[NSDictionary dictionaryWithObject:btnFruiet forKey:#"fruit"] repeats:YES];
[[NSRunLoop mainRunLoop]addTimer:fruitTimer forMode:NSRunLoopCommonModes];
[dicFruitTimer setObject:fruitTimer forKey:[NSString stringWithFormat:#"%i",btnFruiet.tag]];
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:FRUIT_ANIMATION_DURATION/2] forKey:kCATransactionAnimationDuration];
CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
CGMutablePathRef positionPath = CGPathCreateMutable();
CGPathMoveToPoint(positionPath, NULL, [btnFruiet layer].position.x , [btnFruiet layer].position.y);
CGPathAddLineToPoint(positionPath, NULL, xPosition, yPosition);
positionAnimation.path = positionPath;
//CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
// rotateAnimation.delegate = self;
// //rotateAnimation.autoreverses = YES;
// rotateAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
// rotateAnimation.fromValue = [NSNumber numberWithFloat:2.0];
// rotateAnimation.toValue = [NSNumber numberWithFloat:1.0];
// rotateAnimation.fillMode = kCAFillModeForwards;
// rotateAnimation.removedOnCompletion = NO;
CABasicAnimation *shrinkAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
shrinkAnimation.fromValue = [NSNumber numberWithFloat:kScaleFactor];
shrinkAnimation.toValue = [NSNumber numberWithFloat:1.0f];
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
theGroup.delegate = self;
theGroup.removedOnCompletion = NO;
theGroup.fillMode = kCAFillModeForwards;
theGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
theGroup.animations = [NSArray arrayWithObjects:positionAnimation, shrinkAnimation,nil];
NSString *strPosition = [NSString stringWithFormat:#"%d,3", position];
[theGroup setValue:strPosition forKey:#"AnimationGroup"];
[[btnFruiet layer] addAnimation:theGroup forKey:#"AnimationGroup"];
//btnAnimationRunning = btnFruiet;
[CATransaction commit];
CGPathRelease(positionPath);
//[arrTimers removeObject:timer];
//}
if ([arrFruitOnScreen count]>10) {
//NSThread *thread = [[NSThread alloc] init];
//[self performSelector:#selector(removeFruit) withObject:nil];
[self performSelector:#selector(removeFruit) withObject:nil afterDelay:FRUIT_ANIMATION_DURATION/2];
//[thread start];
//[self performSelector:#selector(removeFruit) onThread:thread withObject:nil waitUntilDone:NO];
//}
}
-(void)removeFruit{
UIButton *btnF = [arrFruitOnScreen objectAtIndex:0];
[[btnF layer] removeAllAnimations];
[arrFruitOnScreen removeObjectAtIndex:0];
[btnF removeFromSuperview];
}
It's pretty unclear what you're trying to achieve but UIKit updates must be done in the main thread. This should address the part where it doesn't work on another thread.

iPhone - My new view is blocking my toolbar

I have a problem with my app. With help by a tutorial I've created a slideshow with pictures. I've added a toolbar so it's possible to go back. The problem is that when the pictures are showing, the toolbar disappear. I've been trying to google the problem and so on, but I can't solve it. In a "previous" class I create SlideShowViewController, and inside that class I have another one called SlideShowView. I hope this ain't to messy or stupid, cause I really need help.
Here is the code:
#import "SlideShowViewController.h"
#import "Pictures.h"
#interface SlideShowView : UIView
{
NSArray * mImages;
UIImageView * mLeftImageView;
UIImageView * mCurrentImageView;
UIImageView * mRightImageView;
NSUInteger mCurrentImage;
Pictures *picRef;
SlideShowViewController *slideRef;
BOOL mSwiping;
CGFloat mSwipeStart;
}
- (id)initWithImages:(NSArray *)inImages;
#end // SlideShowView
#pragma mark -
//#import "SlideShowViewController.h"
#implementation SlideShowView
- (UIImageView *)createImageView:(NSUInteger)inImageIndex
{
if (inImageIndex >= [mImages count])
{
return nil;
}
UIImageView * result = [[UIImageView alloc] initWithImage:[mImages objectAtIndex:inImageIndex]];
result.opaque = YES;
result.userInteractionEnabled = NO;
result.backgroundColor = [UIColor whiteColor];
result.contentMode = UIViewContentModeScaleAspectFit;
result.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
return result;
}
- (id)initWithImages:(NSArray *)inImages
{
if (self = [super initWithFrame:CGRectZero])
{
mImages = [inImages retain];
NSUInteger imageCount = [inImages count];
if (imageCount > 0)
{
mCurrentImageView = [self createImageView:0];
[self addSubview:mCurrentImageView];
if (imageCount > 1)
{
mRightImageView = [self createImageView:1];
[self addSubview:mRightImageView];
}
}
self.opaque = YES;
self.backgroundColor = [UIColor whiteColor];
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
return self;
}
- (void)dealloc
{
[mImages release];
[super dealloc];
}
- (void)layoutSubviews
{
if (mSwiping)
return;
CGSize contentSize = self.frame.size;
mLeftImageView.frame = CGRectMake(-contentSize.width, 0.0f, contentSize.width, contentSize.height);
mCurrentImageView.frame = CGRectMake(0.0f, 0.0f, contentSize.width, contentSize.height);
mRightImageView.frame = CGRectMake(contentSize.width, 0.0f, contentSize.width, contentSize.height);
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([touches count] != 1){
return;
}
mSwipeStart = [[touches anyObject] locationInView:self].x;
mSwiping = YES;
mLeftImageView.hidden = NO;
mCurrentImageView.hidden = NO;
mRightImageView.hidden = NO;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (! mSwiping || [touches count] != 1)
return;
CGFloat swipeDistance = [[touches anyObject] locationInView:self].x - mSwipeStart;
CGSize contentSize = self.frame.size;
mLeftImageView.frame = CGRectMake(swipeDistance - contentSize.width, 0.0f, contentSize.width, contentSize.height);
mCurrentImageView.frame = CGRectMake(swipeDistance, 0.0f, contentSize.width, contentSize.height);
mRightImageView.frame = CGRectMake(swipeDistance + contentSize.width, 0.0f, contentSize.width, contentSize.height);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (! mSwiping)
return;
CGSize contentSize = self.frame.size;
NSUInteger count = [mImages count];
CGFloat swipeDistance = [[touches anyObject] locationInView:self].x - mSwipeStart;
if (mCurrentImage > 0 && swipeDistance > 50.0f)
{
[mRightImageView removeFromSuperview];
[mRightImageView release];
mRightImageView = mCurrentImageView;
mCurrentImageView = mLeftImageView;
mCurrentImage--;
if (mCurrentImage > 0)
{
mLeftImageView = [self createImageView:mCurrentImage - 1];
mLeftImageView.hidden = YES;
[self addSubview:mLeftImageView];
}
else
{
mLeftImageView = nil;
}
}
else if (mCurrentImage < count - 1 && swipeDistance < -50.0f)
{
[mLeftImageView removeFromSuperview];
[mLeftImageView release];
mLeftImageView = mCurrentImageView;
mCurrentImageView = mRightImageView;
mCurrentImage++;
if (mCurrentImage < count - 1)
{
mRightImageView = [self createImageView:mCurrentImage + 1];
mRightImageView.hidden = YES;
[self addSubview:mRightImageView];
}
else
{
mRightImageView = nil;
}
}
[UIView beginAnimations:#"swipe" context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:0.3f];
mLeftImageView.frame = CGRectMake(-contentSize.width, 0.0f, contentSize.width, contentSize.height);
mCurrentImageView.frame = CGRectMake(0.0f, 0.0f, contentSize.width, contentSize.height);
mRightImageView.frame = CGRectMake(contentSize.width, 0.0f, contentSize.width, contentSize.height);
[UIView commitAnimations];
mSwiping = NO;
}
#end // SlideShowView
#pragma mark -
#implementation SlideShowViewController
#synthesize toolbar;
-(IBAction) goBack:(id) sender{
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
- (id)init
{
if (self = [super initWithNibName:nil bundle:nil])
{
NSArray * images = [NSArray arrayWithObjects:[UIImage imageNamed:#"bifColor.png"],
[UIImage imageNamed:#"DSCF1600.jpg"],
[UIImage imageNamed:#"refresh.png"],
[UIImage imageNamed:#"DSCF1601.jpg"], nil];
self.view = [[[SlideShowView alloc] initWithImages:images] autorelease];
}
return self;
}
#end
Instead of this:
self.view = [[[SlideShowView alloc] initWithImages:images] autorelease];
do that:
UIView* slideShowView = [[[SlideShowView alloc] initWithImages:images] autorelease];
[self.view addSubview:slideShowView];
EDIT: Also don't forget to set the frame of slideShowView!

Xcode: UIScrollView image gallery, having memory problems

I'm Trying to develop an UIScrollView Based Image gallery.
So let me explain what i'm trying to achieve here:
I want to a sliding presentation, that can show upto 140 image. ( You can swipe back and forth )
I've found information on the web, and i've been told the best way to do this is with a UIScrollview which has 3 UIImageViews which you create and remove from superview.
So i managed to create such a "sliding image gallery" with some help from a few tutorials :).
I've managed to upload the application to the ipad, start up the application and run it.
after i viewed about 50-70 slides the app crashes ( out of memory). My knowledge of Obj. C isn't that great .
You'll find the code below: it Prob. has something to do with releasing the images.
Improvements to the code would be really helpful
#import "ParatelPresentationViewController.h"
//Define the UIView ( we need 3 Image Views left, mid right);
#interface SlideShowView : UIView
{
NSArray * mImages;
UIImageView * mLeftImageView;
UIImageView * mCurrentImageView;
UIImageView * mRightImageView;
NSUInteger mCurrentImage;
BOOL mSwiping;
CGFloat mSwipeStart;
}
- (id)initWithImages:(NSArray *)inImages;
#end // SlideShowView
#pragma mark -
#implementation SlideShowView
- (UIImageView *)createImageView:(NSUInteger)inImageIndex
{
if (inImageIndex >= [mImages count])
{
return nil;
}
UIImageView * result = [[UIImageView alloc] initWithImage:[mImages objectAtIndex:inImageIndex]];
result.opaque = YES;
result.userInteractionEnabled = NO;
result.backgroundColor = [UIColor blackColor];
result.contentMode = UIViewContentModeScaleAspectFit;
result.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight ;
return result;
}
- (id)initWithImages:(NSArray *)inImages
{
if (self = [super initWithFrame:CGRectZero])
{
mImages = [inImages retain];
NSUInteger imageCount = [inImages count];
NSLog(#"hoeveel foto's: %i");
if (imageCount > 0)
{
mCurrentImageView = [self createImageView:0];
[self addSubview:mCurrentImageView];
if (imageCount > 1)
{
mRightImageView = [self createImageView:1];
[self addSubview:mRightImageView];
}
}
self.opaque = YES;
self.backgroundColor = [UIColor blueColor];
self.contentMode = UIViewContentModeScaleAspectFit;
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
return self;
}
- (void)dealloc
{
[mImages release];
[super dealloc];
}
- (void)layoutSubviews
{
if (mSwiping)
return;
//CGSize contentSize = self.frame.size; // Enable when you use content.width/height
//self.backgroundColor = [UIColor redColor];
mLeftImageView.frame = CGRectMake(-1024, 0.0f, 1024, 748);// (-1024, 0.0f, 1024, 748) can be replaced by (-contentSize.width, 0.0f, contentSize.width, contentSize.height);
mCurrentImageView.frame = CGRectMake(0.0f, 0.0f, 1024, 748);
mRightImageView.frame = CGRectMake(1024, 0.0f, 1024, 748);
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([touches count] != 1)
return;
mSwipeStart = [[touches anyObject] locationInView:self].x;
mSwiping = YES;
mLeftImageView.hidden = NO;
mCurrentImageView.hidden = NO;
mRightImageView.hidden = NO;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (! mSwiping || [touches count] != 1)
return;
CGFloat swipeDistance = [[touches anyObject] locationInView:self].x - mSwipeStart;
//CGSize contentSize = self.frame.size;
mLeftImageView.frame = CGRectMake(swipeDistance - 1024, 0.0f, 1024, 748);
mCurrentImageView.frame = CGRectMake(swipeDistance, 0.0f, 1024, 748);
mRightImageView.frame = CGRectMake(swipeDistance + 1024, 0.0f, 1024, 748);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (! mSwiping)
return;
//CGSize contentSize = self.frame.size;
NSUInteger count = [mImages count];
CGFloat swipeDistance = [[touches anyObject] locationInView:self].x - mSwipeStart;
if (mCurrentImage > 0 && swipeDistance > 50.0f)
{
mRightImageView.image = nil;
//[mRightImageView.image release];
[mRightImageView removeFromSuperview];
[mRightImageView release];
//mRightImageView = nil;
//NSLog(#"Count of mRight : %i",[mRightImageView retainCount]);
mRightImageView = mCurrentImageView;
mCurrentImageView = mLeftImageView;
mCurrentImage--;
if (mCurrentImage > 0)
{
mLeftImageView = [self createImageView:mCurrentImage - 1];
mLeftImageView.hidden = YES;
[self addSubview:mLeftImageView];
}
else
{
mLeftImageView = nil;
}
}
else if (mCurrentImage < count - 1 && swipeDistance < -50.0f)
{
mLeftImageView.image = nil;
//[mLeftImageView.image release];
[mLeftImageView removeFromSuperview];
[mLeftImageView release];
//mLeftImageView = nil;
mLeftImageView = mCurrentImageView;
mCurrentImageView = mRightImageView;
mCurrentImage++;
if (mCurrentImage < count - 1)
{
mRightImageView = [self createImageView:mCurrentImage + 1];
mRightImageView.hidden = YES;
[self addSubview:mRightImageView];
NSLog(#"Count of mRight : %i",[mRightImageView.image retainCount]);
}
else
{
mRightImageView = nil;
}
}
[UIView beginAnimations:#"swipe" context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:0.3f];
mLeftImageView.frame = CGRectMake(-1024, 0.0f, 1024, 748);
mCurrentImageView.frame = CGRectMake(0.0f, 0.0f, 1024, 748);
mRightImageView.frame = CGRectMake(1024, 0.0f, 1024, 748);
[UIView commitAnimations];
mSwiping = NO;
}
#end // SlideShowView
#pragma mark -
#implementation ParatelPresentationViewController
- (id)init
{
if (self = [super initWithNibName:nil bundle:nil])
{
NSMutableArray *Displayimages = [[NSMutableArray alloc]init];
int i;
for(i=0 ; i<139 ; i++) {
NSString *tempString = [NSString stringWithFormat:#"Dia%d", i+1];
NSLog(#"Dia%d.jpg", i+1);
NSString *imageFile = [[NSBundle mainBundle] pathForResource:tempString ofType:#"JPG"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:imageFile];
if (fileExists){
[Displayimages addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:tempString ofType:#"JPG"]]];
NSLog(#"img");
}else {
break;
}
}
//NSArray * images = [NSArray arrayWithObjects:[UIImage imageNamed:#"1.jpg"], [UIImage imageNamed:#"2.jpg"], [UIImage imageNamed:#"3.jpg"], [UIImage imageNamed:#"4.jpg"], [UIImage imageNamed:#"5.jpg"], nil];
//NSLog(#"Objects Img = %#", images);
NSLog(#"Images %#",Displayimages);
self.view = [[[SlideShowView alloc] initWithImages:Displayimages] autorelease];
[Displayimages release];
}
return self;
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
//return YES;
return UIInterfaceOrientationIsLandscape (interfaceOrientation);
}
#end
If you would find a solution or tips, all are welcome !
Thanks in advance
kind regards Bart !
You definitely have a memory leak in createImageView:. You will have to change
return result;
to
return [result autorelease];
There might be more leaks, but that's an obvious one.
Johannes

Move an UIImageView around in a UIScrollView

I'm creating an application where I want to let the user move (not pan) an UIImageView around by dragging it on the screen. Additionally, I want the user to be able to zoom the UIImageView in and out.
As such I've been using a custom UIScrollView that forwards single touches to the 'contentView':
#implementation JM_UIScrollView
- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
NSSet *allTouches = [event allTouches];
NSLog(#"Checking for touches: %d", [allTouches count]);
if ([allTouches count] == 1) {
return YES;
}
return NO;
}
#end
Along with a custom UIImageView that implements touchesBegan and touchesMoved to determine where to move the UIImageView:
#implementation JM_UIImageView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
if ([allTouches count] == 0)
return;
UITouch *firstTouch = [[allTouches allObjects] objectAtIndex: 0];
CGPoint touchLoc = [firstTouch locationInView: [self superview]];
touchOffset= CGPointMake(touchLoc.x-self.center.x,touchLoc.y-self.center.y);
NSLog(#"Currently at: %3.3f x %3.3f", touchLoc.x, touchLoc.y);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
if ([allTouches count] == 0)
return;
UITouch *firstTouch = [[allTouches allObjects] objectAtIndex: 0];
CGPoint touchLoc = [firstTouch locationInView: [self superview]];
if ([allTouches count] == 1)
{
if ([firstTouch view] == self)
{
touchLoc.x -= touchOffset.x;
touchLoc.y -= touchOffset.y;
NSLog(#"Moved to: %3.3f x %3.3f", touchLoc.x, touchLoc.y);
self.center = touchLoc;
}
}
}
#end
This is then all glued together:
scrollView = [[JM_UIScrollView alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
scrollView.delegate = self;
scrollView.bouncesZoom = YES;
scrollView.scrollEnabled = NO;
scrollView.backgroundColor = [UIColor redColor];
scrollView.clipsToBounds = YES;
UIImage *image = [UIImage imageNamed:#"berg.jpg"];
imageView = [[JM_UIImageView alloc] initWithFrame: CGRectMake(0, 0, 140, 230)];
imageView.image = image;
imageView.center = CGPointMake(200,300);
[imageView setUserInteractionEnabled: YES];
[scrollView addSubview: imageView];
scrollView.contentSize = CGSizeMake(140,230);
scrollView.minimumZoomScale = 0.2;
scrollView.maximumZoomScale = 1.1;
[window addSubview: scrollView];
// Override point for customization after application launch
[window makeKeyAndVisible];
The problem:
When I start the application, I can move the UIImageView just fine and fluently. I can zoom-in and still be able to move it around.
However, it seems that whenever I zoom back out to the maximum level I seem then unable to move the UIImageView around anymore. It will jump at times, but by a maximum of 10 pixels. Use of NSLog() shows the touchesBegan/touchesMoved methods on the JM_UIImageView are no longer called.
Does anyone have any idea on what I might be missing here?
EDIT:
Would also accept an answer for wether or not this is the only way of implementing pinch-zooming with the zoombounce animation.