How to call a method within another method - iphone

I placed resumeLayer and PauseLayer method definitions within the #interface and #end block in h file.
#interface MainViewController : UIViewController
#property (nonatomic, retain) UIToolbar *toolbar;
#property (strong)AVAudioPlayer *audioPlayer;
#property (nonatomic, retain) NSTimer * timer;
- (void)resumeLayer:(CALayer *)layer;
- (void)pauseLayer:(CALayer *)layer;
#end
methods in m file
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
Now want to call resumeLayer and PauseLayer method in PlayPauseAction method
-(void)playpauseAction:(id)sender {
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
[self pauseLayer: CALayer];
}
else
{
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
if(isFirstTime == YES)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO;
}
}
}
Now when i call
[self PauseLayer:CALayer];
&
[self resumeLayer:CALayer];
gets message in red that unexpected interface name CALayer expected expression.
Anyone can please tell how to call PauseLayer and resumeLayer method in playpauseAction method.
Thanks for help.

This line does not make sense:
[self pauseLayer:CALayer];
because CALayer is a class. The compiler expects you to send in an object of type CALayer.
You need to do something like:
//Get a reference to your UIImageView somehow
UIImageView *myImageView = [yourOtherClass getTheImageView];
[self pauseLayer:myImageView.layer]; // Pause the CALayer of the UIImageView
To explain why, compare with this code, lets say you have a method like this one to add a number from an NSNumber to an int "totalValue" that is stored inside a class:
/** Adds the number to totalValue **/
-(int)addNumber:(NSNumber)number {
totalValue = totalValue + [number intValue];
return totalValue;
}
The correct way to call this method would be for example:
// Store the value 10 into an NSNumber
NSNumber *numberToAdd = [NSNumber numberWithInt:10];
[self addNumber:numberToAdd]; // Add number 10 to totalValue
But this is what you are trying to do:
[self addNumber:NSNumber]; // WRONG, 'NSNumber' is not a value!
The compiler complains because CALayer is not a value, just like NSNumber is not a value. You can not do an operation like 10 + NSNumber. The code above wants an object, an instance of the class NSNumber, not a reference to the NSNumber class itself.

you need to put an instant not a class when you can your methods ..
so instead of calling it like this
[self PauseLayer:CALayer];
do something like
[self PauseLayer:(UIButton*)sender.layer];

Try changing the P on
-(void)pauseLayer:(CALayer*)layer {
to uppercase or the way around.

Related

iphone - getting UIImageView to repeatedly move

Background: I am using xcode 3.1.4 and iphone simulator 3.1 (I know it's outdated and please dont comment about that).
Goal: I am trying to get a UIImageView that is created once the view loads to continuously move down. Creating the UIImageView works fine, but the move function does not work. Nothing happens. I use an NSTimer. Here is my code in the view controller.m file:
-(void)viewDidLoad{
UIImageView *six = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"Meteor.png"]];
CGRect rectSix = CGRectMake(arc4random() % (250), arc4random() % (1), 35, 35);
[six setFrame:rectSix];
[self.view addSubview:six];
[self moveMeteor:six];
[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:#selector(moveMeteor:) userInfo:six repeats:YES];
}
-(void)moveMeteor:(UIImageView *)t{
t.center=CGPointMake(t.center.x, t.center.y + 1);
}
And of course, I declared my moveMeteor function in the view controller.h file. By typing in:
-(void)moveMeteor:(UIImageView *)t;
Any ideas of what the problem is and a solution to it?
Or you could do something like this, which takes advantage of UIView's animateWithDuration and should look much better. No timer required.
// in your interface declaration...
#property (nonatomic, assign) BOOL meteorShouldAnimate;
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
// in your implementation...
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.meteorShouldAnimate = YES;
[self moveMeteorWithAnimationOptions:UIViewAnimationOptionCurveEaseIn]; // ease in to the animation initially
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.meteorShouldAnimate = NO;
}
- (void)moveMeteorWithAnimationOptions: (UIViewAnimationOptions) options {
__weak MyViewController * weakSelf = self;
if (self.meteorShouldAnimate) {
[UIView animateWithDuration:0.2 delay:0.0 options:options animations:^{
self.imageView.transform = CGAffineTransformMakeTranslation(20.0, 20.0); // or whatever x and y values you choose
} completion:^(BOOL finished) {
MyViewController * strongSelf = weakSelf; // in case our view controller is destroyed before our completion handler is called
if (strongSelf) {
UIViewAnimationOptions nextOptions = strongSelf.meteorShouldAnimate ? UIViewAnimationOptionCurveLinear : UIViewAnimationOptionCurveEaseOut; // linear if we're continuing to animate, ease out if we're stopping
[strongSelf moveMeteorWithAnimationOptions:nextOptions];
}
}];
}
}
Your method is actually not getting the right parameter, you get NSTimer as a parameter. so instead
-(void)moveMeteor:(UIImageView *)t
the method should be like this
-(void)moveMeteor:(NSTimer *)timer
and you can't treat NSTimer as an UIImageView. :)
*Edit
I would suggest you to do something like
-(void)viewDidLoad{
UIImageView *six = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"Meteor.png"]];
CGRect rectSix = CGRectMake(arc4random() % (250), arc4random() % (250), 35, 35);
[six setFrame:rectSix];
[self.view addSubview:six];
[self moveMeteor:six];
[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:#selector(moveMeteor:) userInfo:six repeats:YES];
}
and update your method to this
- (void)moveMeteor:(NSTimer *)timer {
UIImageView *six = timer.userInfo;
six.center=CGPointMake(six.center.x, six.center.y + 1);
}
just for information, I am passing the UIImageView in the dictionary as userInfo.

