- (void)dealloc Question - iphone

Can you tell me if the following code is 100% correct? Expecially the dealloc section
FirstViewController.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#class SecondViewController
#interface FirstViewController : UIViewController
{
SecondViewController *SecondController;
}
- (IBAction)SwitchView;
#property (nonatomic, retain) IBOutlet SecondViewController *SecondController;
#end
FirstViewController.m
#import "FirstViewController.h"
#implementation FirstViewController
#synthesize SecondController;
- (IBAction)SwitchView
{
SecondController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
SecondController.modalTransitionStyle = UIModalPresentationFullScreen;
[self presentModalViewController:SecondController animated:YES];
[SecondController release];
}
/// OTHER CODE HERE ///
- (void)dealloc
{
[SecondController release];
[super dealloc];
}
#end
Thanks!

No it is not correct. You are sending the release message to a pointer in dealloc, but the pointer may or may not point to the SecondController anymore. This may lead to some very weird bugs, typically random objects being released.
In objective-c terms, your class doesn't retain (think "own") the SecondController, so it should not try to release it in the first place on dealloc.
To claim and release ownership the correct way, make it so:
- (IBAction)SwitchView
{
self.SecondController = [[[SecondViewController alloc]
initWithNibName:#"SecondViewController" bundle:nil] autorelease];
self.SecondController.modalTransitionStyle = UIModalPresentationFullScreen;
[self presentModalViewController:self.SecondController animated:YES];
}
/// OTHER CODE HERE ///
- (void)dealloc
{
self.SecondController = nil;
[super dealloc];
}
This will also protect you from any other stuff happening between SwitchView and dealloc. (as long as that stuff follows the rules and uses self.SecondController = ... to change the property)
In SwitchView the alloc/autorelease sequence makes that your routine keeps ownership for the length of the routine (and a little beyond). The self.SecondController = part makes sure that your class retains the SecondController object, since you declared it (nonatomic,retain).

You should use the property setter to assign SecondController.
I suggest you only alloc/init that view controller once, then in SwitchView show it:
#import "FirstViewController.h"
#implementation FirstViewController
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
if((self = [super initWithNibName:nibName bundle:nibBundle])) {
self.SecondController = [[[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil] autorelease];
SecondController.modalTransitionStyle = UIModalPresentationFullScreen;
}
return self;
}
- (IBAction)SwitchView
{
[self presentModalViewController:SecondController animated:YES];
}
/// OTHER CODE HERE ///
- (void)dealloc
{
[SecondController release];
[super dealloc];
}
#end
This way, you only actually create that SecondController view controller once, as opposed to creating it every time -SwitchView is invoked.

Related

NSLog returns (null) when logging string from another view controller

I posted a question earlier about the same thing, but now I have made a simple project to show what I am doing, so the problem can be found easier.
I have two viewControllers, one is called ViewController and the other SecondViewController.
I tried sending a NSString called testy to a viewController and logging it, but it returned null.
Here is my code trying to send the string from viewController to secondViewController
ViewController.m
#import "ViewController.h"
#import "SecondViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize cellName;
- (void)viewDidLoad
{
[super viewDidLoad];
cellName = #"testy";
SecondViewController *obj = [[SecondViewController alloc] init];
obj.cellName2 = self.cellName;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
}
#property(nonatomic,retain) NSString *cellName;
#end
SecondViewController.m
#import "SecondViewController.h"
#import "ViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize cellName2;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated {
NSLog(#"%#",cellName2);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController {
}
#property(nonatomic,retain) NSString *cellName2;
#end
Edit
I would like to say that my storyboard has two viewController that each have a button. Each button modally brings you to the other view.
Are you sure viewDidLoad is being called? I think it's not called until the view is loaded. I don't think it's called after an alloc init. Also you are setting the string in obj 2 after init. Even if what you are thinking is correct, the 'viewDidLoad' method may be called before the string is being set.
If you want a variable set on init you need to override viewController 2's init method to something like initWithMyVariable then the var will be set on init.
From: Passing Data between View Controllers
Passing data forward to a view controller from another view controller. You would use this method if you wanted to pass an object/value from one view controller to another view controller that you may be pushing on to a navigation stack.
For this example we will have ViewControllerA and ViewControllerB
To pass a BOOL value from ViewControllerA to ViewControllerB we would do the following.
in ViewControllerB.h create a property for the BOOL
#property(nonatomic) BOOL *isSomethingEnabled;
in ViewControllerA you need to tell it about ViewControllerB so use an
import "ViewControllerB.h"
Then where you want to load the view eg. didSelectRowAtIndex or some IBAction you need to set the property in ViewControllerB before you push it onto nav stack.
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:#"ViewControllerB" bundle:nil];
viewControllerB.isSomethingEnabled = YES;
[self pushViewController:viewControllerB animated:YES];
This will set isSomethingEnabled in ViewControllerB to BOOL value YES.
It might be worth for all who read this article to mention working patterns passing variables between two views:
Options:
Use global variable: SO answer
Use delegation pattern: SO answer
Use notification infrastructure: article
Persist the value in app's userdefault storage, then read when you need : SO answer
For this particular situation it might be better not to create secondviewcontroller in the firstviewcontroller's viewdidload, but to keep the cellName until that point when a user action happens (eg. button press) and then in that method you just set the newly created secondviewcontroller's cellName2 property.
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"second" bundle:nil];
secondViewController.cellName = self.cellName;
I've tested and it is properly logging the value in secondviewcontroller's viewdidload.
Instead of doing: cellName = #"testy"; You should Call:
self.cellName = #"testy";
Also, When you alloc and init in:
SecondViewController *obj = [[SecondViewController alloc] init];,
the viewDidLoad() for secondViewController is called right at that time and you are initializing it's iVar later in the line obj.cellName2 = self.cellName;
That's why you are having NSLOG as null.
Print the NSLOG in viewWillAppear() of secondViewController and you will see the right value this time.
-Create a initialization method for second view controller to pass the variable..
in secondview controller
.h file
add init method
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil cellString(NSString* )cellName;
and .m file
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil cellString(NSString* )cellName{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
cellName2=cellName;
}
return self;
}
and in ViewController.m for initialization
SecondViewController *obj = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil cellString:self.cellName];
This should work...
Best of luck
In viewcontroller.m you have the following in viewDidLoad:
..
..
SecondViewController *obj = [[SecondViewController alloc] init];
obj.cellName2 = self.cellName;
}
The SecondViewController "obj" is never being presented before the end of viewDidLoad, hence NSLog printing null.
If you are wanting to pass a value to SecondViewController via a storyboard, you will need to use the prepareForSegue method. A good example of using it can be found here.

