iPhone app crashing while navigating - iphone

i am developing a rss reader for iPhone, and i have a list of NSDictionary with the name of the site and the url. When i click the DetailDisclosureButton it takes me to another screen with the feeds of the site(I haven't implemented the xlm parser, so its just brings me the screen). Here's the problem after i go back and forth specifically 5 time my app crashes, and it does not show any message on the log.
I have no idea what is happening, what could cause such an error?
thanks!
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
// Gets the site;
NSDictionary *site = [sites objectAtIndex:indexPath.row];
// instantiate a view to see the unread news.
ViewUnreadController *uController = [[ViewUnreadController alloc] init];
uController.title = [site objectForKey:#"site"];
uController.site = site;
// adds the view to NavigationControllers stack (just adds a back button)
[self pushView:uController withBackTitle:#"Signatures"];
[site release];
[uController release];
And an additional information i am using the iPhone simulator 4.0.

Ha! I realized that i was releasing the "site" variable (without retaining it), since it was pointing to an object in a NSMutableArray the reference count reached zero!

Certainly you are over-releasing/under-retainig something. But without seeing you code, nobody will be able to tell more.
NSZombieEnabled might give you some useful informations

Well, you haven't really given us any information, so it could be a huge number of things. Profile your app, post the crash log here as an update to your question. Is this seen on the simulator or a device? Which device or what settings in the simulator are you using?
Arbitrarily guessing, maybe you're making new UIControllers and views every time and you're running out of memory. But that's just a shot in the dark at a target you haven't told me where is, or if it's even there.

Related

How to handle a system alert message for iOS?

I have an app where i am using UIImagePickerController to use the native camer inorder to click pictures but the when the photo gallery on the device is full. I get a alert message which says "Cannot Take Photo - There is not enough available storage to take a photo.You can manage your storage in Settings". I am given two options to click the "Done" button or "Settings" button. Clicking either of them does nothing and the app freezes completely.
This is what i get from the console logs
Not enough space to take a picture. Available space is 0
The code for the picker
UIImagePickerController *mediaPicker = [[UIImagePickerController alloc] init];
mediaPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
mediaPicker.delegate=self;
mediaPicker.sourceType=UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:mediaPicker animated:YES];
I have implemented and tried all the delegates already and its not calling any delegate.
Is there any way i can implement something where i can use a listener to detect when this error occurs and take back the user to the previous screen ?
Sounds like your device run out of memory, system sent lots of "Out of Memory" notifications and your app got one, too. As result your app released the UIViewController, which originally launched UIImagePickerController.
Now when you dismiss imagePicker with Done/Settings button, control returns back to your app. The old UIViewController doesn't exist any more and you haven't implemented code to recreate it from scratch in this kind of situations. The device looks like it frozen, but only because UI wasn't redrawn by your app. Otherwise app works just fine.
You can check this case by implementing didReceiveMemoryWarning method into every UIViewController and logging, if it's called:
- (void)didReceiveMemoryWarning
{
NSLog(#"%#", [self description]);
[super didReceiveMemoryWarning];
}
One of my favourite bugs. Easy to miss :)
This sounds like a bug in iOS.
You should file a feedback at https://feedbackassistant.apple.com/.

iPhone viewDidBecomeActive (or just resuming from background) questions

I've been researching this for a few hours and I'm still unsure if I am even heading in the right direction.
What I would like to do:
When my app is loaded, I need to determine if it's the first time the user has loaded the app that day.
How I was planning on doing it:
I made some labels to display the current day and last day that they used the app. (See sample code below).
-(void)pressStatus{
NSString * currentDay;
currentString = currentDay.text;
NSString * lastDay;
lastString = lastDay.text;
if([currentDay isEqualToString: lastDay]){
status.text = #"same";
}
else {
status.text = #"different";
[self autoReset];
}
So, it does what I need to do, but at the push of a button. Instead, I would like it to happen as soon as the app loads from the background. From what I read, I think I should use viewDidBecomeActive, but I'm not fully understanding it. I've never used the delegate as of yet and at this point everything I'm reading is confusing me more than the last.
Questions
Is viewDidBecomeActive the best way to do this?
If so, can I call the pressStatus function in the MainViewController from within applicationDidBecomeActive in the delegate?
Thanks in advance.
This web page has some very nice flow charts which describe app foregrounding etc.:
http://www.cocoanetics.com/2010/07/understanding-ios-4-backgrounding-and-delegate-messaging
There's no viewDidBecomeActive btw, are you thinking of something else?

UIWebView acts differnetly in app store version than dev version

I've got a problem with an app that works perfectly in the simulator as well as a physical iPhone 4 and an iPhone 3GS. The app was approved and is now in the App Store, but the distribution build downloaded from the App Store exhibits a bug not seen in the dev/release build.
This is a free app, but is supported by local advertising. When the app launches (or returns from background), the AppDelegate attempts to download some HTML from our ad server, and if successful, presents a modal view controller with a UIWebView and passes an NSData variable containing the HTML. In development/release builds, this works PERFECTLY; the app launches, and after a few seconds, a view slides up and shows the ad, which can be dismissed with a button.
However distribution build from the App Store is different. When the modal view controller slides up, the UIWebView never loads. Remember, I present the view controller ONLY if able to download the ad data -- otherwise, the view is never presented.
Thankfully I implemented a timer in the ad view controller which will cause the modal view to dismiss itself if the webViewDidFinishLoad never fires (in which the timer is invalidated), so at least app users aren't too annoyed. But it's still ugly to have an empty view controller slide up and then slide away for apparently no reason.
Here's the relevant methods in the AppDelegate:
- (void)launchAd
{
[NetworkActivity showFor:#"ad"];
if (!alreadyActive && [ServerCheck serverReachable:#"openx.freewave-wifi.com" hideAlert:YES])
{
alreadyActive = YES;
[self performSelectorInBackground:#selector(downloadAdData) withObject:nil];
}
[NetworkActivity hideFor:#"ad"];
}
- (void)downloadAdData
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *baseURL = #"http://appdata.freewave-wifi.com/ad/";
NSString *file = (IS_IPAD) ? #"ipad.php" : #"iphone.php";
NSURL *adURL = [NSURL URLWithString:[baseURL stringByAppendingString:file]];
adData = [[NSData alloc] initWithContentsOfURL:adURL];
[self performSelectorOnMainThread:#selector(presentAdModal) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void)presentAdModal
{
if (adData)
{
AdViewController *adView = [[AdViewController alloc] initWithNibName:nil bundle:nil];
[adView setAdData:adData];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:adView];
[navController setModalPresentationStyle:UIModalPresentationFormSheet];
[navController setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[tabBarController presentModalViewController:navController animated:YES];
[navController release], navController = nil;
[adView release], adView = nil;
}
else
LogError(#"Not presenting ad; unable to create data object.");
}
By the way, adData is defined in header with NSData *adData;
The AdViewController simply contains a UIWebView, which is loaded with
[webView loadData:adData MIMEType:#"text/html" textEncodingName:#"utf-8" baseURL:nil];
Again, this all works PERFECTLY, EVERY TIME with dev/release builds in simulator and physical devices -- just not on distribution build from app store. I have even converted the NSData to an NSString and barfed it out with NSLog() just to prove that the HTML was downloaded before presenting the AdView modally.
[sigh...]
EDIT 1: In case my original post was not clear, the webViewDidFinishLoad never gets called in distribution build (but it does in dev/release build).
EDIT 2: Also, just before I call
[webView loadData:adData MIMEType:#"text/html" textEncodingName:#"utf-8" baseURL:nil];
in the AdViewController, I added a temporary NSLog() and converted adData to NSString and logged it to the console, and the HTML was there. So, the UIWebView just refuses to load the NSData?
HOLY COW. I figure it out.
Okay, before I say what I found, I did want to correct my own original wording: the modal ad has never worked in the simulator, but always on devices. I know the simulator can have its quirks, so I never thought anything of it, especially since it always worked on the devices. I know this is an important detail that was missing for this discussion, but it's been a couple of weeks since I worked on this project, and I'd forgotten all about it until today.
Now then... While tinkering with things, I noticed the AdView.xib was not in my project file list. I expanded a few folders thinking maybe it was accidentally dragged into one of them, but it was not listed at all. This really has me puzzled, though -- Xcode NEVER complained about a missing resource (no warnings or errors; always a perfect compile).
So, I navigated to the physical location and added the AdView.xib into the project. Now, the modal ad is displayed in the simulator, which is a first. I figure that since now the app works correctly in the simulator, it should work fine in the distribution build (odd correlation to make, but it's all I got until my update hits the App Store).
Obviously, I'll be submitting an update, so I won't accept my own answer until after the update hits the App Store (assuming I have actually fixed it).
Ok, this is an extremely long shot, but perhaps worth considering.
The docs for NSData state that with regards to initWithContentsOfURL "The returned object might be different than the original receiver." So, if it was a different object, and one which was in fact autoreleased, consider this line in your code:
adData = [[NSData alloc] initWithContentsOfURL:adURL];
This won't add a retain count for adData -- you didn't write self.adData = or similar. So, bearing in mind the scenario mentioned whereby the returned NSData was autoreleased: your method downloadAdData wraps its content in an NSAutoreleasePool. This is correct practice. However, that might result in adData being released BEFORE presentAdModal is called on the main thread. So...
In presentAdModal you just check that adData isn't nil -- but it can be not nil, and still have been deallocated from memory at that point by your NSAutoreleasePool -- hence, you would in this situation trigger the "show web view" code, but be attempting to load an NSData object that had been trashed. Which probably would contain complete garbage, hence no successful "web view loaded" call.
As I said, a long shot, but the ony thing that jumps out at me at this point.
UPDATE:
A completely different cause of your problem might be this:
Your test environment (i.e. non App-Store builds) is making requests from a certain part of the internet (i.e. your office) which has permission to access the web server containing ads, due to either IP blocking or whatever network setup there is, whereas your App Store release builds are attempting to access the ad server from parts of the internet which are forbidden. Again, probably not the case, but worth mentioning.

iphone app crashes due to Low Memory but works fine in simulator

Dear all, I have a navigation-based app with about 60 UIControllerViews, which is divided into 4 sections.
I have run with the following : 1. Build and analyse : bulid is successful with no complains. 2. Instruments allocation and leaks : no leaks.
However, the app crashed in iPhone or iPad but works fine in simulator. There is no crash reports but I do see LowMemory.log in the crashreporter folder.
I have upgraded my iphone and ipad to 4.2
Does anyone have ideas what could be wrong? I have been reading and troubleshooting for a week.
Is there a need to remove/release the UIControllerViews?
The app crashes simply by navigating between the views.
Thank you for any help.
My app has a root view called contentViewController and users can navigate to 4 quizzes from here.
This is the code I use to return to my root view.
- (void)goHome {
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle: #"Warning"
message: #"Proceed?"
delegate: self
cancelButtonTitle:#"Yes"
otherButtonTitles:#"No",nil];
[alert show];
[alert release];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
[[self navigationController] setNavigationBarHidden:NO animated:YES];
if (buttonIndex == 0) {
NSArray * subviews = [self.view subviews];
[subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
self.view = nil;
if (self.contentViewController == nil)
{
ContentViewController *aViewController = [[ContentViewController alloc]
initWithNibName:#"ContentViewController" bundle:[NSBundle mainBundle]];
self.contentViewController = aViewController;
[aViewController release];
}
[self.navigationController pushViewController:self.contentViewController animated:YES];
}
else {
}
}
The simulator isn't going to give you any useful information about memory warnings—your app, running there, effectively has access to all the memory the system's willing to give it. The device is where you need to be testing for memory usage, and if you're getting warnings and crashes, then you need to do some Instruments work to figure out where you can free up some of that memory.
Look at your xcode console. If you are getting a number of low memory warnings, then you need to be allocating and de-allocating your views on the fly because they are taking up too much memory on the device (the simulator isn't quite so memory restricted).
But it could be about a million other things causing your crash. Make sure you're doing a debug build (breakpoints on) so the debugger will kick in and hopefully you can see where on the stack your crash is occurring.
You have some good suggestions already. However I'd suggest spending a lot of time reviewing XCode's debugging tools documentation. This so you have a basic understanding of what they are capable of and how to use them. Follow that up with some reading on iOS memory management, auto release pools and the like.
For your app you need to realize that there is no swap space on iOS devices. So you are forced to manage memory to an extent that you mat not have to on other platforms. Generally that means you don't want to keep to much view data in memory if it can be avoided.
In the case of the current iPad there may only be about 110MB of RAM available to the app. Specific numbers probably are iOS version dependent. In any event you need to get an idea as to how large the data structures (in memory) are for your various views. 60 different views could be considered a lot depending upon memory usage, if you don't manage it correctly you are likely to run out very quickly. This not like programming in Java or other garbage collected language.
Lastly; even though this sounds like a memory management issue it could always be something else. If you still have trouble you will need to post code. Right now it is really guess work on our part. Just remember you do not have VM and there is no garbage collection.
You are using up memory, always remember if you allocate memory you must release it, in some cases you can use autorelease so you dont forget to release it after the void dealloc method before end.

Problem with applicationShouldTerminate on iPhone

I'm having a problem with applicationShouldTerminate.
What ever I do it seams that has no effect. Any help would be
appreciated.
I'm well versed in programing but this just gives me headache. Im going
over some basic tutorials for xcode , as I'm new to mac in general, and am currently looking at a simple flashlight app.
It exists but I would like to add a alert box here with option not to
quit.
(void)applicationWillTerminate:(UIApplication *)application
{
[application setIdleTimerDisabled:NO];
}
this has no effect, alert is closed even before its created.
(void)applicationWillTerminate:(UIApplication *)application
{
[application setIdleTimerDisabled:NO];
UIAlertView *alertTest = [[UIAlertView alloc]
initWithTitle:#"This is a Test"
message:#"This is the message contained
with a UIAlertView"
delegate:self
cancelButtonTitle:#"Button #1"
otherButtonTitles:nil];
[alertTest addButtonWithTitle:#"Button #2"];
[alertTest show];
[alertTest autorelease];
NSLog(#"Termination");
}
I did some reading online and found that it should be possible to do
this with
(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
But no mater where I put that declaration I get error: syntax error
before NSApplicationTerminateReply.
There is no syntax error except that xcode seems not to recognize
NSApplicationTerminateReply as valid input.
Any sample code would be greatly appreciated.
I know this is a non-answer, but hopefully I can be helpful:
Displaying a "Really quit?"-type alert like this, even if you can pull it off technically (and I'm not sure you can), is a bad idea and is likely to either cause rejection from the App Store or, at best, an inconsistent user experience because no other apps do this.
The convention with iPhone apps is to save state if necessary, then yield control (for termination) as quickly as possible when the user hits the home button or switches apps.
To ensure a consistent experience, Apple probably has an aggressive timer in place to restrict what you can do in applicationWillTerminate. And even if they don't have a technical measure in place, they probably have an App Store approval policy to ensure that applications quit immediately when they're asked to.
applicationShouldTerminate and NSApplication do not exist on the iPhone. You have to use UIApplication.
The alert view is never shown because the 'show' method does not block, and therefore, the end of 'applicationWillTerminate' is reached immediately after you create the alert view and try to show it. I believe this is by design. You can't really begin asynchronous operations in 'applicationWillTerminate'.
With regards to the applicationShouldTerminate error, in case anyone's curious, NSApplicationTerminateReply and NSApplication seem to be deprecated...even though the OP's method is exactly how it appears in the docs!
Defining your method as the below should build with no errors:
-(BOOL)applicationShouldTerminate :(UIApplication *)application
I think I found the answer to what I wanted to do but will need to check it when I get back home.
Some directions were found here
http://blog.minus-zero.org/
The iPhone 2.0 software was recently released, and with it came the
ability for users to download native apps (i.e., not web sites)
directly to their phones from within the iPhone UI or via iTunes.
Developers (anyone who pays Apple 59GBP for the privilege) can then
write their own apps and have them available for purchase in the App
Store.
One limitation of the Apple-sanctioned SDK is that only one
application is allowed to be running at a time. This presents a
problem for apps such as IM clients, music players and other programs
whose functionality relies on being able to run in the background.
Another example (courtesy of James) would be an app that takes
advantage of the iPhone 3G's GPS chip to create a log of all the
places you visit.
However, there is a neat trick that I discovered: your app will only
get terminated if you switch away from it, and hitting the iPhone's
power button while your app is in the foreground doesn't count as
switching away. The upshot of this is you can create apps which
continue to run while the iPhone is in your pocket - perfect for the
GPS example.
Achieving this is as simple as implementing two methods in your
UIApplication delegate - applicationWillResignActive: and
applicationDidBecomeActive:. Here's a simple example to demonstrate
the effect.
In your UIApplication delegate header file, add a new ivar: BOOL
activeApp. Then, in your implementation, add the following three
methods:
- (void)applicationWillResignActive:(UIApplication *)application {
NSLog(#"resigning active status...");
activeApp = NO;
[self performSelector:#selector(sayHello) withObject:nil afterDelay:1.0];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSLog(#"becoming the active app...");
activeApp = YES;
}
- (void)sayHello {
NSLog(#"Hello!");
if (!activeApp)
[self performSelector:#selector(sayHello) withObject:nil afterDelay:1.0];
}