I used uibuttons to create a grid view, now need to select and deselect the button on its click.
All is working fine but when I try to play a sound on a button click, app get crashed by printing the below message in console:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIButton prepareToPlay]: unrecognized selector sent to instance 0x7526a20'
To play the sound,I have taken the object of AVAudioPlayer claas in .h file and initializing it in view did load method and playing it on button click, here is my code
.h file
#import <UIKit/UIKit.h>
#import <AVFoundation/AVAudioPlayer.h>
#import <AudioUnit/AudioUnit.h>
#interface PlayViewController : UIViewController<AVAudioPlayerDelegate>
{
IBOutlet UIButton *resetBtn;
UIButton *btn[25];
AVAudioPlayer *tapSound;
}
-(IBAction)reserBtnClkd;
#property(nonatomic,retain) AVAudioPlayer *tapSound;
#end
in .m file
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]]];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *path=[[NSBundle mainBundle] pathForResource:#"button-3" ofType:#"wav"];
AVAudioPlayer *Tapsound=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
self.tapSound=Tapsound;
[Tapsound release];
[pool release];
[self setTheIcons];
resetBtn.layer.cornerRadius=6.0;
resetBtn.backgroundColor=[UIColor colorWithRed:90/255.00 green:33.00/255.00 blue:179.00/255.00 alpha:1];
resetBtn.titleLabel.font=[UIFont fontWithName:#"Helvetica" size:22];
[resetBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
#pragma mark
#pragma mark<Creating The Grid View Of Icons>
#pragma mark
-(void) setTheIcons
{
int x=11;
int y=55;
for(int i=1;i<=25;i++)
{
btn[i]=[UIButton buttonWithType:UIButtonTypeCustom];
btn[i].frame=CGRectMake(x, y, 58,58);
[btn[i] addTarget:self action:#selector(btnClkd:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn[i]];
if(i%5==0)
{
x=11;
y=y+60;
}
else
{
x=x+60;
}
}
[self reserBtnClkd];
}
-(void)btnClkd:(UIButton*)sender
{
sender.selected=!sender.selected;
if(sender.selected)
{
// UIView *tempView=[[UIView alloc]initWithFrame:CGRectMake(12, 12, 34, 34)];
UIView *tempView=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 58, 58)];
tempView.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"hover-effectNew.png"]];
tempView.userInteractionEnabled=NO;
[sender addSubview:tempView];
[tempView release];
}
else
{
NSArray *subviewToRemove=[sender subviews];
int i=1;
for(UIView *view in subviewToRemove)
{
if(i==2)
{
[view removeFromSuperview];
}
i++;
}
}
[self.tapSound prepareToPlay];
[self.tapSound setDelegate:self];
[self.tapSound play];
}
And the strange thing is that App crashed only when I play the sound on button click method, otherwise if I play it in view did load then it works without any issue, Scratching my head for two days but could not find any solution, please help me
I think that the problem is that your self.tapSound is an UIButton(you can see it in the crash log: '-[UIButton prepareToPlay]: unrecognized selector sent to instance 0x7526a20'.
Try debugging it step by step and see what happens
I think because self.tapSoundis referencing Tapsound, when you call [Tapsound release] it releases the property as well. I would recommend instantiating the property directly, like this:
/*note that you have declared tapSound in your .h
as a class variable in addition to being a property.
This means you can access it as both.
Wherever you would type self.tapSound, instead use simply tapSound
*/
tapSound = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
Related
I am new to iPhone development.
I am developing an application in which I am using Single tone class.
When I am creating an object of single tone class it is giving me memory leak on analyzing my code. It is giving message as "Potential leak of an object" and "Allocated object is not referenced later". But I am using that object in my code.
following is my code where I have created single tone class object
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Inside View");
self.navigationController.navigationBar.topItem.title = #"Menu List";
UIImage *image = [UIImage imageNamed:#"Navigation_bar.png"];
[_bgImage setFrame:CGRectMake(0,-45,320,510)];
[self.navigationController.navigationBar setBackgroundImage:image
forBarMetrics:UIBarMetricsDefault];
[self.tabBarController.tabBar setBackgroundImage:[UIImage imageNamed:#"Tab_bar.png"]];
[self.navigationItem setHidesBackButton:YES];
menuTableView.backgroundColor=[UIColor clearColor];
menuTableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
_hotelMenu=[SharedHotelMenu sharedInstanceMethod];
_queryFormatter=[[DatabaseQueryFormatter alloc]init];
_isSearchOn=NO;
_searchResult=[[NSMutableArray alloc]init];
_categorySearch.layer.cornerRadius = 19;
_categorySearch.clipsToBounds = YES;
_categorySearch.delegate=self;
UIView *_paddingView=[[UIView alloc] initWithFrame:CGRectMake(0,0,5,10)];
_categorySearch.leftView=_paddingView;
_categorySearch.leftViewMode=UITextFieldViewModeAlways;
[_paddingView release];
UIView *_paddingRightView=[[UIView alloc] initWithFrame:CGRectMake(0,0,30,10)];
_categorySearch.rightView=_paddingRightView;
_categorySearch.rightViewMode=UITextFieldViewModeAlways;
[_paddingRightView release];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(searchBar)
name:UITextFieldTextDidChangeNotification object:_categorySearch];
}
}
I have created single tone class object as _hotelMenu=[SharedHotelMenu sharedInstanceMethod];
As far as I can see in your code is that this line may cause memory leak
menuTableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
As this is #property(nonatomic, retain) UIView *tableFooterView and it will retain your object and thus retain count becomes 2.
Use this
UIView *footerView = [[UIView alloc] initWithFrame:CGRectZero];
menuTableView.tableFooterView = footerView;
[footerView release];
I need to add an activityIndicator to a UIView.I have a button,when that button is clicked then it has to start animating. Actually when the button is clicked some data is received from rest service and parsing is done and then it is filled in UITableView.But the activity indicator is not getting animating..
- (void)viewDidLoad
{
[super viewDidLoad];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc]
initWithFrame:CGRectMake(0.0f, 0.0f, 20.0f, 20.0f)];
[activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview:activityIndicator];
}
-(IBAction)switchtoGetProviders
{
[activityIndicator startAnimating];
NSURL *urlString= [NSString stringWithFormat:#"http://230.32.232.32/services/service.svc/Xml"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc] init]autorelease];
..............//calling data from service url
}
After reciving the whole data it is assigned to UITableView.
How can I get it working ?
You can't start and stop activity indicator in one single function/method.
There are two methods to do this things.
If the request is Asynchronous then you need to start activity indicator at button click and stop when you receive response.
But if the request is synchronous then it is not possible to start and stop activity in one function.for this you need to start animation on button click and make separate method for send synchronous request and call that method using [self performSelector:] method. At the end you need to stop animating.
Updates:
-(IBAction)switchtoGetProviders
{
[activityIndicator startAnimating];
[self performSelector:#selector(startRequest) withObject:nil afterDelay:0];
}
- (void)startRequest
{
NSURL *urlString= [NSString stringWithFormat:#"http://230.32.232.32/services/service.svc/Xml"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc] init]autorelease];
..............//calling data from service url
[activityIndicator stopAnimating];
}
Probably this is due to the fact that you are making the webservice call and updating the UI at the same time on MAIN Thread. You must use GCD or detach another thread for making the webservice call.
Use this to detach a new thread
[NSThread detachNewThreadSelector:#selector(callWebserviceMethod:) toTarget:self withObject:nil];
In your code
-(IBAction)switchtoGetProviders
{
[activityIndicator startAnimating];
[NSThread detachNewThreadSelector:#selector(callWebserviceMethod:) toTarget:self withObject:nil];
}
-(void)callWebserviceMethod
{
NSURL *urlString= [NSString stringWithFormat:#"http://230.32.232.32/services/service.svc/Xml"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc] init]autorelease];
}
You should define activityIndicator as a property, in your code you have it as a local variable.
After defining it as a property, change the assignment line to:
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 20.0f, 20.0f)];
you need to get data from web service in background thread, as calling it on the main thread causes the UI to hang
see this
You have declared the UIActivityIndicatorView *activityIndicator in viewDidLoad method so it is local object only visible to this function you need to declare it in the header file or in class category in .m. When you declare the activityIndicator instance in the .h then you will be able to access this within your class. Either you can make it as property or just declare in .h then initialize in your viewDidLoad method without redeclaration.
just add this line in .h file
UIActivityIndicatorView *spinningWheel;
and in viewWillAppear method add this code..
spinningWheel = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(120, 200, 25.0, 25.0)];
spinningWheel.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;///UIActivityIndicatorViewStyleGray also use this if background white
[self.view addSubview:spinningWheel];
-(IBAction)switchtoGetProviders
{
[spinningWheel startAnimating];
NSURL *urlString= [NSString stringWithFormat:#"http://230.32.232.32/services/service.svc/Xml"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc] init]autorelease];
..............//calling data from service url
}
and when you get data or response at that time stopAnimating like bellow..
[spinningWheel stopAnimating];
Just do one this , declare it in .h file mean declare glibly
.h
#interface yourViewController : UIViewController
{
IBOutlet UIActivityIndicatorView *activityIndicator;
}
.m
- (void)viewDidLoad
{
[super viewDidLoad];
activityIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
activityIndicator.color = [UIColor blackColor];
[self.view addSubview:activityIndicator];
}
-(IBAction)switchtoGetProviders
{
[activityIndicator startAnimating];
NSURL *urlString= [NSString stringWithFormat:#"http://230.32.232.32/services/service.svc/Xml"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc] init]autorelease];
..............//calling data from service url
}
So, here's the situation (this is all in the simulator):
create a view controller. it owns an MPMoviePlayerController, and adds the player's view as a subview to its own.
set this vc as the window's rootViewController.
also in this vc's view is a button which will launch a modal view controller (which obscures the movie) after pausing the movie player.
click the button, launch the modal VC, then dismiss it.
notice that the paused image of the movie player is gone (it is just black).
click "play" to resume playing the movie
crash
Now, change your build target from iOS 4.3 to iOS 5.0 and it works flawlessly.
What's really bothering me is that this didn't cause a crash under 4.3 a month ago. In fact, I have an app in the store right now for which this works just fine: http://itunes.apple.com/us/app/es-musica-free/id474811522?mt=8
So, I've tried to boil this down to a minimal example which reproduces the problem.
Create a vanilla xcode project.
in your AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.backgroundColor = [UIColor blackColor];
[self.window makeKeyAndVisible];
UIViewController *vc = [[DemoMoviePlayerViewController alloc] init];
[self.window setRootViewController:vc];
[vc release];
vc = nil;
return YES;
}
DemoMoviePlayerViewController is pretty simple. here's the h file:
#import
#import
#interface DemoMoviePlayerViewController : UIViewController
{
MPMoviePlayerController *moviePlayer_;
}
#end
and the m file:
#import "DemoMoviePlayerViewController.h"
#interface DemoMoviePlayerViewController (InternalMethods)
- (void)_buttonPressed:(UIButton*)button;
#end
#implementation DemoMoviePlayerViewController
- (id)init
{
self = [super init];
if (self == nil)
{
return nil;
}
[self setWantsFullScreenLayout:YES];
NSURL *url = [NSURL URLWithString:#"http://once.unicornmedia.com/now/od/auto/0116d5af-bdc1-456d-a3ac-e3cbe25bac98/c762a821-e583-420c-b798-7b8c66736027/6c0e77e0-6dc4-48d5-9197-26e59271e8dd/content.once"];
moviePlayer_ = [[MPMoviePlayerController alloc] initWithContentURL:url];
return self;
}
- (void)dealloc
{
[moviePlayer_ stop];
[moviePlayer_ release];
moviePlayer_ = nil;
[super dealloc];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[[self view] setBackgroundColor:[UIColor redColor]]; // debug
[[moviePlayer_ view] setFrame:[[self view] bounds]];
[[moviePlayer_ view] setAutoresizingMask:(UIViewAutoresizingFlexibleWidth
|UIViewAutoresizingFlexibleHeight)];
[moviePlayer_ setControlStyle:MPMovieControlStyleFullscreen];
[[moviePlayer_ view] setBackgroundColor:[UIColor greenColor]]; // debug
[[self view] addSubview:[moviePlayer_ view]];
// add a button to launch share kit
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"launch modal" forState:UIControlStateNormal];
[button addTarget:self
action:#selector(_buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
[[moviePlayer_ view] addSubview:button];
[button setFrame:CGRectMake(20, 100, 200, 40)];
[moviePlayer_ setShouldAutoplay:YES];
[moviePlayer_ play];
}
#pragma mark - internal methods -
- (void)_dismissModal
{
[self dismissModalViewControllerAnimated:YES];
}
- (void)_buttonPressed:(UIButton*)button
{
if ([moviePlayer_ currentPlaybackRate] == 1.0)
{
[moviePlayer_ setShouldAutoplay:NO];
[moviePlayer_ pause];
}
[self performSelector:#selector(_dismissModal) withObject:nil afterDelay:3.0];
UIViewController *vc = [[UIViewController alloc] init];
[[vc view] setBackgroundColor:[UIColor blueColor]];
[self presentModalViewController:vc animated:YES];
// yeah I know, vc is leaked...
}
#end
So apparently, somehow the MPMoviePlayerController is somehow able to detect which its view gets obscured, despite the fact that my view controller isn't doing anything fancy in viewWillDisappear or viewDidDisappear.
Again, what really bothers me is that, to the best of my knowledge, this worked just fine under 4.3 about a month ago.
I am trying to play music in my application. The music works fine but after switching viewControllers and returning to the main menu, my music plays again! It means several identical sounds play together! How can I solve this? Here is my code :
- (void)viewDidLoad {
NSString *music = [[NSBundle mainBundle] pathForResource:#"1music" ofType:#"mp3"];
myMusic = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:music] error:NULL];
myMusic.delegate = self;
myMusic.numberOfLoops = -1;
[myMusic play];
}
- (IBAction) scoreView {
ScoreViewController *scoreView = [[ScoreViewController alloc] initWithNibName:#"ScoreViewController" bundle:nil];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:self.view cache:YES];
[self.view addSubview: scoreView.view];
[UIView commitAnimations];
}
EDITED CODE :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
NSString * musicSonati = [[NSBundle mainBundle] pathForResource:#"music" ofType:#"mp3"];
myMusic = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:musicSonati] error:NULL];
myMusic.delegate = self;
myMusic.numberOfLoops = -1;
[myMusic play];
}
return self;
}
//toggle button
- (IBAction)MusicPlaying:(id)sender {
if ((isPlay = !isPlay))
{
UIImage *buttonImageNormal = [UIImage imageNamed:#"play.png"];
UIImage *stretchableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth:0 topCapHeight:0];
[MusicButton setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];
[myMusic pause];
}else {
UIImage *buttonImageNormal = [UIImage imageNamed:#"pause.png"];
UIImage *stretchableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth:0 topCapHeight:0];
[MusicButton setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];
NSLog(#"Music play");
[myMusic play];
}
}
If you have audio to play on multiple places then one simple way to achieve this is declare AVAudioPlayer instance in delegate with property synthesized.If you want to play this anywhere do this:-
MyAppDelegate *app_delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
if(app_delegate.audioPlayer)
{
[app_delegate.audioPlayer release];
app_delegate.audioPlayer = nil;
}
app_delegate.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
and if you want to stop sound do this:-
if(app_delegate.audioPlayer)
{
if([app_delegate.audioPlayer isPlaying])
{
[app_delegate.audioPlayer stop];
[app_delegate.audioPlayer setCurrentTime:0];
}
}
and to play new sound file release and nil same player if already allocated or alloc it again with new sound file url.
Make sure myMusic is correctly declared as a retained property and synthesized then try something like this:
-(void) commonInit {
NSString * musicSonati = [[NSBundle mainBundle] pathForResource:#"music" ofType:#"mp3"];
self.myMusic = [[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:musicSonati] error:NULL] autorelease];
self.myMusic.delegate = self;
self.myMusic.numberOfLoops = -1;
//You probably don't want to play music on init, rather defer to viewDidLoad.
// [self.myMusic play];
}
- (id)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
[self commonInit];
}
return self;
}
- (id)init {
self = [super init];
if (self) {
[self commonInit];
}
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
[self commonInit];
}
return self;
}
Then try this in your viewDidLoad:
- (void)viewDidLoad {
...
if (!self.myMusic.playing) {
[self.myMusic play];
}
...
}
Also, don't forget to release your player in dealloc!
First, viewDidLoad probably isn't a good place to be initializing your AVAudioPlayer, as the system may need to unload some of your components to reclaim memory (in viewDidUnload). You should probably be creating the AVAudioPlayer in your init method or similar.
So what's happening is you end up creating a second AVAudioPlayer when the focus comes back to your application, and you're actually losing the reference to your first one. (Thus, also leaking memory.)
If you want to start playing music when the view loads, you should additionally check its status before doing so:
- (void)viewDidLoad {
...
if (!myMusic.playing) {
[myMusic play];
}
...
}
Its seems you are developing game (from your function name After viewLoad (ScoreView). ;) )
Well, According to me, AvAudioplayer is not Good Option if you want to implement with Game.
Use cocosdenshion, Download the latest cocos2d folder, find the these 9 files, put it in your resource folder,
And You are done.. !!!
#import "SimpleAudioEngine.h" // wherever you want to call in head part of the file.
Step1 call short file.!
[[SimpleAudioEngine sharedEngine] playEffect:#"blast.mp3"];
step2 call background loop.
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:#"background.mp3" loop:YES];
NOTE: There are list of available function http://www.cocos2d-iphone.org/api-ref/0.99.5/interface_simple_audio_engine.html , Its very easy and simple !
Whole implementation will take, 20 minutes max !
Initialize your player in app delegate file and play your background music. Only set one variable in app delegate which checks music play true or false...and enjoy your app without restarting music......
In your code you initialize you player in view did load and init method... that's why you music restart.....just call it only once in app delegate applicationdidfinshLaunching() method....
Im developing a memory game. As i click on a button I want the background to switch. When I click on the card the second time i want the background to switch for a second and then go back to the original (if it wasnt the correct card). But the background of the buttons are not changed until i return from the method (buttonPressed). Why isnt it changed instantly? Please help me! :)
Here is the class that i am working with:
#import "Button.h"
#import <UIKit/UIKit.h>
#import <AVFoundation/AVAudioPlayer.h>
#class ZogajAppDelegate;
#interface PairPlayPlayViewController : UIViewController <AVAudioPlayerDelegate> {
ZogajAppDelegate *appDelegate;
AVAudioPlayer *av;
Boolean isPairActive;
Button *firstButton;
Button *secondButton;
}
#property (nonatomic, retain) AVAudioPlayer *av;
#property (nonatomic, retain) Button *firstButton;
#property (nonatomic, retain) Button *secondButton;
- (void)buttonPressed:(id)sender;
- (void)secondCard;
#end
and the .m file:
#import "PairPlayPlayViewController.h"
#import "ZogajAppDelegate.h"
#import "Button.h"
#import "AVFoundation/AVAudioPlayer.h"
#implementation PairPlayPlayViewController
#synthesize av, firstButton, secondButton;
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
return self;
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
NSString *newAudioFile = [[NSBundle mainBundle] pathForResource:#"double_card" ofType:#"mp3"];
NSString *newAudioFile2 = [[NSBundle mainBundle] pathForResource:#"right_sound" ofType:#"mp3"];
av = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:newAudioFile] error:NULL];
[av prepareToPlay];
[av initWithContentsOfURL:[NSURL fileURLWithPath:newAudioFile2] error:NULL];
[av prepareToPlay];
//av = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:newAudioFile] error:NULL];
//[av prepareToPlay];
isPairActive = FALSE;
appDelegate = (ZogajAppDelegate *)[[UIApplication sharedApplication] delegate];
int position;
for(int i = 0; i < ((appDelegate.numberOfPairs*2)/5); i++){
for (int j = 0; j<5 ;j++){
Button *button = [[Button alloc] init];
//Sätter bild nummer..
position = (arc4random() % [appDelegate.cardsInPlay count]);
button.picNumber = [[appDelegate.cardsInPlay objectAtIndex:position]intValue];
NSLog(#"%d", button.picNumber);
[appDelegate.cardsInPlay removeObjectAtIndex:position];
button.frame = CGRectMake( 3 + (65 * j), 5 + (65 * i), 55, 55);
button.imageView.contentMode = UIViewContentModeScaleAspectFit;
button.imageView.clipsToBounds = YES;
[button setBackgroundImage:[UIImage imageNamed:#"back.png"] forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
}
for (int j = 0; j<((appDelegate.numberOfPairs*2) % 5) ;j++){
Button *button = [[Button alloc] init];
//Sätter bild nummer..
position = (arc4random() % [appDelegate.cardsInPlay count]);
button.picNumber = [[appDelegate.cardsInPlay objectAtIndex:position]intValue];
NSLog(#"%d", button.picNumber);
[appDelegate.cardsInPlay removeObjectAtIndex:position];
button.frame = CGRectMake( 3 + (65 * j), 5 + (65 * ((appDelegate.numberOfPairs*2)/5) + 1), 55, 55);
//button.imageView.contentMode = UIViewContentModeScaleAspectFit;
//button.imageView.clipsToBounds = YES;
[button setBackgroundImage:[UIImage imageNamed:#"back.png"] forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonPressed:)
forControlEvents:UIControlEventAllTouchEvents];
[self.view addSubview:button];
}
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
-(void)buttonPressed:(id)sender {
Button *button = [[Button alloc] init];
button = sender;
NSLog(#"%d och spela upp ljud", button.picNumber);
NSString *newAudioFile = [[NSBundle mainBundle] pathForResource:#"double_card" ofType:#"mp3"];
[av initWithContentsOfURL:[NSURL fileURLWithPath:newAudioFile] error:NULL];
[av play];
[button setBackgroundImage:[UIImage imageNamed:[NSString stringWithFormat:#"%d.png",button.picNumber]] forState:UIControlStateNormal];
[self.view addSubview:button];
[NSThread sleepForTimeInterval:1.0];
if(isPairActive == FALSE){
isPairActive = TRUE;
firstButton = button;
}
else {
secondButton = button;
[self secondCard];
}
return;
}
- (void)secondCard {
[NSThread sleepForTimeInterval:1.0];
NSString *newAudioFile = [[NSBundle mainBundle] pathForResource:#"double_card" ofType:#"mp3"];
isPairActive = FALSE;
if([appDelegate.dictionary objectForKey:[NSString stringWithFormat:#"%d",secondButton.picNumber]] == [NSString stringWithFormat:#"%d",firstButton.picNumber]){
NSString *newAudioFile2 = [[NSBundle mainBundle] pathForResource:#"right_sound" ofType:#"mp3"];
[av initWithContentsOfURL:[NSURL fileURLWithPath:newAudioFile2] error:NULL];
[av play];
}
else {
[firstButton setBackgroundImage:[UIImage imageNamed:#"back.png"] forState:UIControlStateNormal];
[secondButton setBackgroundImage:[UIImage imageNamed:#"back.png"] forState:UIControlStateNormal];
[av initWithContentsOfURL:[NSURL fileURLWithPath:newAudioFile] error:NULL];
[av play];
}
return;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
[av release];
[firstButton release];
[secondButton release];
}
#end
In buttonPressed: change the background, set an NSTimer to call you back, and return. In the NSTimer callback, set the background back to what you want.
Drawing doesn't happen at the moment you ask for it. That would give you horrible performance. All drawing is merged into the draw portion of the run loop. You won't get to that portion until you return from this IBAction method.
As you already know, the image will be changed after returning from the method. That's it.
You have to return from the method, so you have to change the image, perform selector that executes the rest of code you want to perform and return from the method.
UIKit can run only on main thread, so you have to return from the method, that's blocking it, and it will execute GUI manipulations then.
EDIT:
Instead of telling NSThread to sleep, perform the selector with delay.