can we override alloc and dealloc in objective C? - objective-c

I know that this is rarely required to override the alloc or dealloc methods,but if required is it possible in iPhone programming?

You can and indeed, you should (if using manual memory management) override dealloc to release any resources you hold (not forgetting to call [super dealloc] when finished). Overriding alloc is possible but, as you say, rarely needed.

In general, overriding alloc is only done when you wish to, eg, allocate an object from a pool of available instances, or perhaps allocate a variable amount of storage for the object based on some external parameter. (In C++ you can access the new parameters and allocate based on them, but Objective-C does not give you access to the initXXX parameters.)
I've never attempted any of this, and I suspect that its a bit of a minefield -- you need to study up on the structures and be pretty careful.
As Adam said, you should ALWAYS (in a reference counted environment) override dealloc if there are any retained objects held by your object.
Update: An interesting thing you can do ... in RedClass or a superclass of it code something like:
+(id)alloc {
if (self == [RedClass class]) {
return [BlueClass alloc];
}
else {
return [super alloc];
}
}
The net result is that whenever you execute [RedClass alloc] a BlueCLass object will be returned. (NB: Presumably BlueClass is a subclass of RedClass, or things will get seriously mucked up shortly after the object is returned.)
Not saying that it's a good idea to do this, but it's possible (and I don't offhand know of any cases where it wouldn't work reliably for vanilla user-defined classes). And it does have a few possible uses.
Additional note: In some cases one might want to use [self isSubclassOf:[RedClass class]] rather than == (though that has some serious pitfalls).

Related

Destroying self from within self

