Everything is in the title.
I would like to know when the dealloc method is called on UIViewController using ARC ?
In my app I have a navigation controller with multiple view controllers. When I dismiss my main navigation controller, the dealloc method is not getting call in any of my controllers ..
Thanks,
Dealloc is called on a UIViewController when the memory for that viewController is going to be deallocated from memory. If the dealloc method is not being called on your viewControllers when you expect it to be, you probably have a memory leak. It sounds like your view controllers may be retaining strong references to each other.
#property (nonatomic) UIViewController *otherController;
Change one side of the relationship to
#property (nonatomic, weak) UIViewController *otherController;
Related
I have some heavy processing tasks in my view controller, so I put them in a background thread using GCD. And the tasks are encapsulated in a class AsyncImageProcessor
#interface AsyncProcessor : NSObject
#property (weak, nonatomic) id<AsyncProcessorDelegate> delegate;
// ... other unrelated stuff
#end
#protocol AsyncProcessorDelegate <NSObject>
- (void) asyncProcessorEvent:(AsyncProcessorEventType) event;
#end
The problem is that the view controller implementing the delegate is dismissed right after the AsyncProsessor tasks dispatched. And by the time the processing is done, the view controller memory is released, delegate is nil. Then delegated event can't be passed back to the view controller.
One solution I can think of is to define the delegate "strong", and in the delegated method asyncProcessorEvent, set delegate to nil to break the memory circle after all the processing is done. But I feel this is a hack, and I was told everywhere the delegate should be defined as "weak".
Has someone had this issue before? Please give some suggestions.
I am having problems updating a view when a message from another class is sent to a ViewController.
Basically I have an application with a single window where different custom views will be swapped out for another. I have an AppController Class that manages this and works fine:
#interface AppController : NSObject
#property (weak) IBOutlet NSView *ourView;
#property (strong) NSViewController *ourViewController;
- (IBAction)changeView:(id)sender;
- (IBAction)start:(id)sender;
- (void)changeViewContoller:(NSInteger)tag;
#end
When a new view is swapped out for another, the ourViewController property will be updated to point to that view's controller class. Every view controller class will have a method all named the same thing, for example "action". This method is supposed to change something on a view.
So the "start" method in AppController class will then call the "action" method on the ourViewController property. To do this I used the objc_msgSend() method:
objc_msgSend(self.ourViewController, action);
Here's the View Controller class definition:
#interface CountdownViewController : NSViewController
#property (weak) IBOutlet NSTextField *label;
- (IBAction)changeLabel:(id)sender;
- (void)start;
#end
I placed an NSLog() in the "action" method for each ViewController, to see if it was working, and it does, however the "action" method is also supposed to change a label's string value, but it does not. If anyone knows why the view is not being updated, that would be extremely helpful. Thanks!
the view is held weak?
TRY making it strong if you need to retain that pointer in this class
btw: ..also why do you objc_msgsend.... use performSelector
If I have a view (mainView) in which I have added subViews. How do I get to subviews instance to mainView ?
I have a button in those subviews which when pressed should call a method in mainView, so I tried:
[myButton addTarget:self.presentingViewController
action:#selector(myMethod:)
forControlerEvents:UIControletcetc];
and
[myButton addTarget:self.parentViewController action:#selector....];
I read that parentViewController now returns nil in iOS 5, but presentingViewController doesn't seem the way to do it because its not presented modally. Its just a subview. Any hints?
Your question doesn't make it quite clear whether you are talking about views or view controllers. Use the superview property to access a view's parent.
There is generally no way to get from a view to its view controller.
It feels to me that you're trying to let your views know about objects beyond their scope.
If you need to notify about an event to anyone that included your view, you could use a delegate to do that.
Say:
#protocol YourClassDelegate
#optional
- (void)instanceOfYourClass:(YourClass *)instance tappedButton:(UIButton *)button;
#end
and then
#interface YourClass
#property (nonatomic, assign) id<YourClassDelegate> delegate;
#end
I hope you can take it from here, by synthesizing the property, assigning the delegate and calling the method when you need to.
When implementing the UITextFieldDelegate in my ViewController class, the following error is thrown when entering the first character in the text field:
-[MyViewController respondsToSelector:]: message sent to deallocated instance...
So, I tried creating a separate class (inheriting only NSObject) and implementing UITextFieldDelegate. Guess what, it worked perfectly. However, that introduces some other problems as I have to do a lot of ugly cross-class-communication that I'd like to avoid. Here's the relevant parts of my app delegate code:
#interface RMSAppDelegate : NSObject <UIApplicationDelegate,
UITabBarControllerDelegate>
#property (nonatomic, retain) UIViewController* myViewController;
#end
#implementation MyAppDelegate
#synthesize myViewController;
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
myViewController = [[MyViewController alloc]
initWithNibName:#"MyView" bundle:nil];
[self.window setRootViewController:myViewController];
[self.window makeKeyAndVisible];
return YES;
}
#end
.. and here's what is being displayed:
#interface MyViewController : UIViewController <UITextFieldDelegate>
#property (nonatomic, retain) IBOutlet UITextField* pinTextField;
- (void)viewDidLoad;
#end
#implementation MyViewController
#synthesize pinTextField;
- (void)viewDidLoad {
// DOES NOT WORK (WHY?)
//[pinTextField setDelegate:self];
// WORKS, BUT I'D LIKE TO AVOID
[pinTextField setDelegate:[[[MyTextFieldDelegate alloc] init] autorelease];
[pinTextField becomeFirstResponder];
[super viewDidLoad];
}
#end
And please, if you see any code (even off topic) that I could be doing better, leave a comment.
Since you asked for off-topic code comments: You forget to call [super viewDidLoad]. You also don't need to redeclare the prototype in order to override it. And the #synthesize textFieldDelegate is not valid, as you have no property in the class named textFieldDelegate. And your dealloc method is releasing an ivar named tfd which doesn't seem to actually exist in the class.
Your real problem is that you are not properly retaining the view controller at whatever point you allocate it. It may be that the view controller is being instantiated in a nib and associated with an ivar rather than a property declared retain, or is not being associated with anything. Or it could be that you are allocating it in code, adding its view as a subview of something, and then releasing it without ever retaining the view controller itself. Or it could just be that you are just releasing it when you shouldn't.
Your other class works specifically because you are leaking the object, so it never gets deallocated. The better solution, were you to go with this method, would be to store the object in an ivar when you allocate it and then release it (and set the ivar to nil) in both dealloc and viewDidUnload.
Okay, I finally solved this on my own. I have not changed the code. My NIB (.xib) was the culprit!
I thought that nested UIViewControllers was OK, and I still think they are in some cases (and maybe using another programmatic method). Anyway, I was initializing my class MyViewController with a NIB that in the Objects panel had a UIViewController as the first object.
I solved this by having the UIView as the first object in the Objects panel, and setting the File's Owner to be the UIViewController instead.
Correct code, incorrect NIB. Thank you for your help.
All,
In Apple's sample code "DateCell"
http://developer.apple.com/library/ios/#samplecode/DateCell/Introduction/Intro.html
the ivar "pickerView" is declared in MyTableViewController.h like this:
#interface MyTableViewController : UITableViewController
{
#private
UIDatePicker *pickerView;
UIBarButtonItem *doneButton; // this button appears only when the date picker is open
NSArray *dataArray;
NSDateFormatter *dateFormatter;
}
#property (nonatomic, retain) IBOutlet UIDatePicker *pickerView;
...
It is synthesized in the class file MyTableViewController.m like this:
#implementation MyTableViewController
#synthesize pickerView, doneButton, dataArray, dateFormatter;
...
When this app runs, I can insert NSLog(#"%#",pickerView) into ViewDidLoad and see that, sure enough, the ivar pickerView is real and has a value. Nowhere, though, does this class alloc/init pickerView. And that's the root of the question: how's it getting done if it's not being done explicitly?
Well, I naively copied this stuff to my code into my RootViewController.h and .m files figuring I could do the same, but pickerView stubbornly remains uninitialized (and my NSLog calls return "(nil)" as its value) no matter what I try short of explicitly alloc/initing it. Certainly RootViewController is being instantiated, or the RootView wouldn't be showing up, right? So shouldn't my pickerView be coming along for the ride just as it does for Apple?
So... do I have to manually alloc/init the pickerView instance variable? If so, where's Apple doing it? Or how are they doing it somehow otherwise?
I think I'm missing something very basic here, but I have no idea what it is. I can't see anything in Interface Builder or XCode that looks different between mine and theirs, but I've got tunnel vision at this point and can't see anything clearly anymore.
Thanks,
Bill
The IBOutlet modifier on this line is the key...
#property (nonatomic, retain) IBOutlet UIDatePicker *pickerView;
IBOutlet is a decorator that indicates that the object will be hooked up/connected/initialised when the corresponding xib (Interface Builder) file is loaded. The sample application you're looking up will contain a UITableViewController is a xib which has a connection to a UIPickerView.
You can either go the route of creating your own custom xib file and wire to an instance of UIPickerView or you can manually initialise the picker yourself.
Interface Builder (nib or xib) treats automatically IBOutlet ivar with connection of components.
IBOutlet is a special keyword that is
used only to tell Interface Builder to
treat an instance variable or property
as an outlet. It’s actually defined as
nothing so it has no effect at compile
time.
Your First iOS Application - The
View Controller Interface
Declaration, Making Connections
Interface Builder User Guide -
Defining Outlets and Actions in
Xcode