I have a tableview(being IBOutlet) and tableviewController in my ViewController
what I do is
//.... allocation for tableviewController
self.tableview.delegate = tableviewController;
//now this increases the retain count of tableviewController...
So in deallocation do I need to set the tableview delegate to nil...like
self.tableview.delegate = nil;
or
self.tableview = nil; // is sufficient to make sure that the retain count of tableviewController get decreased by 1.
The tableView already realeases its delegate in its dealloc method, so you should be ok without having to explicitly set the delegate to nil.
The table view does not retain its delegate:
#property(nonatomic, assign) id<UITableViewDelegate> delegate
The reason is that retaining would likely cause a retain cycle. See Avoiding retain cycles rule #3: "Connection" objects should not retain their target.
To keep the delegate alive, you must maintain a reference to it yourself somewhere.
Related
With ARC enabled I have a property
#property (strong, nonatomic) NSMutableArray *arr;
I Allocate it as
self.arr = [NSMutableArray array];
I have a custom object ERSearchView, I allocate it and add it to the arr
ERSearchView *SV = [[ERSearchView alloc] initWithDelegate:nil];
[arr addObject:SV];
In my search view I have overridden the dealloc method, because it seems that the search view isn't getting released:
- (void)dealloc {
self.delegate = nil;
NSLog(#"deallocated search view");
}
This isn't getting called when I pop my view controller. But if I nil the arr variable in the view controller's dealloc I see the log message that the search view has been deleted.
Can anyone explain how is this possible that objects inside arr aren't getting released though the view controller is 100% released since I have "did dealloc" message in its dealloc?
Foundation collection classes such as NSArray, NSDictionary, etc. retain (or have a strong reference to, in ARC-speak) the objects they contain. So as long as the array hasn't been deallocated, the objects it refers to, including your view instance, should still be in memory.
It sounds as though you were leaking the array previously by not setting the property to nil in the controller's dealloc method. When an object declares a property as strong, it's responsible for the nilling the reference in its dealloc implementation to avoid this kind of leak.
I have a problem with ARC. After few hours of debugging I gave up and decided to check here.
Basically I have a MainViewController, which creates instance of PreviewsView.
In PreviewsView I have delegate and dataSource properties:
#property (nonatomic, unsafe_unretained) IBOutlet id<PreviewsDataSource> dataSource;
#property (nonatomic, unsafe_unretained) IBOutlet id<PreviewsDelegate> delegate;
I create instance of PreviewsView in MainViewController, set self as delegate and dataSource, add it to view and save as an instance variable:
- (void)addPreviews {
previewsView = [[PreviewsView alloc] initWithFrame:CGRectMake(0, 75, 1024, 480)];
previewsView.dataSource = self;
previewsView.delegate = self;
[self.view addSubview:previewsView];
}
Then when I remove MainViewController from navigation controller ACR deallocates is, BUT previewsView is still exist (WHY???) and actually running the method which triggers [self.delegate doSomeStuff]. As MainViewController already deallocates - it throws EXC_BAD_ACCESS.
So basically:
Instance of MainViewController owns instance of PreviewsView (previewsView)
Instance of MainViewController assigned as delegate and dataSource in PreviewsView
After deallocation instance of MainViewController, previewsView is still alive and running.
Any ideas why??
Thanks.
you need to set your delegates to nil, before releasing MainViewController like so
previewsView.delegate = nil;
previewsView.dataSource = nil;
Preferable call this code in dealloc method of you MainViewController -> you still can use it also with ARC like this
- (void) dealloc
{
previewsView.dataSource = nil;
previewsView.delegate = nil;
[super dealloc];
}
You should keep in mind that the protocols !assumes! your instance of previewsView is still "alive" ( notifications works the same way ) and try to send messages to your instance whether it's dead or alive . So when MainViewController is realeased, also previewsView is, but the delegates are still "alive". Therefore you need to undelegate them by setting them to nil;)
unsafe_unretained does not nil an ivar. __weak does.
Does the MainViewController member previewsView retain it? In viewDidUnload or after you have finished with previewsView, set it to nil, ie: previewsView = nil.
Generally all IBOutlets or subviews held as ivars should be __weak. If you don't need the previewsView after adding it as a subview you can remove the ivar.
Hope this helps!
I have several NSFetchedResultsControllers throughout my app, and in every view controller, I implement the respective delegate methods. However, instead of copying these delegate methods into every class that implements an NSFetchedResultsController, I thought I would just create a class that implements these delegate methods, and set all fetched results controller's delegate to point to that one class. Here's what I've tried, which doesn't work:
Since the delegate methods need to know which table view they are making changes to, I thought I would just create a separate delegate class for each fetched results controller, and send a pointer to the tableview for that class:
FetchedResultsDelegate *delegate = [[FetchedResultsDelegate alloc] initWithTableView:parentTableView];
self.fetchedResultsController.delegate=delegate;
[delegate release];
However, this causes a BAD_ACCESS crash, so this means that I probably shouldn't be doing what I'm doing above.
How can I create a single delegate class that handles all delegate requests for all my NSFetchedResultsControllers?
Edit: I was able to fix the problem by doing #property (nonatomic, retain) FetchedResultsDelegate *delegate; Is this ok? Some people are saying something about assign rather than retain?
Nothing is retaining your FetchedResultsDelegate as delegate properties are normally declared as assign. e.g. NSFetchedResultsController declares the delegate as
#property(nonatomic, assign) id <NSFetchedResultsControllerDelegate> delegate
Therefore you created the object and destroyed it straight away, but gave the fetchedResultsController a nasty dangling pointer.
To fix this you need a retain on the delegate. So in your UITableViewController class add a new property
// .h
#property (nonatomic, strong) id<NSFetchedResultsControllerDelegate> tableViewDelegate;
// .m
#synthesize tableViewDelegate = _tableViewDelegate;
then when you hook up you delegate just change your code to this
FetchedResultsDelegate *delegate = [[FetchedResultsDelegate alloc] initWithTableView:parentTableView];
self.fetchedResultsController.delegate = delegate;
self.tableViewDelegate = delegate;
[delegate release]; delegate = nil;
Don't forget
Release this new ivar in the dealloc
- (void)dealloc;
{
// ... other releases
[_tableViewDelegate release];
[super dealloc];
}
The use of assign is all about ownership semantics.
In this case your UITableViewController should own the tableView's delegate (e.g. strong/retain) as nothing else is.
The reason that the NSFetchedResultsController uses assign and not retain/strong is because there is a good chance that the object that created it would act as the delegate, which would result in both objects owning each other (both having a retain held on each other), which causes a retain cycle
I've been reading all day about why views should be set to nil in viewDidUnload and released in dealloc. All the articles keep on repeating the same thing. Yes, I know the behind-the-scene instructions are different, but what are the practical differences?
var = nil
If var is a retained propery, reclaim memory the old object var pointed to.
Set var to nil.
[var release]
Reclaim memory var points to.
var now points to nothing, which is equivalent to nil
To me, both ways of reclaiming memory have the same end result. So why do one over the other? Every book out there tells me to set to nil in viewDidUnload and release in dealloc. Someone should point out the bad things that would happen if a view was released in viewDidUnload and nilled in dealloc.
.h
#import <UIKit/UIKit.h>
#interface DisclosureDetailController : UIViewController {
UILabel* label;
}
#property (nonatomic, retain) IBOutlet UILabel* label;
#end
.m
#import "DisclosureDetailController.h"
#implementation DisclosureDetailController
#synthesize label;
- (void)viewDidUnload {
self.label = nil;
// OR [self.label release];
[super viewDidUnload];
}
- (void)dealloc {
[self.label release];
// OR self.label = nil;
}
First things first, the line
[self.label release];
is absolutely wrong regardless of where you call it. You should never call -release on the results of property access. This is exactly the same as writing [[self label] release], which I hope you can recognize as being wrong.
Your code sample should look like the following:
- (void)viewDidUnload {
self.label = nil;
[super viewDidUnload];
}
- (void)dealloc {
[label release];
[super dealloc];
}
If we look at -viewDidUnload first, it's pretty simple. self.label = nil; is correct. Similarly correct would be [self setLabel:nil];. And while not quite as good, it would also be acceptable to write [label release], label = nil;. This last form isn't as good because it bypasses the setter method, which may be doing more things than simply releasing the property (e.g. it may maintain internal state that cares about the value of the property). It also bypasses KVO notifications.
The real question here is what you do in -dealloc. Many people suggest that it's perfectly fine to say self.label = nil;, and practically speaking, this will work most of the time. The problem is, the rest of the time it will cause subtle bugs. There are two things that calling the setter can do. The first is it can cause side effects in your class if the setter method is implemented manually (even if you're not implementing the setter yourself, a subclass might). The second is it can broadcast KVO notifications. Neither of these things are desired when you're in -dealloc. By releasing the ivar directly, as in [label release];, you avoid both the potential side effects and the KVO notifications.
the practical differences are as follows.
Setting the property to nil by using the property accessor will let the synthesized method take hold of your new nil property after releasing the existing property.
// we will take for granted that you synthesize this property
#property (nonatomic, retain) IBOutlet UILabel* label;
we will use the property accessor and set it to nil.
//This will in actuality set the new value of nil to the label variable after
//releasing the existing label that it had a retain count on.
self.label = nil;
next we will release it directly
//This line on the other hand will merely release the label directly.
//As soon as the label is deallocated you will have a handle to an invalid object.
//(memory space that used to be your label)
[label release];
now we will show a simplified version of the property accessor. (not to be used literally)
//Simply put the following is an pseudo equivalent of the property setter.
[label release]
label = nil;
the main point here being that the property accessor handles releasing the label that it retained. and setting it to whatever you hand it (in this case being nil)
therefore adding the following code
label = nil;
without releasing the retained object would cause a memory leak and you would have a retain count on a label you no longer have a pointer to.
Note:
another thing to take into account.
Any pointer that is nil. will be able
to accept messages. And in return they
will reply with nil. An object that
was released on the other hand, as
soon as that memory is deallocated
your message to it will most likely
throw an error. the outcome is
unpredictable. This is a good reason
for setting your properties to nil.
Not only will it handle the release
for the object that it is holding. but
it will also give you an object you
can safely message to without blowing
up.
A good point #WaltSellers
Accessing a variable -- regardless if its the property accessor or instance variable. -- After it has been released completely. Will result in "Undefined" actions. This means that the access may act ok, or it may ruin other parts of the app, or alternatively it may just blow up real fast and terminate the offending app. Basically setting the variable to nil after releasing will enable you to get past that error.
A separate tip from me
to overcome the misconception of property accessor and instance variable I just #synthesize and tell it to set a variable name.
#synthesize label = _label;
doing this allows me to differentiate self.label from its instance variable. as no longer can you access the label variable directly without the preceding _
I've defined a view controller with an array as one of its properties, and set the array with an allocated and autoreleased array.
After I push the view for display I release it.
By watching the leaks tool I see that every time that I pop the view I suffer from leakage.
I tried to release the properties explicitly, immediately after the push but the app crashes.
looking forward for your suggestions.
The leak is probably because of the array property is set to retain, like so:
#property (nonatomic, retain) NSArray *yourArray;
Your autorelease object is retained on assignment to the yourArray property. Since it is retained, you have to release it in the controller's dealloc method:
- (void) dealloc {
[yourArray release], yourArray = nil;
[super dealloc];
}
HTH.