I have an Objective-C class whose instances can detect when they are no longer needed and destroy themselves, but I am looking for a safe way to trigger an object's self-destruction from within the object itself, without somehow "destroying the method that is calling the destruction"... My code looks roughly like this (some removed for brevity):
+ (oneway void)destroyInstance:(id)obj {
printf("Destroying.\n");
if (obj != nil) {
free(obj);
obj = nil;
}
}
- (oneway void)release {
_noLongerRequired = [self determineIfNeeded]; // BOOL retVal
if (_noLongerRequired) {
[self deallocateMemory]; // Free ivars etc (NOT oneway)
[MyClass destroyInstance:self]; // Oneway
}
}
If I call -release, it should return instantly to the main thread (due to the oneway).
Meanwhile, if the instance finds it is no longer needed, it should then call the oneway class method destroyInstance: and remove itself from the runtime. My question is, is this safe?? And have I used oneway correctly? It seems to me there is the possibility of destroying the instance's -release function before it returns, which could be... rather bad..?
(PS: Obviously not looking for anything to do with NSObject, etc :))
This is without a doubt a terrible idea if you want working and maintainable software and unsafe in just about any context. But sometimes terrible, unsafe ideas can be fun on the weekend, so I'll answer the components of the question I can discern.
A method will not get "destroyed" because an instance is deallocated. What can happen is that self can end up pointing to deallocated memory during the execution of a method, which means that accessing self or any instance variables during this time can crash.
As to the rest of your code, there is no reason at all to set obj equal to nil in +destroyInstance, so if you were trying accomplish something in particular (nil'ing out pointers to the object perhaps) that way is not the right way to go about it.
Thinking about the use of oneway, what the language says is that sending this message won't block the calling thread. In the context of releasing objects I think it makes some sense, as presumably the target of the message won't ever be referenced by that thread again. By that logic I'd think your declaration of +destroyInstance is maybe OK. I do wonder if you'd need to provide some sort of synchronization so that there's no retain/release race conditions but thinking about it, taking ownership of an object should probably never be asynchronous.
My personal opinion is that anyone who puts this code into production should probably be fired or sued =P. But if it's only for educational purposes, have fun, and hope this helps.

Why does ARC retain method arguments?

When compiling with ARC, method arguments often appear to be retained at the beginning of the method and released at the end. This retain/release pair seems superfluous, and contradicts the idea that ARC "produces the code you would have written anyway". Nobody in those dark, pre-ARC days performed an extra retain/release on all method arguments just to be on the safe side, did they?
Consider:
#interface Test : NSObject
#end
#implementation Test
- (void)testARC:(NSString *)s
{
[s length]; // no extra retain/release here.
}
- (void)testARC2:(NSString *)s
{
// ARC inserts [s retain]
[s length];
[s length];
// ARC inserts [s release]
}
- (void)testARC3:(__unsafe_unretained NSString *)s
{
// no retain -- we used __unsafe_unretained
[s length];
[s length];
// no release -- we used __unsafe_unretained
}
#end
When compiled with Xcode 4.3.2 in release mode, the assembly (such that I'm able to understand it) contained calls to objc_retain and objc_release at the start and end of the second method. What's going on?
This is not a huge problem, but this extra retain/release traffic does show up when using Instruments to profile performance-sensitive code. It seems you can decorate method arguments with __unsafe_unretained to avoid this extra retain/release, as I've done in the third example, but doing so feels quite disgusting.
See this reply from the Objc-language mailing list:
When the compiler doesn't know anything about the
memory management behavior of a function or method (and this happens a
lot), then the compiler must assume:
1) That the function or method might completely rearrange or replace
the entire object graph of the application (it probably won't, but it
could). 2) That the caller might be manual reference counted code, and
therefore the lifetime of passed in parameters is not realistically
knowable.
Given #1 and #2; and given that ARC must never allow an object to be
prematurely deallocated, then these two assumptions force the compiler
to retain passed in objects more often than not.
I think that the main problem is that your method’s body might lead to the arguments being released, so that ARC has to act defensively and retain them:
- (void) processItems
{
[self setItems:[NSArray arrayWithObject:[NSNumber numberWithInt:0]]];
[self doSomethingSillyWith:[items lastObject]];
}
- (void) doSomethingSillyWith: (id) foo
{
[self setItems:nil];
NSLog(#"%#", foo); // if ARC did not retain foo, you could be in trouble
}
That might also be the reason that you don’t see the extra retain when there’s just a single call in your method.
Passing as a parameter does not, in general, increase the retain count. However, if you're passing it to something like NSThread, it is specifically documented that it will retain the parameter for the new thread.
So without an example of how you're intending to start this new thread, I can't give a definitive answer. In general, though, you should be fine.
Even the answer of soul is correct, it is a bit deeper than it should be:
It is retained, because the passed reference is assigned to a strong variable, the parameter variable. This and only this is the reason for the retain/release pair. (Set the parameter var to __weak and what happens?)
One could optimize it away? It would be like optimizing every retain/release pairs on local variables away, because parameters are local variables. This can be done, if the compiler understands the hole code inside the method including all messages sent and functions calls. This can be applied that rarely that clang even does not try to do it. (Imagine that the arg points to a person (only) belonging to a group and the group is dealloc'd: the person would be dealloc'd, too.)
And yes, not to retain args in MRC was a kind of dangerous, but typically developers know their code that good, that they optimized the retain/release away without thinking about it.
It will not increment behind the scenes. Under ARC if the object is Strong it will simply remain alive until there are no more strong pointers to it. But this really has nothing to do with the object being passed as a parameter or not.

what is difference between alloc and allocWithZone:?

From forum discussion , seem like that the big difference is performance factor, allocWithZone: will alloc memory from particular memory area, which reduce cost of swapping.
In practice, almost get no chance to use allocWithZone: , anyone can give simple example to illustrate which case to use allocWithZone: ?
Thanks,
When one object creates another, it’s
sometimes a good idea to make sure
they’re both allocated from the same
region of memory. The zone method
(declared in the NSObject protocol)
can be used for this purpose; it
returns the zone where the receiver is
located.
This suggests to me that your ivars, and any objects your classes "create" themselves could make use of +allocWithZone: in this way, to make the instances they create in the same zone.
-(id)init {
if (self = [super init]) {
someIvar = [[SomeOtherClass allocWithZone:[self zone]] init];
}
return self;
}
From Apple's documentation:
This method exists for historical reasons; memory zones are no longer
used by Objective-C.
A good example for using allocWithZone: is when you are implementing the NSCopy protocol, which allows you make your custom objects copyable (deep copy / copy by value) like:
(1) ClassName *newObject = [currentObject copy]; //results in newObject being a copy of currentObject not just a reference to it
The NSCopy protocol ensures you implement a method:
(2) -(id)copyWithZone:(NSZone *)zone;
When copying an object the 'copy' message you send as above (1) when stated as 'copyWithZone sends a message to the method(2). aka you don't have to do anything to get a zone yourself.
Now as you have a 'zone' sent to this message you can use it to ensure a copy is made from memory in the same region as the original.
This can be used like:
-(id)copyWithZone:(NSZone *)zone
{
newCopy = [[[self class]allocWithZone:zone]init]; //gets the class of this object then allocates a new object close to this one and initialises it before returning
return(newCopy);
}
This is the only place I am aware allocWithZone is actually used.
I use allocWithZone in singleton. As Forrest mentioned, the variables created allocated from the same region of memory. Thus other classes can use or access them from the same zone of memory. Save memory space when you run your app.
In the Foundation Functions Reference, all of the Zone functions are now prefaced with the below warning that Zones will be ignored.
Zones are ignored on iOS and 64-bit runtime on OS X. You should not use zones in current development.
NSCreateZone
NSRecycleZone
NSSetZoneName
NSZoneCalloc
NSZoneFree
NSZoneFromPointer
NSZoneMalloc
NSZoneName
NSZoneRealloc
NSDefaultMallocZone
Even if the Apple's Documentation indicates that allocWithZone:
exists for historical reasons; memory zones are no longer used by Objective-C. You should not override this method.
and
Zones are ignored on iOS and 64-bit runtime on OS X. You should not use zones in current development.
in reality I overridden it in an Objective-C class (in a full Objective-C project) and the method is called when I do [[Mylass alloc] init] even if the build is running on an iPhone 6s.
But I think it's better to follow the documentation and override alloc method instead of this one because alloc can certainly do the same job.

Three Objective-C constructor questions

I have three quick questions I've seen conflicting answers to that hopefully someone can clear up.
Does [super init] need to be done all the way down to NSObject? (e.g if Foo inherits from NSObject, should Foo call [super init]? If not, does that hold for dealloc too?
Does any form of default-initialization occur for member variables in an object. E.g would an NSString* member be initialized to nil? float to 0.0?
If my object has an initFoo method, can I call [self init] within that function to perform common initialization?
Since starting with Objective-C I've pretty much assumed Yes for the first and No for the second two, but I'm hoping to save some typing :)
Thanks,
Just to add a little more to the three replies ahead of me:
Yes it does. In practice NSObject (probably) doesn't require it (now), but if that ever changed you're screwed if you haven't. It's best to get into the habit anyway (or use the code generation in XCode to drop an init template down). That said it's not always init that you should call (more soon).
As has been noted initialisation to defaults (by virtue of memcpy 0s, so 0, nil, etc) is guaranteed and it's reasonably idiomatic to rely on this. Some people still prefer to be explicit and that's fine.
Absolutely. Remember init, or any variation is just a normal method. It's only an initialiser by convention (albeit a very strong convention). You are free to call other methods, including other initialisers. Again, by convention, you should decide on a "designated initializer" and have all other initialisers call this. Think about this in relation to your first question. If you subclass, what will your subclass call? By default a subclass author will call your init - so if you have a different designated initializer then it is very important that you make that clear so subclass authors know to call it.
You can read more (authoritative) detail here in the Apple docs.
You always need to call the initialization method of the superclass and assign self to the result. You also definitely need to call super's implementation at the end of your implementation of -dealloc.
All instance variables are initialized to zero/nil by default, this is guaranteed.
Yes, you can call [self init] from a more specific initialization method:
- (id)initFoo
{
self=[self init];
if(self)
{
//do stuff
}
return self;
}
yes for init (not technically required, but best practice) definitely yes for dealloc
yes, all memory is initialized to 0 which is nil, 0.0, etc.
yes, and this is common
Yes, Otherwise the superclass objects wont get a chance to do their initialization.
don't know.
Yes. Create whatever init method you want. Document it. But be sure to call the super's proper init method: whatever it may be.

is it good form to release self in an init method when that method allocates and returns something else?

In my code, I have something that looks like this:
#implementation MyClass
- (id) initWithType:(NSInteger)type {
[self release];
if (type == 0) {
self = [[MyClassSubclass1 alloc] init];
} else {
self = [[MyClassSubclass2 alloc] init];
}
return self;
}
//...
#end
which I think handles any potential memory leaks. However, I have seen code out there that does something similar, except it doesn't release self before reassigning it to another newly allocated instance. Is it not necessary to release self here or is the other code I've seen incorrect?
Your code looks technically correct, from a memory management perspective. Replacing self with a different alloc'd object loses the pointer to the original object, and nobody else will be able to release it, which would cause a leak. Try commenting out the release call and run it with Leaks in Instruments.
Just be cautious about opening this particular can of worms — Foundation.framework (part of Cocoa) uses class clusters for collections and strings, but doing so is a fairly advanced concept. A better approach might be to have a class method for each subclass, using the AbstractFactory pattern.
In any case, determining the subclass type based on an integer is a bad idea — any change in mapping from type to class will break dependent code. If you're going that way, why not just pass in the class object itself?
This looks like poor use of object-oriented design.
If you're creating a different instance depending on a type variable, then why don't you have subclasses for those types?
It would be much cleaner to define a base class with all the common functionality, and a subclass for each "type" variation.
What does the class do? We might be able to point you in the right direction.
Code-wise, your example code is correct, but it's generally bad practice to replace the instance with a different instance. Unless the init method is a factory method re-using instances or a singleton initializer, avoid releasing self en-lieu of another instance.