Can you customize UISlider like the "unlock slider" in iPhone?

I have a question about UISliders in IOS and to what extent you can customize them?
I would like to implement a slider like the "Unlock slider" in iPhone.
But it seems like IOS have not provided any "standard" ways for implementing a slider like this?.
Is it possible to implement a standard UISlider and set it to a min.value (0.0) and maximum.value (0.5). If the slider "hits" a value greater then (0.01) it should automatically be pulled back to the min.value (0.0).
If it hits the maximum value (0.5), start an event then automatically pulled back to min.value?
All help is appreciated!
Try this. I use this in my Project
Slider.h
#class Slider;
#protocol SliderDelegate <NSObject>
#required
- (void) slideEnd;
#end
#interface Slider : UISlider
#property (nonatomic, weak) id<SliderDelegate> delegate;
Slider.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setMinimumTrackImage:YOUR_MINIMUM_TRACK_IMG forState:UIControlStateNormal];
[self setMaximumTrackImage:YOUR_MAXIMUM_TRACK_IMG forState:UIControlStateNormal];
[self setThumbImage:YOUR_THUMB_IMAGE];
self.minimumValue = 0.0;
self.maximumValue = 1.0;
self.value = 0.0;
[self addTarget:self action:#selector(moved:) forControlEvents:UIControlEventTouchUpInside];
[self addTarget:self action:#selector(moved:) forControlEvents:UIControlEventTouchUpOutside];
}
return self;
}
- (void) moved:(UISlider *) sender
{
if (self.value != 1.0) {
[self setValue: 0 animated: YES];
} else {
[[self delegate] slideEnd];
[self setValue: 0 animated: YES];
}
}
Implement it like this:
[self setSlider:[[Slider alloc] initWithFrame:CGRectMake(645, 25, 120, 50)]];
[[self view] addSubview:[self slider]];
[[self view] bringSubviewToFront:[self slider]];
[[self slider] setDelegate:self];
Don't forget to implement the delegate method:
- (void)slideEnd {
// Things you want to do when slide ends
}

Reference of UIImageview layer created in separate class

