The problem is only happening with iOS4.3. I'm using ARC and my Base SDK is iOS6.
In -viewDidAppear of my view controller, I check if this is the first time the app has been started and if so, then I create and show a UIAlertView. I assign that UIAlertView to a strong property on the view controller and set self as the UIAlertView delegate.
self.uiAlertView = [[UIAlertView alloc] initWithTitle:#"Welcome!"
message:messageString
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:#"View Tutorial Videos", #"Email Support", nil];
When I tap one of the buttons, the app crashes complaining that -alertView:didDismissWithButtonIndex: was sent to a deallocated instance. The delegate is the view controller that is displaying the UIAlertView.
On all subsequent launches of the app, when the UIAlertView isn't shown there are no problems. The view controller is definitely not being deallocated.
If I display the UIAlertView but set the delegate to nil, then there is no problem and the app continues working, so clearly the view controller hasn't been deallocated because I can keep using it.
What is happening? This only causes a problem with iOS4.3.
EDIT: Based on suggestions in the comments, I added some more log messages in different places.
I've discovered that the view controller IS getting dealloc'd, but only if that view controller displays the UIAlertView. What in the world would cause the view controller to get dealloc'd just because it sets itself as the delegate of a UIAlertView and then displays it?
My app delegate has a strong reference to the view controller, so there is absolutely no reason that I can see for the view controller to get dealloc'd.
EDIT 2: I've discovered that during start up my main view controller is being instantiated TWICE. The first one is the one creating the UIAlertView and that one is getting dealloc'd. The second one is the one that I've been able to interact with afterwards that made me think the view controller was still there and operable.
However, I can't figure out where or why my view controller would be created twice. I don't have any alloc/init statements for the view controller. It only exists in the MainWindow_iPhone.xib.
The first time viewDidLoad is called on my view controller, the stack frame above is [UIViewController view]. The second time viewDidLoad is called on the second instance of my view controller, the stack frame above is [UINib instantiateWithOwner:options:]
EDIT 3: I've "fixed" the problem, but I don't understand why this would happen. Perhaps you can help me understand.
In my MainWindow_iPhone.xib, I created my root view controller and assigned it to an IBOutlet on my app delegate. Instead, I deleted the view controller from the xib and created it in code in the -application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions ... and the problem disappeared.
Why in the world would the view controller be created twice when in the xib?
I have this issue before. alertView:didDismissWithButtonIndex: is called after alertView: clickedButtonAtIndex:. You most likely deallocate the view controller in alertView:clickedButtonAtIndex by doing something like [self.navigationController popViewControllerAnimated:YES].
UIAlertView delegate is assign not weak reference. When delegate is deallocated, it is not set to nil automatically. That's reason why your code is crashed.
i fixed this issue commenting this method (or deleting it).
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSLog(#"se apreto cancel");
}
as James Wang said, the didDismissWithButtonIndex is called after clickedButtonAtIndex so i commented it to avoid the crash.
Related
My app takes a picture and then needs to ask the user what they want to name their image.
I've tried using UIAlertView, but I'm having this issue where the string itself isn't collected on time because the code doesn't pause to wait for user input.
What I want to try now is to make a new view controller that just has a text field for the user to input their PDF file's name. What I want to know is how exactly it would conceptually work (or if it would work at all).
Pseudo code:
1. The user clicks on a take picture button, which runs a method that captures the image.
2. After the image is in memory, the View Controller that has the text field is presented.
3. The user inputs the information into the text field
4. The view is dismissed
5. The code in the method that captures the image continues.
Is this how view controllers work? If I present a view controller in from a button, and then dismiss the presented view controller from another button in the new view controller, does the code in the original method continue executing where it left off?
No. The code in the original method executes immediately after presenting the UIAlertView (or UIActionSheet, or any other thing). It doesn't wait for the dismissal.
To handle event of dismissing the UIAlertView, for example there is mechanism called Delegation. It works like this:
You create the UIAlertView in View Controller.
You set UIAlertView's .delegate property to some object. Typically the View Controller itself. That object should implement several methods, that UIAlertViewDelegate defines.
You present the Alert and your code continues immediately.
When user click on some button, the UIAlertView calls one of the defined methods on its Delegate. In our case, the View Controller, which brings us back to our code.
In your delegate method, you “continue” what you wanted to do before Alert was presented.
Example code:
- (void)presentAlert {
// 1
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Hello!"
message:nil
delegate:self // 2
cancelButtonTitle:#"Eh?"
otherButtonTitles:#"Hello!", #"Hi!", #"Aloha!" nil];
[alert show]; // 3
NSLog(#"Did present alert"); // immediately executed
}
// Between these method calls may pass several seconds, minutes or eternity.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
// 4, 5
NSLog(#"Did click button %#", [alertView buttonTitleAtIndex:buttonIndex]);
}
In addition, you will have to declare UIAlertViewDelegate protocol on your View Controller:
#interface YourViewController : UIViewController <UIAlertViewDelegate>
I believe you are misunderstanding Viewcontrollers quite a bit. But i cannot explain all the issues here, or this post would turn into a book. So heres a very helpful link (that i hope you already did read) and a few hints:
https://developer.apple.com/library/ios/featuredarticles/viewcontrollerpgforiphoneos/Introduction/Introduction.html
Viewcontrollers are presented either modally (stacked on top of each other) or in a common ParentViewController (such as a NavigationController or a SlideViewController). The presenting controller will always either keep the controller running in the background or finish the Viewcontrollers logic before presenting a new one. So the shortest possible answr to your question is no.
Pay special attention to the Viewcontroller lifecycle. ViewControllers have special callback methods that get invoked under certain circumstances. Look out for the viewDidLoad and viewDidAppear - methods, this will clear your confusion quite a bit.
Last, not least, look into the delegate pattern. Delegates are a way of sending messages between viewcontrollers. So you could make the ViewController that takes the name send a message with the chosen name to the viewController that took the picture.
Heres a link to the delegate programming guide:
https://developer.apple.com/library/ios/documentation/general/conceptual/CocoaEncyclopedia/DelegatesandDataSources/DelegatesandDataSources.html
i hope that gets you started
My application is on ARC and I still see few crashes. I then saw that I was setting my view controller as delegate of an alert view and then when the alert is on screen, on tap on "OK" button I was moving back to previous view and my current view controller was getting dealloc-ed. After it is getting dealloc-ed, I got a call from UIKit for the alert view and it crashes. As a safe handling, I created a property for UIAlertView and in the dealloc now, I am setting delegate of this UIAlertView to nil. This is working fine now.
I see another crash happening randomly:
-[CFString release]: message sent to deallocated instance 0xd2de900
My question here is that there are lot many places where I create local instances of some objects (custom view controllers or iOS objects like UIAlertView) and set my view controller as delegate of it. Do I need to create class level properties for all of them and the delegate on them to nil in the dealloc? Is there any other easy alternative to make sure no call back happens after delegate object is gone.
I am using ARC.
I show an alert view after a user taps a UITableView cell.
99% of the times everything works great.
NOW TO THE WEIRED PART
I have this view hierarchy -
UITableView --> First UIViewController --> Child UIViewControllerControllers
The crash only appears after I open one, specific child UIViewControllers. After I enter all the other child viewControllers the alert view works great. If I enter the "problematic" view controller even once, The UIAlert view will crash even 5 minutes later and even if I get into all the other view controllers.
I have to say again that the alertView is presented in the root UITableView. And that it crashes even if the alert view callback method is only NSLoging.
The crash report is:
*** -[ReviewViewController isKindOfClass:]: message sent to deallocated instance 0x20bea8d0
while 'ReviewViewController' is the problematic viewController.
Thanks
Shani
You're setting the delegate of the UIAlertview to the calling UIViewController. That UIViewController is being de-allocated in certain cases when you navigate away from it.
If you require a delegate to respond to the UIAlertView, you'll have to structure your code so that the delegate doesn't get de-allocated before the UIAlertView will be dismissed.
I have a viewController called "FirstViewController". In an IBAction i call another ViewController called "thePageFlipViewController" and push it in sight via
[self presentModalViewController:thePageFlipViewController animated:YES];
after some time the user closes thePageFlipViewController with a button where the following code is executed via a delegate in FirstViewController:
[self dismissModalViewControllerAnimated:YES];
[thePageFlipViewController release];
And here is my problem:
-viewDidLoadin FirstViewController get's sometimes called after dismissing thePageFlipController. I don't understand why, because firstViewController should live in background. Is it dependent how long the modal view is displayed? is it possible that ARC does release something?
My problem is, that i initialise a lot of objects in viewDidLoad and the app crashes if viewDidLoad gets called again. I define some Routes for RESTKit there and RestKit complains that the routes are already set up and crash the app.
Any Help is appreciated.
When a view is not actually displayed it can be unloaded to free up memory. You would get a call to viewDidUnload: when that happens so you can release any objects you are holding strong references to. Then next time the view is needed, viewDidLoad: will get called again when the view is reloaded, there you have to recreate the objects you released in viewDidUnload:.
See the Memory Management section of the UIViewController class reference.
Also this answer has a good explanation already.
I have a modal view which is launched from the current view controller, as
[self presentModalViewCOntroller:modalViewController animated:TRUE];
The modal view controller dismisses itself when someone hits a button.
[self dismissModalViewControllerAnimated:TRUE];
A couple of screens later, I attempt to swap the root view within the window. I do this all the time with no trouble. But in a certain case, when switching the one view within the window, the picker delegate method is being called on the modal view controller even thought it was dismissed a while ago.
This is very strange because the modal view controller is usually deallocated when dismissModalViewController is called.
Why is a view from the modal view controller being invoked?
It appears that someone, probably the window still has a reference. Are you supposed to do something else in addition to dismissModalViewController?
Thanks
DismissModalViewController should be enough. It does seem like you have a problem with some reference hanging around that you don't intend. Without seeing more code, I can't point to anything specific.