I am trying to impliment a basic UIAlertView into my app (I am using storyboard). But when I run my app, it goes to the debugger screen after stalling at the app's loading screen.
my .h:
#import <UIKit/UIKit.h>
#interface MindTripAnim :UIViewController {
IBOutlet UIImageView *animation;
}
- (IBAction)showMessage:(id)sender;
#end
and my .m:
#import "MindTripAnim.h"
#interface MindTripAnim ()
#end
#implementation MindTripAnim
- (void)viewDidLoad {
animation.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"trips1.png"],
[UIImage imageNamed:#"trips2.png"],
[UIImage imageNamed:#"trips3.png"],
[UIImage imageNamed:#"trips4.png"],
[UIImage imageNamed:#"trips5.png"],
[UIImage imageNamed:#"trips6.png"],nil];
[animation setAnimationRepeatCount:0];
animation.animationDuration = 0.65;
[animation startAnimating];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)showMessage:(id)sender
{
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Hello World!" message:#"This is your first UIAlertview message." delegate:nil cancelButtonTitle:#"Close" otherButtonTitles:nil];
[message show];
}
#end
I am not sure what I am doing wrong, or why the app keeps stalling at the loading screen, please help!
I found this in the debugger
2012-12-01 19:39:03.428 MindTrip[3327:11303] * Terminating app due
to uncaught exception 'NSUnknownKeyException', reason:
'[ setValue:forUndefinedKey:]: this class is
not key value coding-compliant for the key Alert.'
* First throw call stack: (0x1c9a012 0x10d7e7e 0x1d22fb1 0xb84711 0xb05ec8 0xb059b7 0xb30428 0x23c0cc 0x10eb663 0x1c9545a 0x23abcf
0xffe37 0x100418 0x100648 0x100882 0x4fa25 0x4fdbf 0x4ff55 0x58f67
0x1cfcc 0x1dfab 0x2f315 0x3024b 0x21cf8 0x1bf5df9 0x1bf5ad0 0x1c0fbf5
0x1c0f962 0x1c40bb6 0x1c3ff44 0x1c3fe1b 0x1d7da 0x1f65c 0x2a4d 0x2975)
libc++abi.dylib: terminate called throwing an exception (lldb)
The issue is that you have added alert(or a pointer to some view called alert) in your storyboard but the same is not added to the class code. If you are displaying the alert view programmatically, you can remove it from the storyboard.
Related
I have found some code for my infoButton which shows up my new credits.xib but I can't manage to come back to my RootViewController.
On my Credits.xib, I have linked my "Done" button with ToucheDown-FirstResponder-ToggleCredits Close.
Here is my code for the infoButton in my RootViewController.m in ViewDidLoad
UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoLight];
[button addTarget:self action:#selector(toggleCreditsOpen:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *modalButton = [[UIBarButtonItem alloc] initWithCustomView:button];
[self.navigationItem setRightBarButtonItem:modalButton animated:YES];
//[button release];
[modalButton release];
and my code just after my ViewDidLoad
- (IBAction) toggleCreditsOpen:(id)inSender
{
UIViewController *theController = [[UIViewController alloc] initWithNibName:#"Credits" bundle:nil];
[self.navigationController presentModalViewController:theController animated:YES];
}
- (IBAction) toggleCreditsClosed:(id)inSender
{
NSLog(#"Button Pressed!");
//[self.navigationController dismissModalViewControllerAnimated:YES];
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
I think I am missing something should I create a Credits.h and put the toggleCreditsClosed in it ?
Here is the stack trace
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIViewController 0x7c67610> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key DoneButton.'
*** First throw call stack:
Here is my Credits.h
#import <UIKit/UIKit.h>
#interface Credits : UIViewController
{
IBOutlet UIButton *DoneButton;
}
#property (nonatomic, retain) UIButton *DoneButton;
#end
and my Credits.m
#import "Credits.h"
#implementation Credits
#synthesize DoneButton;
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
}
- (IBAction) toggleCreditsClosed:(id)inSender
{
NSLog(#"Button Pressed!");
[self dismissModalViewControllerAnimated:YES];
}
#end
If a delete the DoneButton link, the Credits view shows up but I it's when I press the Done button that I have a problem
Costumes[402:11f03] -[UIViewController toggleCreditsClosed:]: unrecognized selector sent to instance 0x7a4c460
2012-10-24 22:19:33.271 Costumes[402:11f03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController toggleCreditsClosed:]:
Sorry but I don't understand what I have to do and I cannot upload an image to show you but
in Outlets the link is (view<->View) and in Received Actions (toggleCreditsClosed:<->Button-Done Touch Down)
Welcome on SO !
Yes, you should create a separate .h / .m for your Credits. Then tell Inteface Builder that your .xib is a Credits class. Then link your button to this .h with the action you want. Basically, your last method should be in Credits.m :
- (IBAction) toggleCreditsClosed:(id)inSender
{
NSLog(#"Button Pressed!");
[self dismissModalViewControllerAnimated:YES];
}
Watch out, you dismiss the modal view with self instead of self.parentViewController in your code !
(PS : answers you'll get may not always work. Don't hesitate to comment, telling us what (didn't) work !)
I have a tableView with an button to push a mapView. The push and back actions generally work fine. If I switch quickly between these two views, "EXC_BAD_ACCESS" error will appear.
MapViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
UIButton *btnL = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 40.0, 40.0)];
[btnL setImage:[UIImage imageNamed:#"back.png"] forState:UIControlStateNormal];
[btnL addTarget:self.navigationController action:#selector(popViewControllerAnimated:) forControlEvents:UIControlEventTouchDown];
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:btnL] autorelease];
[btnL release];
self.whereAmIAnnotation = [[[WhereAmIAnnotation alloc] init] autorelease];
if (!self.mapView || !self.whereAmIAnnotation) {
NSLog(#"mapview : %#", self.mapView);
NSLog(#"whereAmIAnnotation : %#",self.whereAmIAnnotation);
// will never enter in to here
}
[self.mapView addAnnotation:self.whereAmIAnnotation];
}
If I comment [self.mapView addAnnotation:self.whereAmIAnnotation]; , there is no "EXC_BAD_ACCESS" anymore.
Any answers and comments will be appreciated. Thanks in advance!
Edit 2
main.m
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
// "EXC_BAD_ACCESS" error message shows here
}
}
Edit 3:
the whereAmIAnnotation is declared here:
MapViewController.m
#interface AddrCoordinateAdjustMapViewController()
#property (retain) WhereAmIAnnotation *whereAmIAnnotation;
#end
#implementation MapViewController
#synthesize whereAmIAnnotation;
Edit 4:
Error message is as following:
2012-07-30 15:56:19.735 myApp[13584:707] *** -[MapViewController respondsToSelector:]: message sent to deallocated instance 0x10195e80
It usually crashes when i switch back to the tableView while the annotationView is dropping.
Have you removed yourself as delegate of the mapview?
self.mapview.delegate = nil;
try removing it at viewWilldisappear or whenever you consider necessary as you might need it later if you have pushed a view controller and will return to the view later.
In a nutshell, remove it when your view cannot respond to the delegate which is why you got the EXC_BAD_ACCSS. it sent a message to your view but it was already released from memory.
Do you release and set to nil all your IBOutlets in the viewDidUnload? So at least you should do:
- (void)viewDidUnload {
self.mapView = nil;
[super viewDidUnload];
}
Generally in ViewDidUnload you should release and set to nil, any view objects that are created from a Nib file or allocated in your ViewDidLoad method
I would suggest to check whether self.whereAmIAnnotation isnt already released by at the time you add it to mapView. That might be one reason for the BAD_ACCESS you receive.
I had similar problem and my solution was to remove all overlays from the map before popping controller from UINavigationController. I was using OpenStreetMap.
I've created an ARC Application that run's perfect. It's got a UINavigationController that I use to push through the views and everything runs fine.
I'm converting the Application to iPad and i've decided to show one of the views as a popover. (I don't like UIPopoverController so i've created my own basic popup). It's added to the view as follows..
MyViewController *hotelinf = [[MyViewController alloc]
initWithNibName:#"MyViewController_iPad" bundle:nil];
[self.view addSubview:hotelinf.view];
The view is added as a subview fine. The view i'm adding contains a UIWebView that has the usual delegate methods in it, but when the view tries to access one of the delegates it simply crashes.
*** -[MyViewController respondsToSelector:]: message sent to deallocated instance 0x7917b90
Specifically, it crashes on this line..
[self.webView loadHTMLString:stringResponse baseURL:nil];
I've displayed views (and UINavigationControllers) as subViews many of times without any issues, although none of them included a UIWebView delegate. I'm guessing I have to set the delegate of my UIViewController istance but i'm not sure how. It's also worth noting that if I push the view in my existing UINavigationController it calls and loads the HTML fine, which surely means it has nothing to do with the code of the view itself.
Any help would be greatly appreciated! Here is the code (in addition to above that shows the controller)..
.h
#interface MyViewController : UIViewController <UIWebViewDelegate, UIActionSheetDelegate> {
//Unrelated IBOutlets
}
#property (nonatomic, strong) UIWebView *webView;
#end
.m
#implementation MyViewController
#synthesize webView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.webView = [[UIWebView alloc]initWithFrame:CGRectMake(317,283,393,354)];
self.webView.delegate = self;
[self.view addSubview:self.webView];
[NSThread detachNewThreadSelector:#selector(getHTMLString) toTarget:self withObject:nil];
}
-(void)getHTMLString {
#autoreleasepool {
//Download a valid HTML String
[self performSelectorOnMainThread:#selector(loadHTML) withObject:nil waitUntilDone:NO];
}
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.webView = nil;
}
-(void)loadHTML {
self.webView.opaque = NO;
self.webView.backgroundColor = [UIColor clearColor];
if ([stringResponse isEqualToString:#""]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Could not connect to XXXXX.com. Please verify you are connected to a working 3G/WIFI Network." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
} else {
//it crashes here only when loaded as a subview - the first access to the delegate
[self.webView loadHTMLString:stringResponse baseURL:nil];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self stopIndicator];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
if (error.code == NSURLErrorCancelled) return; // this is Error -999
[self stopIndicator];
// report the error inside the webview
NSString* errorString = [NSString stringWithFormat:
#"<html><center><font size=+10 color='black' face='Helvetica'>An error occurred:<br>%#</font></center></html>",
error.localizedDescription];
[self.webView loadHTMLString:errorString baseURL:nil];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Cannot load URL."
message:#"You have a connection failure. Please verify you are connected to a WIFI or 3G enabled Network."
delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}
#end
The issue has nothing to do with the UIWebView, rather with your controller class. Indeed,
MyViewController *hotelinf = [[MyViewController alloc]
initWithNibName:#"MyViewController_iPad" bundle:nil];
[self.view addSubview:hotelinf.view];
You are allocating the controller and assigning it to a local variable; then you add the controller's view as subview to your current view. Doing that, that view is retained, but what happens to the controller object itself? Are you releasing it? Or it leaks (since it is assigned to a local variable)?
This possibly explains why when later the respondsToSelector method is called, the controller has already been deallocated...
A way to fix this is creating a new property or an ivar in your main controller class and store MyViewController in there. Don't forget to release it in dealloc.
I would also suggest another thing. In:
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.webView = nil;
}
set the webView delegate to nil before releasing the view:
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.webView.delegate = nil;
self.webView = nil;
}
And I would also possibly review the reason why you release the webView in viewDidDisappear. On the other hand you allocate it in viewDidLoad. This asymmetry is dangerous, since whenever the main view disappears (for any reason) the webView will be removed and when the view reappears, it is not there anymore.
Better add all the delegate methods. You havent added the first two. Most probably, your code is crashing when message webViewDidStartLoad is sent
– webView:shouldStartLoadWithRequest:navigationType:
– webViewDidStartLoad:
– webViewDidFinishLoad:
– webView:didFailLoadWithError:
Hi there I currently I have a warning on a line of code where I am trying to push a new view onto the screen.
Outline // my NSObject receives a code=1 from my server I have set up. Everything works fine the code comes through which then initializes an AlertView where I have set up an if statement to catch the button click of my AlertView message. When that button is pressed my application falls over.
I have declared my ViewController of the view I am trying to push in its header file and there are no errors just the warning when compiled.
this is my NSObject I have made
/////.h
#import <Foundation/Foundation.h>
#interface alerts : NSObject {
}
- (void)pleaseRegisterDevice;
#end
/////.m
#import "alerts.h"
#import "instaCode1_3AppDelegate.h"
#import "RegisterDeviceViewController.h"
#implementation alerts
//use this alert when phone falls out of sync
- (void)pleaseRegisterDevice {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Please Register Device"
message:#"click OK to register"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert autorelease];
[alert show];
}
//Catch pleaseRegisterDevice method
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
NSString *buttonTitle=[alertView buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:#"OK"]) {
NSLog(#"msg from alertView method");
//open new wndow
RegisterDeviceViewController *regViewController = [[RegisterDeviceViewController alloc] init];
//Push it onto the top pf the navigation controller's stack
**[[self navigationController] pushViewController:regViewController animated:YES];**
}
else {
NSLog(#"was not able to push view");
}
}
- (void)dealloc {
[super dealloc];
}
#end
I have bolded the line of code where I get the warning 'alerts' may not respond to -navigationController
any help would be greatly appreciated.
I dont think an NSObject subclass has a UINavigationController...
You need to get a pointer to your app delegate's navigation controller like so
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.navigationController pushViewController:regViewController animated:YES];
navigationController is a property defined on a UIViewController. A NSObject does not have this method.
You don't have any instance member or method called navigationController, hence the warning.
I am having an issue with updating the contents of an "myInfoBox" object I created to be displayed while some background processes are done.
In the delegate method I am creating a new viewController:
-(void)loadMainView
{
myFirstViewController = [[MyFirstViewController alloc] initWithNibName:#"MyFirstView" bundle:nil];
navigationController = [[UINavigationController alloc] initWithRootViewController:myFirstViewController];
// myFirstViewController was retained again by the controller, release one
[myFirstViewController release];
navigationController.navigationBar.hidden = YES;
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
// the next method is run after the "viewDidLoad" is finished loading
[myFirstViewController loadAlertViewForNewUser];
}
Following is my implementation of "myFirstViewController", it creates an instance of the "infoBox" class(I will show its code later):
- (void)viewDidLoad {
self.navigationController.navigationBar.frame = CGRectMake(0, 0, 0, 0);
self.navigationController.navigationBar.bounds = CGRectMake(0, 0, 0, 0);
self.myInfoBox = [[InfoBoxController alloc] initWithNibName:#"InfoBox" bundle:[NSBundle mainBundle]];
CGRect infoBoxFrame;
infoBoxFrame = CGRectMake(60, 120, 200, 200);
myInfoBox.view.frame = infoBoxFrame;
myInfoBox.i_statusLabel.text = #"Downloading Account Updates";
myInfoBox.i_titleLabel.text = #"Updating";
// disabled for testing
//myInfoBox.view.hidden = YES;
[self.view addSubview:myInfoBox.view];
[super viewDidLoad];
}
// this method is called after the view has been loaded by the delegate
- (void)loadAlertViewForNewUser
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Welcome!" message:#"Connect to download stuff from your account?"
delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
alert.tag = 0;
[alert show];
}
// implementation of the alertview delegate
- (void)alertView:(UIAlertView *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (actionSheet.tag == 0)
{
if (buttonIndex == 0)
{ NSLog(#"button 0 was pressed"); }
if (buttonIndex == 1)
{
// this is the button that is pressed
[actionSheet removeFromSuperview];
[actionSheet release];
// tried using this also
//[self performSelectorOnMainThread:#selector(userInitialSetupMainThread) withObject:nil waitUntilDone:NO];
// do stuff and update the infobox about it
[self loadInfoBoxInitialUserSetup];
// tried using this as well
//[self performSelectorInBackground:#selector(loadInfoBoxInitialUserSetup) withObject:nil];
}
return;
}
}
- (void)loadInfoBoxInitialUserSetup
{
[self performSelectorOnMainThread:#selector(userInitialSetupMainThread) withObject:nil waitUntilDone:NO];
}
- (void)userInitialSetupMainThread
{
// fetch JSON data
NSDictionary *responseJSON = [NSDictionary dictionaryWithDictionary:[self getUserstuff]];
self.myInfoBox.i_statusLabel.text = #"Processing Recieved information";
// breakpoint - nothing changes in the view on the simulator
[myInfoBox.view setNeedsLayout];
// breakpoint - nothing changes in the view on the simulator
[myInfoBox.view setNeedsDisplay];
// breakpoint - nothing changes in the view on the simulator
[myInfoBox.parentViewController.view setNeedsLayout];
// breakpoint - nothing changes in the view on the simulator
[myInfoBox.parentViewController.view setNeedsDisplay];
// breakpoint - nothing changes in the view on the simulator
[myInfoBox performSelectorOnMainThread:#selector(updateValuesForTitle:) withObject:#"test" waitUntilDone:YES];
// breakpoint - nothing changes in the view on the simulator
[self.view setNeedsLayout];
// breakpoint - nothing changes in the view on the simulator
[self.view setNeedsDisplay];
// breakpoint - nothing changes in the view on the simulator
self.myInfoBox.i_statusLabel.text = #"Reloading...";
// breakpoint - nothing changes in the view on the simulator
[self readStuffFromDB];
sleep(2);
//disabled view removal for testing..
//[self.myInfoBox.view removeFromSuperview];
// breakpoint - nothing changes in the view on the simulator
}
What happens for me in the testing is that the myInfoBox object is created on screen when the -(void)loadMainView method is complete, then I can see on screen the "myInfoBox" in the background while the alertView in front (for testing...) at this point the screen is responsive and I can select the YES, once I select yes the delegate method is called.
As I commented in the source file, using breakpoints I am monitoring the simulator and following the code, never the less the changed label values are not reflected while I am still in the - (void)userInitialSetupMainThread method, but once it finishes the view updates with the latest set .text value!! grrr..
Also, the source for the myInfoBox class:
#interface InfoBoxController : UIViewController {
IBOutlet UILabel* i_titleLabel;
IBOutlet UILabel* i_statusLabel;
IBOutlet UIImageView* i_loadingImage;
IBOutlet UIImageView* i_background;
IBOutlet UIActivityIndicatorView* i_activityIndicator;
}
#property(nonatomic, retain) IBOutlet UILabel* i_titleLabel;
#property(nonatomic, retain) IBOutlet UILabel* i_statusLabel;
#property(nonatomic, retain) IBOutlet UIImageView* i_loadingImage;
#property(nonatomic, retain) IBOutlet UIImageView* i_background;
#property(nonatomic, retain) IBOutlet UIActivityIndicatorView* i_activityIndicator;
//- (void)updateValuesForTitle:(NSString *)title Label:(NSString *)label;
- (void)updateValuesForTitle:(NSString *)title;
#end
#implementation InfoBoxController
#synthesize i_titleLabel, i_statusLabel, i_loadingImage, i_background;
#synthesize i_activityIndicator;
//-(void)updateValuesForTitle:(NSString *)title Label:(NSString *)label
-(void)updateValuesForTitle:(NSString *)title
{
self.i_titleLabel.text = title;
self.i_statusLabel.text = title;
[self.i_titleLabel setNeedsDisplay];
[self.i_statusLabel setNeedsDisplay];
}
Sorry for the LOONG post :)
PLEASE ASSIST!
At the risk of sounding unhelpful, that's kind of just how it works. If you have long-running code in the main event loop (i.e., you don't explicitly create a thread or similar), the operating system won't be able to update the UI.
To update the UI while your code is running, you either need to run your complex operation in the back ground using thread, NSOperationQueue, etc, or just break it into smaller steps and return control to the main loop occasionally so that the UI can be updated.