I have a custom view class which is a subclass of UITableViewCell.
I have two other custom view classes which inherit from this subclass (they share a lot of the same properties but were different enough to warrant separate classes).
I've declared the shared properties in MyParentCell and also declared their unique properties in the respective classes.
UITableViewCell
|
|
MyParentCell // defines propertyA and propertyB, both IBOutlet subviews
/ \
/ \
/ \
| |
| ChildClass1 // defines propertyC, an IBOutlet subview
|
ChildClass2 // defines property D, an IBOutlet subview
My question is: Since I'm using ARC and cannot explicitly call [super delloc]; when I'm defining dealloc: in ChildClass1 and ChildClass2 do, I have to release all of the subviews they own in each class, or will MyParentCell#dealloc still be called too?
i.e.,
Do I have to write this:
// ChildClass1.m
#implementation ChildClass1
-(void)dealloc
{
self.propertyA = nil;
self.propertyB = nil;
self.propertyC = nil;
}
#end
// ChildClass2.m
#implementation ChildClass2
-(void)dealloc
{
self.propertyA = nil;
self.propertyB = nil;
self.propertyD = nil;
}
#end
Or is it enough to write:
// MyParentCell
#implementation MyParentCell
-(void)dealloc
{
self.propertyA = nil;
self.propertyB = nil;
}
#end
// ChildCell1.m
#implementation ChildCell1
-(void)dealloc
{
self.propertyC = nil;
}
#end
// ChildCell2.m
#implementation ChildCell2
-(void)dealloc
{
self.propertyD = nil;
}
#end
If the second approach is fine, can someone explain when and how MyParentCell#dealloc is called?
If the first approach is necessary, that sucks :/
Of course, also with ARC every class is responsible to clean up only its own resources. If you define a dealloc in a subclass, it's calling the parent's dealloc implicitly at the end of your method. You just don't have to type it.
If you just release instance variables or properties, you can rely on ARC to do this for you after the whole dealloc chain is done. ARC silently implements .cxx_destruct which gets called from NSObject's dealloc and takes care of releasing anything strong in your class.
No not need to use dealloc at all as a general rule(but in some cases), put ain dealloc an NSLog that shows just a dealloc word. Run and trust in ARC everything happen automatically
You don't have to do neither approach 1 nor approach 2. You don't need to implement dealloc at all. When an instance of your subclasses is deallocated, objects it retains will be released automatically. So if they are not retained somewhere else, they will be deallocated too.
Related
Is there any way to delegate to two objects at a time in Objective-C? I know that delegation pattern implies one response at a time and for multiple listeners and broadcasting there is notification center but notification does not return any value.
If I have a heavily network-based iOS project and need to delegate to multiple listeners and required to return values from them, in this scenario what approach should be the best?
In every class the delegate is one, so one delegate is informed about the event. But nothing forbids you to declare a class with a set of delegates.
Or use Observation instead. A class may be observed by multiple classes.
Example
As requested from the OP, since also some code would be useful, here is a way of doing it:
#interface YourClass()
#property (nonatomic, strong, readwrite) NSPointerArray* delegates;
// The user of the class shouldn't even know about this array
// It has to be initialized with the NSPointerFunctionsWeakMemory option so it doesn't retain objects
#end
#implementation YourClass
#synthesize delegates;
... // other methods, make sure to initialize the delegates set with alloc-initWithOptions:NSPointerFunctionsWeakMemory
- (void) addDelegate: (id<YourDelegateProtocol>) delegate
{
[delegates addPointer: delegate];
}
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
{
// Remove the pointer from the array
for(int i=0; i<delegates.count; i++) {
if(delegate == [delegates pointerAtIndex: i]) {
[delegates removePointerAtIndex: i];
break;
}
} // You may want to modify this code to throw an exception if no object is found inside the delegates array
}
#end
This is a very simple version, you can do it in another way. I don't suggest to make public the delegates set, you never know how it could be used, and you can get an inconsistent state, specially with multithreading. Also, when you add/remove a delegate you may need to run additional code, so that's why making the delegates set private.
You may also a lot of other methods like delegatesCount for example.
PS: The code has been edited to be a NSPointerArray instead of a NSMutableSet, because as stated in the comments a delegate should be held with a weak pointer to avoid retain cycles.
In addition to Ramys answer you could use a [NSHashTable weakObjectsHashTable] instead of a
NSMutableSet. This would keep only a weak reference to your delegates and prevents you from running into memory leaks.
You will get the same behavior you already know from standard weak delegates #property (nonatomic, weak) id delegate;
#interface YourClass()
#property (nonatomic, strong) NSHashTable *delegates;
#end
#implementation YourClass
- (instancetype)init
{
self = [super init];
if (self) {
_delegates = [NSHashTable weakObjectsHashTable];
}
return self;
}
- (void) addDelegate: (id<YourDelegateProtocol>) delegate
{
// Additional code
[_delegates addObject: delegate];
}
// calling this method is optional, because the hash table will automatically remove the delegate when it gets released
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
{
// Additional code
[_delegates removeObject: delegate];
}
#end
Robbie Hanson wrote a multicast delegate implementation. Looks like what you need. He talks about it in more detail here, and how it is used in the XMPPFramework. He has some good discussion about one of the main problems which is how to handle the case where the multiple delegates implement a given method who's return value determines the class' behaviour (and the multiple delegates return different values). Relevant bits:
What is a MulticastDelegate?
The xmpp framework needs to support an unlimited number of extensions.
This includes the official extensions that ship with the framework, as
well as any number of extensions or custom code you may want to plug
into the framework. So the traditional delegate pattern simply won't
work. XMPP modules and extensions need to be separated into their own
separate classes, yet each of these classes needs to receive delegate
methods. And the standard NSNotification architecture won't work
either because some of these delegates require a return variable.
(Plus it's really annoying to extract parameters from a notification's
userInfo dictionary.)
So a MulticastDelegate allows you to plug into the framework using the
standard delegate paradigm, but it allows multiple classes to receive
the same delegate notifications. The beauty of this is that you don't
have to put all your xmpp handling code in a single class. You can
separate your handling into multiple classes, or however you see fit.
If you're writing the function that will call the delegates, you can have as many as you want. But if you're using a class (that you can't change) that calls the delegates, then you can't have more delegates than the class supports.
You could, if it worked out for you, have one delegate call another. Set up the first delegate so it will call the second delegate (whose pointer is stored in the first delegate object). This can be simple, with it pre-defined as to which calls are "passed on", or quite complex, using the dynamic call mechanisms of Objective-C.
One delegate can be setting for only one object but it's possible to store delegates in array.
Variant of Ramy Al Zuhouri is good but I want to say that it may be a problem to release delegates from array because NSArray (like NSMutableArray) classes retain all added objects but delegate in most cases is an assign property without retainCount. Retaining the delegate can bring to consequences that class with delegate implementation will have retainCount + 1.
Solution of this is store delegates in NSMutableArray like pointers to delegate methods.
I'm using singletone class with delegate header.
//YourClass.h file
#protocol YourDelegateProtocol <NSObject>
-(void)delegateMethod;
#end
#interface YourClass : NSObject
+(YourClass *)sharedYourClass;
- (void) addDelegate: (id<YourDelegateProtocol>) delegate;
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
#end
//YourClass.m file
#interface YourClass()
#property (nonatomic, retain) NSMutableArray *delegates;
-(void)runAllDelegates;
#end
#implementation YourClass
#synthesize delegates = _delegates;
static YourClass *sharedYourClass = nil;
+(YourClass *)sharedYourClass {
if (!sharedYourClass || sharedYourClass == nil) {
sharedYourClass = [YourClass new];
sharedYourClass.delegates = [NSMutableArray array];
}
return sharedYourClass;
}
-(void)addDelegate: (id<YourDelegateProtocol>) delegate{
NSValue *pointerToDelegate = [NSValue valueWithPointer:delegate];
[_delegates addObject: pointerToDelegate];
}
-(void)removeDelegate: (id<YourDelegateProtocol>) delegate{
NSValue *pointerToDelegate = [NSValue valueWithPointer:delegate];
[_delegates removeObject: pointerToDelegate];
}
-(void)runAllDelegates{
//this method will run all delegates in array
for(NSValue *val in sharedYourClass.delegates){
id<YourDelegateProtocol> delegate = [val pointerValue];
[delegate delegateMethod];
}
}
-(void)dealloc{
sharedYourClass.delegates =nil;
[sharedYourClass release], sharedYourClass =nil;
[super dealloc];
}
#end
//YourClassWithDelegateImplementation.h file
#include "YourClass.h"
#interface YourClassWithDelegateImplementation : NSObject <YourDelegateProtocol>
#end
//YourClassWithDelegateImplementation.m file
#implementation YourClassWithDelegateImplementation
-(id)init{
self = [super init];
if(self){
//...your initialization code
[[YourClass sharedYourClass] addDelegate:self];
}
return self;
}
-(void)delegateMethod{
//implementation of delegate
}
-(void)dealloc{
[[YourClass sharedYourClass] removeDelegate:self];
[super dealloc];
}
#end
If you want to call callbacks for classes B and C from a class A with only one delegate, you could create a delegate wrapper DWrap which has references to the classes B and C. Then class A calls the callbacks on B and C through DWrap.
This is something I should have cleared up long ago, but I just need to know the best practice for deallocating in the following scenario.
In my header file I declare a reference to an IBOutlet as follows:
#interface Test : UIViewController {
UIButton *_loginBtn;
}
#property (nonatomic, retain) IBOutlet UIButton *loginBtn;
And in the implementation file I associate the instance variable to the property and deallocate as follows:
#implementation Test
#synthesize loginBtn = _loginBtn;
...
- (void) dealloc {
[_loginBtn release];
self.loginBtn = nil;
[super dealloc];
}
- (void) viewDidUnLoad {
[_loginBtn release];
self.loginBtn = nil;
[super viewDidUnLoad];
}
Am I correct in the deallocating the instance variable and setting the property to nil and doing this in both the viewDidUnLoad and dealloc methods?
There is no need for self.loginBtn = nil; in dealloc, the previous line released it. It is best not to use the property to release it in dealloc. The reason for releasing vs setting the property to nil is that the setter is a method call and the class is in the midst of tearing down and things may be unstable.
In viewDidUnLoad release any properties that are IBOutlets with self.theOutlet = nil;, in this case the _loginBtn release]; is not needed and redundant. Also release any other objects that you can easily re-create.
If properties are used they should be used for all accesses in the class with two exceptions: init and dealloc. In both of these cases the class is partially complete. In these two cases it is best to use the ivar directly in init (if necessary) and release in dealloc.
No, this is incorrect. By first releasing _loginBtn and then setting the property to nil, you release the instance twice. The correct way to do it is to release _loginBtn and then set _loginBtn to nil.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?
When creating a new project in Xcode 4, the boilerplate code adds an underscore character when it synthesizes the ivars in the implementation file as:
#synthesize window = _window;
or:
#synthesize managedObjectContext = __managedObjectContext;
Can someone tell me what is being accomplished here? I'm not a complete nube, but this is one aspect of objective-C I don't understand.
Another point of confusion; in the app delegate implementation, after synthesizing the window iVar as above, in the application didFinishLaunchingWithOptions: method the window and viewController ivars are referred to using self:
self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];
but in the dealloc method it's _window, or _viewController
Thanks
This is an artifact of a previous version of the Objective-C runtime.
Originally, #synthesize was used to create accessors methods, but the runtime still required that instance variables had to be instantiated explicitly:
#interface Foo : Bar {
Baz *_qux;
}
#property (retain) Baz *qux;
#end
#implementation Foo
#synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
#end
People would prefix their instance variables to differentiate them from their properties (even though Apple doesn't want you to use underscores, but that's a different matter). You synthesize the property to point at the instance variable. But the point is, _qux is an instance variable and self.qux (or [self qux]) is the message qux sent to object self.
We use the instance variable directly in -dealloc; using the accessor method instead would look like this (though I don't recommend it, for reasons I'll explain shortly):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
This has the effect of releasing qux, as well as zeroing out the reference. But this can have unfortunate side-effects:
You may end up firing some unexpected notifications. Other objects may be observing changes to qux, which are recorded when an accessor method is used to change it.
(Not everyone agrees on this point:) Zeroing out the pointer as the accessor does may hide logic errors in your program. If you are ever accessing an instance variable of an object after the object has been deallocated, you are doing something seriously wrong. Because of Objective-C's nil-messaging semantics, however, you'll never know, having used the accessor to set to nil. Had you released the instance variable directly and not zeroed-out the reference, accessing the deallocated object would have caused a loud EXC_BAD_ACCESS.
Later versions of the runtime added the ability to synthesize instance variables in addition to the accessor methods. With these versions of the runtime, the code above can be written omitting the instance variables:
#interface Foo : Bar
#property (retain) Baz *qux;
#end
#implementation Foo
#synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
#end
This actually synthesizes an instance variable on Foo called _qux, which is accessed by getter and setter messages -qux and -setQux:.
I recommend against this: it's a little messy, but there's one good reason to use the underscore; namely, to protect against accidentally direct ivar access. If you think you can trust yourself to remember whether you're using a raw instance variable or an accessor method, just do it like this instead:
#interface Foo : Bar
#property (retain) Baz *qux;
#end
#implementation Foo
#synthesize qux;
- (void)dealloc {
[qux release];
[super dealloc];
}
#end
Then, when you want to access the instance variable directly, just say qux (which translates to self->qux in C syntax for accessing a member from a pointer). When you want to use accessors methods (which will notify observers, and do other interesting things, and make things safer and easier with respect to memory management), use self.qux ([self qux]) and self.qux = blah; ([self setQux:blah]).
The sad thing here is that Apple's sample code and template code sucks. Never use it as a guide to proper Objective-C style, and certainly never use it as a guide to proper software architecture. :)
Here is another reason. Without underscoring instance variables you frequently obtain warning with the parameters self.title = title and self.rating = rating:
#implementation ScaryBugData
#synthesize title;
#synthesize rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // Warning. Local declaration hides instance variable
self.rating = rating; // Warning. Local declaration hides instance variable
}
return self;
}
#end
You avoid warning by underscoring instance variables:
#implementation ScaryBugData
#synthesize title = _title;
#synthesize rating = _rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // No warning
self.rating = rating; // No warning
}
return self;
}
#end
in the application didFinishLaunchingWithOptions: method the window and viewController ivars are referred to using self
No, they're not. Those are references to the properties window and viewController. That's the point of the underscore, to make it clearer when the property is being used (no underscore) and when the ivar is being accessed directly (with underscore).
Yes, Its is just to differentiate the reference of object. That is , if the object is referred directly use it with underscore, otherwise use self to refer the object.
I'm a objective c newbie, and i'm having a bit of problems with memory management, I've read the apple's memory management policies, however i need a bit of clarification here, this is pretty simple i guess, but i would like to ask you if I'm right:
Given this property:
#interface Test : NSObject {
NSArray *property1;
}
#property (nonatomic,retain) NSArray* property1;
#end
...
//And its implementation:
#implementation Test
#synthetize property1;
-(id) init {
if (self=[super init]) {
self.property1=[[[NSArray alloc] initWithCapacity:5] autorelease];
}
return self;
}
-(void) dealloc {
[super dealloc];
[property1 release];
}
#end
Is it right to issue an Autorelease message to the allocated object in the init method?, i do this cause in apple's document, says that every allocated object should be released by the developer, then, I think, alloc sets retain count to 1, then the property (nonatomic, retain) adds 1, so retain==2, then autorelease substracts 1, and when the dealloc method is called, property1 is released and retain count==0, am I right?
You have your memory management right, though Apple (and a lot of other people) generally recommend not using accessors in your initialization methods because accessors can have side effects beyond simply setting an instance variable that your class might not be set up to handle yet. And in that case, you wouldn't want to autorelease since you'd want ownership of the object.
one side note: in your dealloc, you need to release the property before calling [super dealloc], because [super dealloc] eventually deallocates the memory of the object, which includes the memory containing the property1 variable, so it is invalid to refer to that variable after you call [super dealloc]. It should be:
-(void) dealloc {
[property1 release];
[super dealloc];
}
One of the nice things about using properties is that you can encapsulate all of your "releasing" behavior regardless of whether your property is set to retain, copy, assign, or whatever by just doing this:
self.property1 = nil;
Personally I've gotten in the habit of setting all properties to nil (using self.property, not just accessing the member variable directly) in dealloc so that even if I change how the memory management works for the member variable it works correctly.
If class A is using class B and class A is class B's delegate, is it ok if the delegate is set to nil in class B's dealloc? I have seen code usually resetting the delegate to nil inside class A's dealloc but wasn't sure the real difference doing it one way or the other.
e.g. This is the usual way:
// somewhere in class A
- (void) someFunc {
self.b = [[B alloc] init];
self.b.delegate = self;
}
- (void) dealloc {
self.b.delegate = nil;
[self.b release];
}
Yes, you should set the classB's delegate property to nil in classA's dealloc.
It's not a memory management issue, because delegate properties should be marked assign, not retain, to avoid retain cycles (otherwise the dealloc will never be called). The issue is that otherwise classB might message classA after it has been released.
For example, if classB has a delagate call to say "being hidden", and classB is released just after classA, it would message the already dealloc'ed classA causing a crash.
And remember, you can't always guarentee the dealloc order, especial if they are autoreleased.
So yes, nil out the delegate property in classA's dealloc.
As far as I know, its best practice to (assign) a delegate, such that you avoid circular references on retain counts for situations just like this. If you've set up the property properly, ie:
#property (assign) id<BDelegate> delegate;
You shouldn't have to perform any memory management in the dealloc, as the retain count is not bumped when you call self.b.delegate = self; -- unlike using (retain) or (copy)
Make sense? It would be fine to set the delegate to nil, but whats the point?
First, a few observations...
You've forgotten to call [super dealloc] at the end of your own dealloc method.
Since 'a' created 'b', and if no other objects have retained 'b', there no point in nilling the delegate in the -dealloc, since 'b' is about to be destroyed anyhow. If it's possible that other objects have a reference to 'b' (meaning it might outlive 'a') then set the delegate to nil.
Object 'b' should be the one to take care of its delegate in its own -dealloc if necessary. (Generally, the delegator does not retain the delegate.)
Avoid using properties in -init... and -dealloc methods — Apple discourages this, and for good reason. (Not only could it have unexpected side effects, but can also cause nastier, crashier problems.)
Using properties (via the dot syntax) when you don't need to invisibly adds extra work. For instance, self.b.delegate = self is equivalent to [[self getB] setDelegate:self] — it's just syntactic sugar that makes it look like you're accessing the ivar directly, but you're actually not.
Using properties without understanding what they do can lead to trouble. If self.b retains the value (the property is set to "assign"), you have a memory leak on your hands.
Here's how I would probably write it:
- (void) someFunc {
b = [[B alloc] init];
b.delegate = self; // or [b setDelegate:self];
}
- (void) dealloc {
b.delegate = nil;
[b release];
[super dealloc];
}