iPhone - Preventing Sleep while using applicationMusicPlayer in MPMusicPlayerController - iphone

I am trying to disable the automated sleeping of iPhone for certain period in my app.
Used [[UIApplication sharedApplication] setIdleTimerDisabled:YES] which works fine as long as I play no music.
But when I play music the Idle Timer seems to get reactivated.
I have tried all kinds of tricks from NSTimer firing silent sounds every 10 second etc but nothing works.
Would welcome any suggestion or thoughts on making this happen.

The way to fix this is to first subclass UIApplication, override the setIdleTimerDisabled method and make it do nothing. Then, add a couple of your own methods that you'll call from your application instead of using the normal setter. By doing this you will ignore all messages that might change the idle timer aside from the custom method calls you make yourself. Here's how you do it:
Edit your main.m file to use a custom UIApplication subclass:
#import <UIKit/UIKit.h>
int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString* appClass = #"CustomUIApplicationSubclass";
NSString* delegateClass = nil;
int retVal = UIApplicationMain(argc, argv, appClass, delegateClass);
[pool release];
return retVal;
}
Then define your UIApplication subclass:
#interface CustomUIApplicationSubclass : UIApplication {
}
- (void)disableIdleTimer;
- (void)enableIdleTimer;
#end
#implementation CustomUIApplicationSubclass
- (void)setIdleTimerDisabled:(BOOL)disabled
{
// do nothing! take that stupid ipod controller!
}
- (void)enableIdleTimer
{
[super setIdleTimerDisabled:NO];
}
- (void)disableIdleTimer
{
[super setIdleTimerDisabled:YES];
}
#end
This will force the iPod controller to use your custom UIApplication instance which does no longer does anything when the normal setIdleTimerDisabled method is called.

Related

EXC_BAD_ACCESS when opening modal view

I'm having a problem with my iPhone App, I'm getting EXC_BAD_ACCESS, I had some memory leaks, but these are now fixed, so I'm not sure whats going on. I realise that I haven't provide a lot of information, but I really don't know whats happening.
The initial screen opens up where I have a number of buttons. Tapping on the first button, which runs the following code and opens up a modal view:
-(IBAction)newWorkoutButton
{
newWorkoutViewController .loadedFromRootViewController = #"YES";
[self presentModalViewController:newWorkoutViewController animated:YES];
}
The screen freezes and the is in the code below:
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#import <CoreLocation/CoreLocation.h>
int main(int argc, char *argv[])
{
Method getDistanceFrom = class_getInstanceMethod([CLLocation class], #selector(getDistanceFrom:));
class_addMethod([CLLocation class], #selector(distanceFromLocation:), method_getImplementation(getDistanceFrom), method_getTypeEncoding(getDistanceFrom));
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil); // ERROR HAPPENING HERE
[pool release];
return retVal;
}
Like Aleks suggested you can try to find the zombie like this:
I find this alternative more convenient:
Click the "Run Button Dropdown"
From the list choose Profile
The program "Instruments" should open where you can also choose Zombies
Now you can interact with your app and try to cause the error
As soon as the error happens you should get a hint on when your object was released and therefore deallocated.
(source: dimzzy.com)

Implement auto log-off feature in Iphone

I am making an application which logs in using some username and password. Now when i am logged in succesfully I want my application to be logged out automatically if no interaction with the application found for 10-12 minutes.
Can anybody guide me how can i achieve this ??
Help with some code will be really appreciated.
Thanks
The Thing you want to implement is called SESSION MANAGEMENT.You have to subclass the UIApplication.
#interface MyUIApp : UIApplication {
}
In this class you have to reset the timer each time. Also you have to check if the application is responded or not with this.If the idleTimer is Exceeded then push the viewController to your login view.
- (UIResponder *)nextResponder {
[self resetIdleTimer];
return [super nextResponder];
}
Also you have to change the main class file with this:-
#import <UIKit/UIKit.h>
int main(int argc, char *argv[]) {
NSString* appClass = #"MyUIApp";
NSString* delegateClass = nil;
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, appClass, delegateClass);
[pool release];
return retVal;
}

Objective-C on iPhone - tab bar crash