Defined resumeLayer and PauseLayer method within the #interface and #end block in h file.
#interface MainViewController : UIViewController
#property (nonatomic, retain) UIToolbar *toolbar;
#property (strong)AVAudioPlayer *audioPlayer;
#property (nonatomic, retain) NSTimer * timer;
- (void)resumeLayer:(CALayer *)layer;
- (void)pauseLayer:(CALayer *)layer;
#end
methods in m file
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
For calling resumeLayer and PauseLayer method in PlayPauseAction method
-(void)playpauseAction:(id)sender {
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
[self pauseLayer:ImageView.layer]; // Pause the CALayer of the UIImageView
}else{
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
if(isFirstTime == YES){
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO;
}
}
}
ImageView is defined in class named Third
- (void)viewDidLoad
{
// Displays UIImageView
UIImageView* ImageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 5, 300, 235)];
self.view.backgroundColor = [UIColor brownColor];
// load all the frames of our animation
ImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"3a.png"],
[UIImage imageNamed:#"3b.png"],
nil];
// all frames will execute in 24 seconds
ImageView.animationDuration = 24;
// start animating
[ImageView startAnimating];
ImageView.layer.borderWidth = 2;
ImageView.layer.borderColor = [[UIColor whiteColor]CGColor];
[ImageView.layer setMasksToBounds:YES];
[ImageView.layer setCornerRadius:15.0f];
[self.view addSubview:ImageView]; }
I want to get reference of this ImageView.layer in MainViewController class to use in
[self pauseLayer:ImageView.layer];
to pause imageview.layer animation
Now how can i get reference of this ImageView using
UIImageView *myImageView = [OtherClass getTheImageView];
to use following in playpauseAction to pause and resume Imageview layer animation
[self pauseLayer:myImageView.layer]; // Pause the CALayer of the UIImageView
Any one can help me with thisHow to reference ImageView.layer in MainviewController
Either you add a property to MainviewController and let ImageView set its value when it's ready, or you use NSNotificationCenter to send a notification from MainViewController to ImageView;
In ImageView:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pauseMyLayer) name:kPauseLayerNotif object:nil];
In MainViewController:
[[NSNotificationCenter defaultCenter] postNotificationName:kPauseLayerNotif object:self];
The notification mechanism provides you a very loose coupling between the two classes and it is very easy to use.

How to create a new UIImageView with a different instance variable every time a timer is called

how are you guy's?
I want to make a new instance variable every time a timer is called for e.g.
numberofObjects += 1;
i = numberofObjects;
UIImageView *Object[i] = [[UIImageView alloc] initWithFrame:CGRectMake(randomx,0,36 ,36)];
UIImage *imag = [UIImage imageNamed:#"ball.png"];
[Object[i] setImage:imag];
[self.view addSubview:Object[i]];
Is there a way to do this?
Any comments will be appreciated.
This isn't too hard to do. I make the assumption that you are only going to have a maximum number of UIImageViews, as this can add a lot of overhead, and you may run into problems if it's allowed to continue forever. In the .h file,
#interface viewController : UIViewController {
int numberAdded;
NSTimer * timer;
UIImageView * currentImageView;
NSMutableArray * arrayOfImageViews;
}
- (void)addNewImageView;
#end
In the .m file:
#define MaxImageViews 20 // This is changeable!
#implementation viewController
- (void)viewDidLoad; {
[super viewDidLoad];
numberAdded = 0;
arrayOfImageViews = [[NSMutableArray alloc] init];
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(addNewImageView) userInfo:nil repeats:YES];
}
- (void)addNewImageView; {
if(numberAdded >= MaxImageViews){
[timer invalidate];
timer = nil;
return;
}
int randomX = arc4random() % 320; // Gives value from 0 - 319.
int randomY = arc4random() % 480; // Gives value from 0 - 479.
UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(randomX, randomY, 36, 36)];
imageView.image = [UIImage imageNamed:#"ball.png"];
[self.view addSubview:imageView];
[arrayOfImageViews addObject:imageView];
[currentImageView release];
currentImageView = imageView;
}
- (void)dealloc; {
[currentImageView release];
[arrayOfImageViews release];
[super dealloc];
}
#end
This should keep track of all of the imageViews in the array arrayOfImageViews, and you can access the i-th imageView by calling [arrayOfImageViews objectAtIndex:i]. The currentImageView pointer keeps track of the latest UIImageView added. Hope that helps!
Store the image views' pointers in an NSMutableArray object.

