Lower the CPU usage of an app - iphone

I am having an issue with CPU usage. When I starts my app its animation starts at good speed and all of sudden animation speed gets lower down and then app gets crashed. But when I checked the app with Activity Monitor(Instrument) my app use CPU near about 80%-90%. I am unable reduce the CPU usage.
CODE:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint location;
UITouch *touch = [[event allTouches] anyObject];
location = [touch locationInView:self.view];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint location;
UITouch *touch = [[event allTouches] anyObject];
location = [touch locationInView:self.view];
touchMovedX = location.x;
touchMovedY = location.y;
[self merge];
}
// -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
//{
// [self merge];
// }
-(void)merge
{
CGSize size = CGSizeMake(320, 480);
UIGraphicsBeginImageContext(size);
CGPoint point1 = CGPointMake(0,0);
CGPoint point2 = CGPointMake(touchMovedX,touchMovedY);
UIImage *imageOne = [UIImage imageNamed:#"iphone.png"];
[imageOne drawAtPoint:point1];
UIImage *imageTwo = [UIImage imageNamed:#"Cloud.png"];
[imageTwo drawAtPoint:point2];
imageB.image=imageTwo;
UIImage *imageC = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageview = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,320,480)];
imageview.image=imageC;
[self.view addSubview:imageview];
}
-(IBAction)save:(id)sender {
UIImage* imageToSave = imageview.image;
UIImageWriteToSavedPhotosAlbum(imageToSave, nil, nil, nil);
[imageToSave release];
}
Any help would be appreciable.
Thanks

Don't call touchesMoved in your touchesBegan code. touchesMoved is called by iOS in response to touches being moved
Likewise with touchesEnded - this gets called when the user removes the finger from the screen
In addition - your code for merge is adding more and more subviews to your view - at the end of every call to merge you are callin [self.view addSubview:imageview] which is going increase your CPU usage in handling all the subviews. Everytime you move your finger in touches moved then this will be adding a new subview and never removing them.