i am not able to pass value from one view controller to another view controller

hi i have problem that i am not able to pass value from one view controller to another view controller through button i implement when i click on button other view appear on iphone screen but the value which i have set not dispay this is the button code
-(IBAction)save:(id)sender
{
nextview *admin = [[nextview alloc]init];
[self presentModalViewController:admin animated:YES];
if (admin.view)
{
admin.fetchname = name.text;
}
[admin release];
}
and this is the nextview.h file
#import <UIKit/UIKit.h>
#interface nextview : UIViewController
{
UILabel *getname;
NSString *fetchname;
}
#property (nonatomic,retain) IBOutlet NSString *fetchname;
#property (nonatomic,retain) IBOutlet UILabel *getname;
#end
and this is the nextview.m file
#import "nextview.h"
#import "ViewController.h"
#implementation nextview
#synthesize getname,fetchname;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (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.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
getname.text = self.fetchname;
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
The viewDidLoad method is called before you had a chance to assign your NSString value.
That's why you dont see the text in your UIButton.
Try this :
-(IBAction)save:(id)sender
{
nextview *admin = [[nextview alloc] init];
admin.fetchname = name.text;
[self presentModalViewController:admin animated:YES];
[admin release];
}
-(IBAction)save:(id)sender
{
nextview *admin = [[nextview alloc]init];
[self presentModalViewController:admin animated:YES];
if (admin.view)
{
admin.fetchname = name.text;
}
[admin release];
}
You release the instance of nextview right after you assign the name. That can't even work.
By the way, getname and fetchname are really bad chosen names for properties.
You can do something like this.
You can implement the below code in nextView.h
NSString *fetchData;
also property and synthesize this
#property(nonatomic, retain) NSString *fetchData;
implement this on button pressed code
-(IBAction)save:(id)sender
{
nextview *admin = [[nextview alloc] init];
admin.fetchData = name.text;
[self presentModalViewController:admin animated:YES];
[admin release];
}

Help me to understand the answer given