How do I initialize this custom class that inherits from UIButton?

I can't figure out how I'm supposed to initialize this custom class, the code isn't mine and I'm fairly new to Obj-C, so I'm slow on the uptake.
PFTintedButton.h
#import <UIKit/UIKit.h>
#class CALayer;
typedef enum
{
PFTintedButtonRenderTypeStandard,
PFTintedButtonRenderTypeCandy,
PFTintedButtonRenderTypeOpal,
} PFTintedButtonRenderType;
#interface PFTintedButton : UIButton
{
#private
UIColor * tint;
CGFloat cornerRadius;
PFTintedButtonRenderType renderType;
UIImage * stretchImage;
CALayer * glowLayer;
UILabel * subLabel;
BOOL customShadow;
BOOL customTitleColor;
}
#property( nonatomic, retain ) UIColor * tint;
#property( nonatomic, assign ) CGFloat cornerRadius;
#property( nonatomic, assign ) PFTintedButtonRenderType renderType;
#property( nonatomic, readonly ) UILabel * subLabel;
#end
PFTintedButton.m excerpt
#import "PFTintedButton.h"
#import "PFDrawTools.h"
#import "UIColor+PFExtensions.h"
#import <QuartzCore/QuartzCore.h>
#define glowRadius 30
#interface PFTintedButton()
-(void) createBackgroundImage;
-(void) createGlowLayer;
#end
#implementation PFTintedButton
-(void) dealloc
{
SafeRelease( tint );
SafeRelease( stretchImage );
SafeRelease( subLabel );
SafeRelease( glowLayer );
[NSObject cancelPreviousPerformRequestsWithTarget: self selector: #selector(createGlowLayer) object: nil];
[NSObject cancelPreviousPerformRequestsWithTarget: self selector: #selector(renderGlowLayerOnMainThread) object: nil];
[super dealloc];
}
-(void) initCommon
{
cornerRadius = 6;
}
-(id) initWithFrame: (CGRect) frame
{
if( self = [super initWithFrame: frame] )
{
[self initCommon];
}
return self;
}
-(id) initWithCoder: (NSCoder *) coder
{
if( self = [super initWithCoder: coder] )
{
// this is such a hack but there's no other way to determine if the title label's settings
// have been modified in IB.
NSDictionary * dic = [coder decodeObjectForKey: #"UIButtonStatefulContent"];
NSObject * st = [dic objectForKey: [NSNumber numberWithInt: UIControlStateNormal]];
NSString * bc = [st description];
customTitleColor = [bc rangeOfString: #"TitleColor = UIDeviceRGBColorSpace 0.196078 0.309804 0.521569 1"].location == NSNotFound;
customShadow = [bc rangeOfString: #"ShadowColor = UIDeviceRGBColorSpace 0.5 0.5 0.5 1"].location == NSNotFound;
[self initCommon];
//[super setBackgroundColor: [[UIColor redColor] colorWithAlphaComponent: .5]];
}
return self;
}
I just included a small bit of the implementation, the full source can be found here. As a part of this repository by Paul-Alexander.
I initialize it like this:
PFTintedButton* buttony = [PFTintedButton buttonWithType:UIButtonTypeCustom];
[buttony setTint:[UIColor redColor]];
[buttony setBackgroundColor:[UIColor redColor]];
[buttony setRenderType:PFTintedButtonRenderTypeCandy];
[buttony setTitle:#"Title for Button" forState:UIControlStateNormal];
And it hiccups in PFDrawTools, it seems the tint variable is nil. So is it because I am initializing it incorrectly? Has anyone had success with this?
It seems to explicitly handle initWithFrame, I would try that.
PFTintedButton *buttony = [[[PFTintedButton alloc] initWithFrame:<some_frame>] autorelease];
Try this instead:
PFTintedButton* buttony = [[PFTintedButton alloc] initWithFrame:CGRectMake(x, y, width, height)];
Have you defined buttonWithType: initialize method in PFTintedButton class?