I'm relatively new to Objective-C and coding. I've tried doing a little dev on my own but have now become stuck on what is probably a rookie error.
I've created a tab bar controller with 5 views, one such view is a UIWebView. I've got the Webview working and it loads, but when I select a different tab, the app crashes. Please find my code below and any help would be appreciated!
#import <UIKit/UIKit.h>
#interface LiveViewController : UIViewController {
IBOutlet UIWebView *liveView;
}
#property (nonatomic, retain) UIWebView *liveView;
#end
#import "LiveViewController.h"
#implementation LiveViewController
#synthesize liveView;
// 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 {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[self.liveView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.britishseapower.co.uk/live/"]]];
[super viewDidLoad];
}
- (void)webViewDidStartLoad:(UIWebView *)liveView
{
// starting the load, show the activity indicator in the status bar
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
- (void)webViewDidFinishLoad:(UIWebView *)liveView
{
// finished loading, hide the activity indicator in the status bar
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (void)liveView:(UIWebView *)liveView didFailLoadWithError:(NSError *)error
{
// load error, hide the activity indicator in the status bar
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
// report the error inside the webview
NSString* errorString = [NSString stringWithFormat:
#"<html><center><font size=+5 color='red'>An error occurred:<br>%#</font></center></html>",
error.localizedDescription];
[self.liveView loadHTMLString:errorString baseURL:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
if ( [self.liveView loading] ) {
[self.liveView stopLoading];
}
self.liveView.delegate = nil; // disconnect the delegate as the webview is hidden
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (void)dealloc {
[liveView release];
[UIWebView release];
[LiveViewController release];
[super dealloc];
}
#end
Many thanks,
Ryan
[UIWebView release]; [LiveViewController release];
This is what make your app crash.
It's not valid to send a release message to a class itself.
What you've done with [liveView release]; is enough (with the call to [super dealloc];.)
You should also set the delegate to nil in the dealloc method as in the viewWillDisappear method self.liveView.delegate = nil;. This way you're sure to avoid any further message sent to the LiveViewController from the UIWebView.
You should read a bit more of documentation on Objective-C to better understand how it works.
Not sure if this is related but I noticed that you aren't setting yourself as the delegate anywhere in code which means that it must be connected in Interface Builder. Now when the view disappears, you are breaking that connection, but if the view were to re-appear and wasn't previously unloaded that connection will remain broken.
One of the most common reasons why an app may crash is to refer to or send a message to an object that has been already released from the memory. And this type of bug can be easily located using NSZombieEnabled and looking into the console message. So if you haven't already tried that, that's the first thing you must do.
The problem could be in LiveViewController but could be in the other view controllers as well. I wouldn't believe the problem is 100% in LiveViewController because the view controller wouldn't try releasing its view when the view is not shown unless it gets a memory warning. And you run the app using the simulator, it's unlikely it will have a memory warning unless you simulate one.
You would probably know that a view controller never create a view unless the view is used by an object. One of the other view controllers may have a silly bug in its view loading process which causes a crash. Or, you might have released another view controller by mistake. Make 100% sure that the other view controllers have no problem showing their views on their own, when you keep changing between their views (without showing LiveViewController).
So what I would do is to try NSZombieEnabled and check if it accesses a released object, and if it does, what the object is. Also, I will make a double check that the problem is related to LiveViewController. If it doesn't help I would log a message when LiveViewController and its liveView is deallocated (for liveView you need to subclass it). Because delegate property almost always does not retain an object, if the LiveViewController object is released (which shouldn't happen) and liveView still has a reference to it in the delegate property it will make a crash.
Crashes like this are almost always related to releasing an object that has already been released and deallocated.
Let XCode help you find the error. In XCode 4:
- In the toolbar, select the scheme list, and select 'Edit Scheme'
- Select the 'Run Your.app' in the list on the left.
- Under 'Environment Variables', add the following name/value pairs in the appropriate columns:
CFZombieLevel 3
NSZombieEnabled YES
Now when debug your app, you will get a message telling when -release is called on an object that already has a -retainCount of zero. Now you have a good clue to start your investigation.
Note that these flags prevent objects from being deallocated, so it is best to turn them on as needed to prevent out of memory errors.

Strange custom delegate actions

Ok -- this one is weird. I have a singleton class that loads information from an XML file. I am using a delegate definition as follows (I define the delegate in a separate header file to make life easier):
#protocol ResourceClassDelegate <NSObject>
#optional
- (void)picturesDidStartLoading;
- (void)picturesDidFinishLoading;
#end
In the resource file, the delegate is defined correctly (I believe):
#property (assign) id<ResourceClassDelegate> delegate;
When using the delegate, the code in the resource class is as follows:
-(void)refreshPiecesOfHistoryWithOperation {
NSLog(#"Operation Started");
if ([delegate respondsToSelector:#selector(picturesDidStartLoading)])
[delegate picturesDidStartLoading];
self.picturePacks = [HistoryXMLParser loadPicturePacks];
[self.allPiecesOfHistory removeAllObjects];
// now lets put all of them in one big file...
for (PicturePack *pp in self.picturePacks) {
for (int ct = 0; ct < [[pp piecesOfHistory] count] ; ct++) {
[self.allPiecesOfHistory addObject:(PieceOfHistory *)[[pp piecesOfHistory] objectAtIndex:ct]];
}
}
NSLog(#"Operation Ended");
if ([delegate respondsToSelector:#selector(picturesDidFinishLoading)])
[delegate picturesDidFinishLoading];
}
Now... in the class that is listening to the delegate, it is assigned:
- (void)viewDidLoad {
[super viewDidLoad];
// now for the part that makes the loading all happen...
[[ResourceClass sharedResourceClass] setDelegate:self];
}
And in the listening class, the methods are defined....
#pragma mark ResourceClassDelegate
-(void)picturesDidStartLoading {
if (loadingActivity == nil)
loadingActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[self.view addSubview:loadingActivity];
[loadingActivity setCenter:[self.view center]];
[loadingActivity startAnimating];
}
-(void)picturesDidFinishLoading {
if (loadingActivity != nil) {
[loadingActivity stopAnimating];
[loadingActivity removeFromSuperview];
}
[self.tableView reloadData];
}
Now for the problem... every single time, in the listening class, the method (void)picturesDidFinishLoading is called. The method (void)picturesDidStartLoading never is called.
When I debug the code, in the resource class, the line
if ([delegate respondsToSelector:#selector(picturesDidStartLoading)])
[delegate picturesDidStartLoading];
never reaches the delegate method call - even if I remove the if statement. The line
if ([delegate respondsToSelector:#selector(picturesDidFinishLoading)])
[delegate picturesDidFinishLoading];
is always called.
any ideas?
Ok -- I figured it out....
The delegate was nil during the first call. The reason it is nil is because the function using the delegate was called in the source during the init method. The init method was not complete when the first test of the delegate was performed. At this time the delegate was nil because it is not instantiated until the the init method completes. The reason the second test of the delegate worked is because I submitted the process using an NSOperationQueue.
To fix the problem I have to move things around a bit... it's all about the timing!
Well now that was fun....
That's weird, try to remove #optional in the protocol declaration, and see if you get some warnings.
Try to print a log inside the method as well, other than that it looks fine.

Problem creating a timer in Objective C for the Iphone

I've been having alot of problems creating a timer for a iphone application, currently I have a label displaying my timer, but it is just displaying the variable i (2700) in the label, and not decreasing by one every second. Its really driving my head in as this is really my 1st attempt coding in obj C, and for the life of me I cannot get it to decrease in the label.
I was hoping one of the programs on this site would be able to readover my code (MainViewController.m), with particular reference to the timer (countDown and viewDidLoad) and help me fix my problem.
Cheers in advance.
#import "MainViewController.h"
#include <unistd.h>
#include <stdio.h>
int i = 2700;
#implementation MainViewController
#synthesize window;
#synthesize InformationAboutRSI, mainView;
- (IBAction) InformationAboutRSI {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://www.rsi.org.au/what-is-rsi.html"]];
}
-(void)countDown {
if (i > 0) {
i--;
countdownLabel.text = [NSString stringWithFormat:#"%i",i];
sleep(100);
}
}
- (void)viewDidLoad {
int countDown();
[countdownLabel setFont:[UIFont fontWithName:#"DBLCDTempBlack" size:128.0]];
countdownLabel.text = [NSString stringWithFormat:#"%i",i];
[super viewDidLoad];
}
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller {
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)showInfo:(id)sender {
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"FlipsideView" bundle:nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
[controller release];
}
- (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 {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
[window release];
[super dealloc];
}
-(void)updateLabel {
countdownLabel.text = [NSString stringWithFormat:#"%i",i];
}
#end
When developing applications for most modern operating systems, you generally don't want to block the UI thread. This means that your code should do its work and get out of the way as quickly as possible, because while it blocks, the application can't do anything else (like respond to button presses). On a desktop application, blocking the UI thread for more than a couple of seconds will display an hourglass or pinwheel cursor.
With that in mind, you could design your countDown method to:
Decrement the counter
Update the label
Create an NSTimer (I would try scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:) in your initialization to ask the operating system to call countDown every X seconds.
You are calling your countdown method only once, i don't see a loop or timer that would repeat this action.
Have a look at the NSTimer reference.
or use a classic for loop
-(void)countDown
{
for (int j = i, j > 0, j--)
{
countdownLabel.text = [NSString stringWithFormat:#"%i",j];
sleep(100);
}
}
you could call this method after loading your view and initializing the textfield with [self countDown];
You need to return from your countDown method without sleeping and without setting the label more than once. The display will only update after you exit your code.
Then you need to find a way to call your countDown method again after a long enough delay and without sleeping anywhere else. (Hint: use NSTimer) Rinse and repeat.