I have problem with UIModalTransitionStylePartialCurl when i rotate the device beacuse the curl is not rotating as i expected and i found the below extract of the answer but i am not able to undertsand.
i am not sure how to create a "rootviewcontroller" Property as told like below
So i am looking for your guidence to proceed further .I am really stuck with this thing for long days...
Thanks for any help:-
The SOURCE CODE I HAVE
//
// ModalViewExampleViewController.h
// ModalViewExample
//
// Created by Tim Neill on 11/09/10.
//
#import <UIKit/UIKit.h>
#interface ModalViewExampleViewController : UIViewController {
UIButton *showDefaultButton, *showFlipButton, *showDissolveButton, *showCurlButton;
}
#property (nonatomic, retain) IBOutlet UIButton *showDefaultButton, *showFlipButton, *showDissolveButton, *showCurlButton;
- (IBAction)showDefault:(id)sender;
- (IBAction)showFlip:(id)sender;
- (IBAction)showDissolve:(id)sender;
- (IBAction)showCurl:(id)sender;
#end
//
// ModalViewExampleViewController.m
// ModalViewExample
//
// Created by Tim Neill on 11/09/10.
//
#import "ModalViewExampleViewController.h"
#import "SampleViewController.h"
#implementation ModalViewExampleViewController
#synthesize showDefaultButton, showFlipButton, showDissolveButton, showCurlButton;
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (IBAction)showDefault:(id)sender {
SampleViewController *sampleView = [[[SampleViewController alloc] init] autorelease];
[self presentModalViewController:sampleView animated:YES];
}
- (IBAction)showFlip:(id)sender {
SampleViewController *sampleView = [[[SampleViewController alloc] init] autorelease];
[sampleView setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:sampleView animated:YES];
}
- (IBAction)showDissolve:(id)sender {
SampleViewController *sampleView = [[[SampleViewController alloc] init] autorelease];
[sampleView setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self presentModalViewController:sampleView animated:YES];
}
- (IBAction)showCurl:(id)sender {
SampleViewController *sampleView = [[[SampleViewController alloc] init] autorelease];
sampleView.rootViewController = self;
[sampleView setModalTransitionStyle:UIModalTransitionStylePartialCurl];
[self presentModalViewController:sampleView animated:YES];
}
- (void)dealloc {
[showDefaultButton release];
[showFlipButton release];
[showDissolveButton release];
[showCurlButton release];
[super dealloc];
}
#end
//
// SampleViewController.h
// ModalViewExample
//
// Created by Tim Neill on 11/09/10.
//
#import <UIKit/UIKit.h>
#class RootViewController;
#interface SampleViewController : UIViewController {
RootViewController *rootViewController;
UIButton *dismissViewButton;
}
#property (nonatomic, retain) IBOutlet UIButton *dismissViewButton;
#property (nonatomic, retain) RootViewController *rootViewController;
- (IBAction)dismissView:(id)sender;
#end
//
// SampleViewController.m
// ModalViewExample
//
// Created by Tim Neill on 11/09/10.
//
#import "SampleViewController.h"
#implementation SampleViewController
#synthesize rootViewController;
#synthesize dismissViewButton;
- (IBAction)dismissView:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)dealloc {
[dismissViewButton release];
[super dealloc];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
[self dismissModalViewControllerAnimated:YES];
return YES;
}
#end
UIView Animation: PartialCurl ...bug during rotate?
I too had this issue and somewhat gave up. However, I mentioned my
dilemma to a friend, who encouraged me to look into the child VC's
logic and I recalled a handy trick that I've used to pass data between
parent/child view controllers.
In your flipside view controller, create a "rootViewController"
property. In your parent view controller, when you initialize the
flipside view controller, you set (where "self" is the rootVC):
flipsideController.rootViewController = self;
You then use this for your flipside VC's
shouldAutorotateToInterfaceOrientation method:
-
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{ return interfaceOrientation ==
self.rootViewController.interfaceOrientation;
}
Viola! The flipside view no longer rotates underneath the partially
curled up parent view!
#From the post : In your flipside view controller, create a "rootViewController" property.
#import <UIKit/UIKit.h>
#class ModalViewExampleViewController;
#interface flipSideViewController : UIViewController {
ModalViewExampleViewController *rootViewController;
}
#property (nonatomic, retain) ModalViewExampleViewController *rootViewController;
#end
and in your flipSideViewController's implementation file
#import "ModalViewExampleViewController.h"
#synthesize rootViewController;

Iphone : unrecognized selector sent to instance & viewDidLoad isn't running

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.

iphone app with multiple views/subviews: memory is not being deallocated

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.