I began from a tutorial example that had a UIViewController connected to a nib, but now i've decided to do it all programmatically. Consequently, I deleted the nib but without knowing how to implement my controller.
I did something like this:
EventsDetailController *myChild = [[EventsDetailController alloc] init];
[self.navigationController pushViewController:myChild animated:YES];
However, it crashes when I click the specific cell.
Do I have to initWith something? Before when I had a nib it was initWithNib
#import <UIKit/UIKit.h>
#interface EventsDetailController : UIViewController {
NSString *message;
}
#property (nonatomic, copy) NSString *message;
#end
#import "EventsDetailController.h"
#implementation EventsDetailController
#synthesize message;
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
}
-(void)viewDidLoad{
UILabel *theMsg = [[UILabel alloc] initWithFrame:CGRectMake(0,0,200,30)];
theMsg.text = #"hello";
[theMsg release];
[super viewDidLoad];
}
-(void)viewDidUnload{
self.message = nil;
[super viewDidUnload];
}
-(void)dealloc{
[message release];
[super dealloc];
}
#end
Perhaps, I'll start from scratch, I think it is still looking for the nib I deleted.
I'm assuming that you have the app delegate's window.rootViewController set to a NavigationController instance, and that instance was created with a initWithRootViewController, as you mentioned that you're getting to the point where it crashes when you click on a cell.
Looking at the added code, the only thing I see that's strange is in the 'veiwDidLoad' method - you alloc and release 'theMsg', but don't use it. I'm assuming you've cut out some code for brevity.
I ended up starting from scratch when I went away from .nib files (about 5 minutes after starting my first iPhone app). I would run with that, adding in your functionality a little at a time.
Related
I need to view a subview with an activity indicator.
This is my code but the subview doesn't appear:
#interface ProgressViewController : UIViewController {
IBOutlet UIActivityIndicatorView *myActivityIndicator;
}
#property (nonatomic, retain) IBOutlet UIActivityIndicatorView *myActivityIndicator;
#end
#implementation ProgressViewController
#synthesize myActivityIndicator;
- (void)viewDidLoad {
[myActivityIndicator startAnimating];
[super viewDidLoad];
}
- (void)viewWillDisappear:(BOOL)animated {
[myActivityIndicator stopAnimating];
}
#end
#import "ProgressViewController.h"
#interface MyViewController : UIViewController {
ProgressViewController *progressViewController;
}
#property (nonatomic, retain) ProgressViewController *progressViewController;
#end
#implementation MyViewController
#synthesize progressViewController
- (void)viewDidLoad
{
progressViewController = [[ProgressViewController alloc] initWithNibName:#"ProgressViewController" bundle:nil];
[self.view addSubview:progressViewController.view];
sleep(4);
[progressViewController.view removeFromSuperview];
[super viewDidLoad];
}
#end
There could be several causes, and it's still a bit unclear from the code you sent, which one it is.
First, you shouldn't use sleep(4) in your code - it messes up the application engine iOS runs to support user input, screen refresh, etc.
Your code could easily be changed to:
[self performSelector:#selector(removeMyProgressView:) withObject:progressViewController.view afterDelay:4.0];
and have removeFromSuperview in your removeMyProgressView: function.
Also, this line of code is buggy:
progressViewController = [[ProgressViewController alloc] initWithNibName:#"ProgressViewController" bundle:nil];
It should be
self.progressViewController = [[ProgressViewController alloc] initWithNibName:#"ProgressViewController" bundle:nil];
Otherwise you don't call the setter function (#sythesized property), and the object isn't retained. It could be that it is released, and therefore you don't see it.
If this none of this is right, we'll keep pounding at it :)
Good luck!
Oded.
Everything in your -viewDidLoad method happens in one runloop. This means that you add and remove the activity indicator without giving the system a chance to actually draw it. The 4 seconds of sleep don't help. Those just make the runloop take longer to finish.
call [super viewDidLoad] before anything in - (void)viewDidLoad methods
I'm developing an application.
I used a TabBar and every tab have its Class (FirstViewController, SecondViewController, ... )
There is one AppDelegate too.
When I launch the program, the first Class is running.
When i select the second tab, the Secondview.xib 's running but the "viewDidLoad" isn't working.
When I select the third Tab, that's the same.
I've put some buttons on the third tab, and when I push it, I have a
> -[UIViewController testAuthentication:]: unrecognized selector sent to instance 0x5f16920
2011-04-08 13:46:42.511 e-mars[19501:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController testAuthentication:]: unrecognized selector sent to instance 0x5f16920'
Here's the code of my classes
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController {
}
#end
SecondViewController.m
#import "SecondViewController.h"
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"viewDidLoad de SecondViewController");
NSURL *url = [NSURL URLWithString: #"http://iosdevelopertips.com/images/logo-iphone-dev-tips.png"];
UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
[self.view addSubview:[[UIImageView alloc] initWithImage:image]];
}
- (void)dealloc {
[super dealloc];
}
#end
ThirdViewController.h
#import <UIKit/UIKit.h>
#interface ThirdViewController : UIViewController {
IBOutlet UITextField *login;
IBOutlet UITextField *motdepasse;
NSMutableData *responseData;
}
#property (retain, nonatomic) UITextField *login;
#property (retain, nonatomic) UITextField *motdepasse;
#property (retain, nonatomic) NSMutableData *responseData;
- (IBAction) testAuthentication: (id)sender;
- (IBAction) saveAuthentication: (id)sender;
#end
ThirdViewController.m
#import "ThirdViewController.h"
#implementation ThirdViewController
#synthesize login;
#synthesize motdepasse;
#synthesize responseData;
- (id)initWithFrame:(CGRect)frame {
//if ((self = [super initWithFrame:frame])) {
// Initialization code
//}
return self;
}
-(IBAction) testAuthentication: (id)sender {
//NSLog(#"testAuthentication");
}
- (IBAction) saveAuthentication: (id)sender {
NSLog(#"saveAuthentication");
}
- (void)dealloc {
[login dealloc];
[motdepasse dealloc];
[responseData dealloc];
[super dealloc];
}
#end
Your third ViewController doesn't actually create an instance, so no instance methods can be called upon it. Fix your initWithFrame: method. Remember: instance methods start with the '-' sign, class methods start with the '+' sign.
- (id)initWithFrame:(CGRect)frame {
self = [super initWithNibName:nil bundle:nil];
if (self)) {
// Initialization code
}
return self;
}
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
{
return [self initWithFrame:CGRectZero];
}
- (id)init
{
return [self initWithFrame:CGRectZero];
}
After you fixed this, at least the viewDidLoad method in the third ViewController should work.
With regards to the second ViewController, could you please show the code you use to instantiate the ViewController?
Edit: I've made some changed to make sure initWithFrame: is always called upon initialization, just in case you create the instance using another method (initWithNibName:bundle: or init), now initWithFrame: has become the designated initializer.
Set class in Viewcontroller.
and then try.
Check the Object On which your are calling testAuthentication
May be you are calling testAuthentication on secondViewController's object , Just check and let us know
First time alone the viewController will come from viewDidLoad after that it does not call viewDidLoad instead it calls viewWillAppear. so you can code whatever you want in viewWillAppear.
The question is if insertSubview is retaining the views and if I'm doing it right.
I would say yes. Since I'm not using the property anymore I don't receive an EXC_BAD_ACCESS. I think when releasing the view all subviews are also released. And so mapView is over-released. I'm right or do I still have a memory management issue?
My ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController <MKMapViewDelegate> {
MKMapView *mapView;
// ...
}
//#property (nonatomic, retain) MKMapView *mapView;
// ...
#end
My ViewController.m
#import "MapViewController.h"
#implementation MapViewController
//#synthesize mapView;
- (void)viewDidLoad {
[super viewDidLoad];
//self.mapView=[[[MKMapView alloc] initWithFrame:self.view.bounds] autorelease];
mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
[self.view insertSubview:mapView atIndex:0];
[mapView release];
// ...
}
- (void)dealloc {
//[mapView release];
[super dealloc];
}
#end
- (void)dealloc {
//[mapView dealloc];
[super dealloc];
}
You should never call dealloc directly (save for [super dealloc]; at the end of the method). That will most assuredly cause a crash in most situations.
Since that isn't the source of your crash, you have an over-release somewhere. Use Instrument's Zombie Detection to figure out where.
Yes, you are correct on all counts:
the call to insertSubView: should be retaining the mapView that you are passing it.
releasing your reference to the mapView after you add it to the parent view
the parent view will release all the retained subviews when it is released
As a rule, you should not worry about whether or how another object will retain an instance you give it. That's up to that object to deal with; you only have to worry about making sure an instance that you intend to directly access later is retained. Don't rely on another object to keep an instance retained for you.
In your example, you have an instance (mapView) which is accessible to MapViewController but MapViewController does not have it's own retention for it. self.view could release mapView at any time for any number of reasons and you'd suddenly have bad memory there.
I am new to objective C and I have a c++ background. I want to display a value in the label on the screen. I am calling the label value from the MainView.m. However, the label becomes blank after I click a button instead of printing a value. What is the problem? Here is the code.
MainView.h
#interface MainView : UIView {
int a;
}
-(int) vr;
#end
MainView.m
-(int) vr
{
return 100;
}
#end
MainViewController.h
#interface MainViewController : UIViewController {
IBOutlet UILabel *myLabel;
NSMutableString *displayString;
MainView *view1;
}
#property (nonatomic, retain) UILabel *myLabel;
#property (nonatomic, retain) NSMutableString *displayString;
(IBAction)showInfo;
(IBAction) pressButton:(id) sender;
#end
MainViewController.m
#synthesize myLabel, displayString;
-(IBAction) pressButton:(id) sender{
[displayString appendFormat:#"%i", view1.vr];
myLabel.text = displayString;}
- (void)viewDidLoad {
view1 = [[MainView alloc] init];
[super viewDidLoad];}
- (void)dealloc {
[view1 dealloc];
[super dealloc];}
I have not mentioned code that had been auto generated. This is enough to get the whole picture. I tried a lot to debug this thing. I believe that IBAction carries out direct command such that
myLabel.text = #"string";
but it does not invoke any method or class. Any subtle ideas? Thanks.
Few issues:
1
In MainView.h you declare -(id) vr;
And in MainView.m it returns int.
2
Maybe pressButton is not connected to the right event in Interface Builder (it is usually touch up inside).
Try to write to log in this method.
3
Maybe myLabel is not connected to the label in the Interface Builder.
Try to set tome hard-coded string to label's text property.
4
Do you initiate view1 in some place?
Can you post this piece of code too?
5
You can use [displayString appendFormat:#"%i", view1.vr];...
EDIT (due to changes in question):
6
The line [super viewDidLoad]; should be the first line inside viewDidLoad.
7
[view1 dealloc]; - never call dealloc directly on objects. Call release instead. The only place, where you can and should use dealloc is the line [super dealloc]; inside dealloc method.
8
When you format your question/answer in Stack Overflow, remember that each code line should start with at least 4 spaces (or tab). Try reformatting you question by adding 4 spaces in the beginning of each code line.
9
I think that displayString is not initiated. Add the next line in the viewDidLoad: displayString = [NSMutableString new];
I have an iPhone application that loads succesive views in a framework based on the one explained in this link (basically a main ViewController that loads/removes additional views with a displayView method). In my application I am using NIBs (the example link uses coded views) though so each of my ViewControllers has its accompanying nib.
Debugging in Instruments shows no leaks but if I enter/leave a section (ViewController with its View.xib), the nib remains in memory so after a few in/outs memory starts to accumulate.
I know the nib is not being unloaded because one is almost programmatically created (no stuff in IB) while another does have images and buttons created in IB. The large one is loaded first and the small one loads next. You would expect a reduction in allocation in Instruments.
How can I prevent this?
My structure is as follows, with a few comments below:
`MyAppDelegate.h`
#import <UIKit/UIKit.h>
#class RootViewController;
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
RootViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet RootViewController *viewController;
-(void) displayView:(int)intNewView;
#end
`MyAppDelegate.m`
#import "MyAppDelegate.h"
#import "RootViewController.h"
#implementation MyAppDelegate
#synthesize window;
#synthesize viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}
-(void) displayView:(int)intNewView {
[viewController displayView:intNewView];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
This controller handles subview load/removes:
`RootViewController.h`
#import <UIKit/UIKit.h>
#interface RootViewController : UIViewController {
}
- (void) displayView:(int)intNewView;
#end
`RootViewController.m`
#import "RootViewController.h"
#import "ViewController.h"
#implementation RootViewController
UIViewController *currentView;
- (void) displayView:(int)intNewView {
NSLog(#"%i", intNewView);
[currentView.view removeFromSuperview];
[currentView release];
switch (intNewView) {
case 1:
currentView = [[ViewController alloc] initWithNibName:#"View" bundle:nil];
break;
}
[self.view addSubview:currentView.view];
}
- (void)viewDidLoad {
currentView = [[ViewController alloc]
initWithNibName:#"View" bundle:nil];
[self.view addSubview:currentView.view];
[super viewDidLoad];
}
- (void)dealloc {
[currentView release];
[super dealloc];
}
#end
There would be as many case as "detail" ViewControllers I have (right now I have 3 case but this will grow to 10 or more). The purpose of this structure is to easily move from one "section" of the application to another (NavBar controller or TabBar controller do not suit my specific needs).
`ViewController.h`
// Generic View Controller Example
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
UIImageView *_image1;
UIImageView *_image2;
NSTimer *_theTimer;
}
#property (nonatomic, retain) IBOutlet UIImageView *image1;
#property (nonatomic, retain) IBOutlet UIImageView *image2;
#property (nonatomic, retain) NSTimer *theTimer;
#end
`ViewController.m`
#import "ViewController.h"
#import "MyAppDelegate.h"
#synthesize image1 = _image1, image2 = _image2, theTimer = _theTimer;
- (void)loadMenu {
[self.theTimer invalidate];
self.theTimer = nil;
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate displayView:2];
}
-(void)setView:(UIView*)aView {
if (!aView){
self.image1 = nil;
self.image2 = nil;
}
[super setView:aView];
}
- (void)viewDidLoad {
//some code
[super viewDidLoad];
}
- (void)viewDidUnload {
self.image1 = nil;
self.image2 = nil;
}
- (void)dealloc {
NSLog(#"dealloc called");
[self.theTimer invalidate];
[self.theTimer release];
[self.image1 release];
[self.image2 release];
[super dealloc];
}
Notice the NSLog in dealloc. This is being called (I can see it in the console) but the memory needed for the nib is not freed (Instruments shows an increase in memory allocation when leaving a section, because a new nib is loaded).
Any help will be greatly appreciated. I have tried a million different things and I cannot get the nibs to unload.
After a million different tries I finally ran into this forum.
It states:
Apparently images assigned in IB are loaded into image views using imageNamed. imageNamed caches the images in a way that makes them unloadable. You could load the images in viewDidLoad with initWithContentsOfFile and then assign them to the views.
Somewhere else I had read that imageNamed is the devil so I'd rather not have my images load that way.
(BTW this is iPhone OS 3.1 I'm using)
What I ended up is leaving the UIImageView intact in IB but with an empty .image value. The modified code is something like:
- (void)viewDidLoad {
NSString *path = [NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] resourcePath], #"myImageThatBeforeWasAValueinIB.jpg"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
outlet.image = image;
// do the rest of my stuff as it was
[super viewDidLoad];
}
- (void)dealloc {
outlet.image = nil;
[outlet release], outlet = nil;
[super dealloc];
}
And now everything works like a charm! Memory is recovered when I unload a nib and when I get memory warnings.
So pretty much if you have IBOutlets for UIImageViews and memory is a concern (it always is I guess), you can design all you want in IB and when the time comes to connect them to outlets, remove the image reference in IB and create it from code. IB is really good for laying out your app. It would suck to have to do all that thing by code, but I also found this nice utility that converts nibs to objective c code although I haven't tested it yet.
Did you try setting your outlet variables to nil in dealloc?
You are correctly implementing the setView method, but you are setting your outlet variables to nil in the viewDidUnload method instead of dealloc. As discussed here, you should implement dealloc as follows:
- (void)setView:(UIView *)aView {
if (!aView) { // view is being set to nil
// set outlets to nil, e.g.
self.anOutlet = nil;
}
// Invoke super's implementation last
[super setView:aView];
}
- (void)dealloc {
// release outlets and set outlet variables to nil
[anOutlet release], anOutlet = nil;
[super dealloc];
}
EDIT: if the outlets are UIImageViews, then it may be the case that you need to do
anOutlet.image = nil;
because setting the UIImage’s instance image property should increase the retain count of the UIImage’s instance by 1.