-(void)viewDidAppear:(BOOL)animated{
UIPanGestureRecognizer *pgr1 = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(image1Moved:)];
[iv1 addGestureRecognizer:pgr1];
}
-(void)image1Moved:(UIPanGestureRecognizer *)pgr{
NSLog(#"Came here");
[iv1 setCenter:[pgr locationInView:self.view]];
}
Do some thing like the above. Where you can move the imageview.
Also, call the merge using another button, where you move the image at will, but when it is time to merge, click a button. That way, you will call Merge only once and it will not be any load on the CPU.
Looks like you are a beginner and I would highly recommend that you follow some tutorials and learn some more about
Instance Variables
Properties
gesture recognizers etc

It is not touchesMoved or touchesBegan which is causing the CPU usage. It is definitely [self merge]. I am assuming that you are doing some CPU intensive job in [self merge] and that is being done so many times.
You have to do any CPU intensive job on another thread for the app to be responsive. Also if you are doing stuff at every move, then it may become too slow.
Please post the code for what you are doing in merge method.
There are three things which you can do
Improve the merge method to make it efficient.
Use Grand Central dispatch
Read up about dispatch_async(dispatch_get_global_queue, ^{ }); etc. This will be under Grand Central Dispatch section.
Another way is to do [self performSelector:#(merge) afterDelay:0.5s];
This method will call merge, only once every 0.5 seconds.
and then if you do not want the same method to be called so many times, or it is not necessary for every move, just before that call
[NSObject cancelPreviousPerformRequestsWithTarget:<#(id)#> selector:<#(SEL)#> object:<#(id)#>
The cancel method will cancel previous invocations and call the method again.
But again, it all depends on what you are trying to do.

Related

frame by frame animation with UIGestureRecognizer

I would like to show an animation with images of an object rotating.
I have an NSArray with frames of the object and I would like to display them frame by frame with the property of UIImageView animationImages.
The problem is that I would like to control the animation with UISwipeGestureRecognizer (Right and Left). And depending on the speed of the gesture the object should rotate faster or slower. I think is not possible because the gesture it is called just once and not continuously.
(NOTE: this is my first question in StackOverflow)
Thank you in advance
EDIT: I just post my solution. Maybe it can be useful for anybody. I think it's useful.
Firstly: add gesture to the view.
self.recognizer = [[UISwipeGestureRecognizer alloc] init];
self.recognizer.cancelsTouchesInView=NO;
[self.view addGestureRecognizer:self.recognizer];
Secondly: in tocuhMoved method I display the frame that I need depending of the direction of the previous touch. It is called by the event of the user.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
NSInteger image= [self.animationView.animationImages indexOfObject:self.animationView.image];
UITouch *touch = [touches anyObject];
NSLog(#"Touch moved with index:%i", image);
if ((positionTouch.x<[touch locationInView:self.animationView].x)) {
if (image==24) {
self.animationView.image=[self.animationView.animationImages objectAtIndex:0];
}
else{
self.animationView.image=[self.animationView.animationImages objectAtIndex:image+1];
}
}
else if((positionTouch.x>[touch locationInView:self.animationView].x)){
if (image==0) {
self.animationView.image=[self.animationView.animationImages objectAtIndex:24];
}
else{
self.animationView.image=[self.animationView.animationImages objectAtIndex:image-1];
}
}
positionTouch= [touch locationInView:self.animationView];
}
Don't forget <UIGestureRecognizerDelegate>
with this method, I fill the array of frames...
-(void)addPictures{
NSMutableArray* mArray=[[NSMutableArray alloc]initWithCapacity:25];
for (int i=0; i<25; i++) {
[mArray insertObject:[UIImage imageNamed:[NSString stringWithFormat:#"Picture %i.jpg", i+1]] atIndex:i];
}
self.animationView.image=[mArray objectAtIndex:0];
self.animationView.animationImages=mArray;
[self.view addSubview:self.animationView];
}
It's actually very simple to control the speed of an animation. In fact, it's so simple (because CALayer conforms to the CAMediaTiming protocol) that the property to control it is literally called speed. It's all a matter of using the gesture as a sort of analog for a slider, and calculating an x value relative to it's location onscreen. This should be a suitable starting point:
//Speed changes necessitate a change in time offset, begin time, and
//speed itself. Simply assigning to speed it not enough, as the layer needs
//to be informed that it's animation timing function is being mutated. By
//assigning a new time offset and a new begin time, the layer
//automatically adjusts the time of any animations being run against it
layer.timeOffset = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.beginTime = CACurrentMediaTime();
layer.speed = ([self.gesture locationInView:self.view].x / CGRectGetWidth(self.view.bounds));

one touch in two button in same time

My app has 2 buttons, near.
I'm trying to touch this two buttons, at the same time, using only one finger.
There is a way to check if the touch is over this two buttons at same time?
You can (but really shouldnt) touch 2 buttons with one finger like Abizern said, but you can also call 2 methods for one button touch. For example:
-(void)viewDidLoad {
self.myButton = /*initialize the button*/;
[self.myButton addTarget:self action:#selector(callTwoMethods) forControlEvents:UIControlEventTouchUpInside];
}
-(void)callTwoMethods {
[self methodOne];
[self methodTwo];
}
However, this is not always the correct behavior for what you're trying to do, so starting with iOS 3, we can use a bit of jiggering with the UITouch and event mechanism to figure a lot of it out:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if ([touches count] == 2) {
//we are aware of two touches, so get them both
UITouch *firstTouch = [[allTouches allObjects] objectAtIndex:0];
UITouch *secondTouch = [[allTouches allObjects] objectAtIndex:1];
CGPoint firstPoint = [firstTouch locationInView:self.view];
CGPoint secondPoint = [secondTouch locationInView:self.view];
if ([self.firstButton pointInside:firstPoint withEvent:event] && [self.secondButton secondPoint withEvent:event] || /*the opposite test for firstButton getting the first and secondButton getting the second touch*/) {
//Do stuff
}
}
}
A touch is a point. Although the recommendation is to make controls of a reasonable size, when you touch the screen, you are getting a point, not a region. That point is going to be in one or other of the controls.
You could try to intercept the touch and turn it into a larger rectangle and see if that covers both the buttons at the same time.
EDIT
Have a look at this SO question to see one way of doing intercepting touches.

Making images appear... How?

Could someone please tell me how to make an image appear when the user taps the screen and make it appear at the position of the tap.
Thanks in advance,
Tate
UIView is a subclass of UIResponder, which has the following methods that might help: -touchesBegan:withEvent:, -touchesEnded:withEvent:, -touchesCancelled:withEvent: and -touchesMoved:withEvent:.
The first parameter of each of those is an NSSet of UITouch objects. UITouch has a -locationInView: instance method which should yield the position of the tap in your view.
You could create an initial star and just move it every time view is touched.
I'm not sure what you're end result will look like.
Note:
This code will give you 1 star that moves with a tap
Here is my code:-
(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
switch ([allTouches count]) {
case 1:
{
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint point = [touch locationInView:myView];
myStar.center = point;
break;
}
default:
break;
}
}
It seems implied from the question that you want the user to be able to tap anywhere on the screen and have an image drawn where they tap? As opposed to tapping in a designated place and having the image appear there?
If so, you're probably going to have to go with a custom view. In that case, you'd do something like the following:
Create a subclass of UIView.
Override the touchesBegan method. Call [[touches anyObject] locationInView:self] (where touches is the first argument to the method, an NSSet of UITouch objects) to get the location of the touch, and record it.
Override the touchesEnded method. Determine the location touches ended at using the same method as in step 2.
If the second location is near the first, you'll want to place your image at that location. Record that location and call [self setNeedsDisplay] to cause the custom view to be redrawn.
Override the drawRect method. Here, if the location has been set in step 4, you can use the UIImage method drawAtPoint to draw your image at the selected location.
For further details, this link might be worth a look. Hope that helps!
EDIT: I've notice you've asked essentially the same question before. If you're not happy with the answers given there, it's generally considered better to "bump" the old one, perhaps by editing it to ask for further clarification, rather than create a new question.
EDIT: As requested, some very brief sample code follows. This is probably not the best code around, and I haven't tested it, so it may be a little iffy. Just for clarification, the THRESHOLD allows the user to move their finger a little while tapping (up to 3px), because it's very difficult to tap without moving your finger a little.
MyView.h
#define THRESHOLD 3*3
#interface MyView : UIView
{
CGPoint touchPoint;
CGPoint drawPoint;
UIImage theImage;
}
#end
MyView.m
#implementation MyView
- (id) initWithFrame:(CGRect) newFrame
{
if (self = [super initWithFrame:newFrame])
{
touchPoint = CGPointZero;
drawPoint = CGPointMake(-1, -1);
theImage = [[UIImage imageNamed:#"myImage.png"] retain];
}
return self;
}
- (void) dealloc
{
[theImage release];
[super dealloc];
}
- (void) drawRect:(CGRect) rect
{
if (drawPoint.x > -1 && drawPoint.y > -1)
[theImage drawAtPoint:drawPoint];
}
- (void) touchesBegan:(NSSet*) touches withEvent:(UIEvent*) event
{
touchPoint = [[touches anyObject] locationInView:self];
}
- (void) touchesEnded:(NSSet*) touches withEvent:(UIEvent*) event
{
CGPoint point = [[touches anyObject] locationInView:self];
CGFloat dx = point.x - touchPoint.x, dy = point.y - touchPoint.y;
if (dx + dy < THRESHOLD)
{
drawPoint = point;
[self setNeedsDisplay];
}
}
#end

Drawing a UIImageView at position of user tap

This is the 2nd time I have asked this. How do I draw an image at the location of the user's tap every time the user taps the screen?
Could you please leave a sample project or code because I am new to iPhone programming and have a hard time understanding certain methods etc.
Thanks,
Tate
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
UIImageView * anImageView = [[UIImageView alloc] initWithImage:anImage];
[anImageView setCenter:[touch locationInView:self.view]];
[self.view addSubview:anImageView];
[anImageView release];
}
In the future, read the documentation or use Google.

Making a UIImageView appear when screen is tapped [duplicate]

Could someone please tell me how to make an image appear when the user taps the screen and make it appear at the position of the tap.
Thanks in advance,
Tate
UIView is a subclass of UIResponder, which has the following methods that might help: -touchesBegan:withEvent:, -touchesEnded:withEvent:, -touchesCancelled:withEvent: and -touchesMoved:withEvent:.
The first parameter of each of those is an NSSet of UITouch objects. UITouch has a -locationInView: instance method which should yield the position of the tap in your view.
You could create an initial star and just move it every time view is touched.
I'm not sure what you're end result will look like.
Note:
This code will give you 1 star that moves with a tap
Here is my code:-
(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
switch ([allTouches count]) {
case 1:
{
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint point = [touch locationInView:myView];
myStar.center = point;
break;
}
default:
break;
}
}
It seems implied from the question that you want the user to be able to tap anywhere on the screen and have an image drawn where they tap? As opposed to tapping in a designated place and having the image appear there?
If so, you're probably going to have to go with a custom view. In that case, you'd do something like the following:
Create a subclass of UIView.
Override the touchesBegan method. Call [[touches anyObject] locationInView:self] (where touches is the first argument to the method, an NSSet of UITouch objects) to get the location of the touch, and record it.
Override the touchesEnded method. Determine the location touches ended at using the same method as in step 2.
If the second location is near the first, you'll want to place your image at that location. Record that location and call [self setNeedsDisplay] to cause the custom view to be redrawn.
Override the drawRect method. Here, if the location has been set in step 4, you can use the UIImage method drawAtPoint to draw your image at the selected location.
For further details, this link might be worth a look. Hope that helps!
EDIT: I've notice you've asked essentially the same question before. If you're not happy with the answers given there, it's generally considered better to "bump" the old one, perhaps by editing it to ask for further clarification, rather than create a new question.
EDIT: As requested, some very brief sample code follows. This is probably not the best code around, and I haven't tested it, so it may be a little iffy. Just for clarification, the THRESHOLD allows the user to move their finger a little while tapping (up to 3px), because it's very difficult to tap without moving your finger a little.
MyView.h
#define THRESHOLD 3*3
#interface MyView : UIView
{
CGPoint touchPoint;
CGPoint drawPoint;
UIImage theImage;
}
#end
MyView.m
#implementation MyView
- (id) initWithFrame:(CGRect) newFrame
{
if (self = [super initWithFrame:newFrame])
{
touchPoint = CGPointZero;
drawPoint = CGPointMake(-1, -1);
theImage = [[UIImage imageNamed:#"myImage.png"] retain];
}
return self;
}
- (void) dealloc
{
[theImage release];
[super dealloc];
}
- (void) drawRect:(CGRect) rect
{
if (drawPoint.x > -1 && drawPoint.y > -1)
[theImage drawAtPoint:drawPoint];
}
- (void) touchesBegan:(NSSet*) touches withEvent:(UIEvent*) event
{
touchPoint = [[touches anyObject] locationInView:self];
}
- (void) touchesEnded:(NSSet*) touches withEvent:(UIEvent*) event
{
CGPoint point = [[touches anyObject] locationInView:self];
CGFloat dx = point.x - touchPoint.x, dy = point.y - touchPoint.y;
if (dx + dy < THRESHOLD)
{
drawPoint = point;
[self setNeedsDisplay];
}
}
#end