Nested factory methods in Objective-C - iphone

What's the best way to handle memory management with nested factory methods, such as in the following example?
#interface MyClass : NSObject {
int _arg;
}
+ (MyClass *) SpecialCase1;
+ (MyClass *) SpecialCase2;
+ (MyClass *) myClassWithArg:(int)arg;
- (id) initWithArg:(int)arg;
#property (nonatomic, assign) int arg;
#end
#implementation MyClass
#synthesize arg = _arg;
+ (MyClass *) SpecialCase1
{
return [MyClass myClassWithArg:1];
}
+ (MyClass *) SpecialCase2
{
return [MyClass myClassWithArg:2];
}
+ (MyClass *) myClassWithArg:(int)arg
{
MyClass *instance = [[[MyClass alloc] initWithArg:arg] autorelease];
return instance;
}
- (id) initWithArg:(int)arg
{
self = [super init];
if (nil != self) {
self.arg = arg;
}
return self;
}
#end
The problem here (I think) is that the autorelease pool is flushed before the SpecialCaseN methods return to their callers [Edit: apparently not - see comments below]. Hence, the ultimate caller of SpecialCaseN can't rely on the result having been retained. (I get "[MyClass copyWithZone:]: unrecognized selector sent to instance 0x100110250" on trying to assign the result of [MyClass SpecialCase1] to a property on another object.)
The reason for wanting the SpecialCaseN factory methods is that in my actual project, there are multiple parameters required to initialize the instance and I have a pre-defined list of "model" instances that I'd like to be able to create easily.
I'm sure there's a better approach than this.
[Edit: #interface added per request.]

Why do you think the autorelease pool is being flushed?
The autorelease pool is not flushed in cocoa-touch unless either you flush it, or control is returned back to the event loop.
From the iPhone Memory Management Guide
The Application Kit automatically
creates a pool at the beginning of an
event cycle (or event-loop iteration),
such as a mouse down event, and
releases it at the end, so your code
normally does not have to worry about
them.

The error describes the problem exactly: copyWithZone is called and it's not implemented in MyClass. Check out the attributes or the implementation of the property it's assigned to (see if it's copying). Also, copyWithZone will be called if the instance of MyClass is used as a key to an NSDictionary. Here's some info on implementing copyWithZone.

Related

Calling [[super allocWithZone:nil] init], messaging mechanism

f. e. (just for understanding messages mechanism more clear) I have class
MyClass.h
#interface MyClass : NSObject {
int ivar1;
int ivar2;
}
+ (id)instance;
#end
MyClass.m
static MyClass* volatile _sInstance = nil;
#implementation MyClass
+ (id)instance {
if (!_sInstance) {
#synchronized(self) {
if (!_sInstance) {
_sInstance = [[super allocWithZone:nil] init];
}
}
}
return _sInstance;
}
#end
What will be send in objc_msgSend in fact when calling [super allocWithZone:nil] ?
objc_msgSend([MyClass class], "allocWithZone", nil) or objc_msgSend([NSObject class], "allocWithZone", nil) ?
In practice I think that called objc_msgSend(self, "allocWithZone", nil) and in that case self == [MyClass class];
I want to be sure that memory for ivar1 and ivar2 will be allocated.
Is it true, that when we call super in class method, in objc_msgSend() function the "self" argument is passed, that in our case is class object of child? And allocWithZone will "look" at the child class object to see how much memory should be allocated for ivar1 and ivar2.
Thanks!
Any message to super is translated by the compiler to objc_msgSendSuper (not objc_msgSend). The first argument is a pointer to a struct. The struct contains a pointer to the super class of the current implementation and the a pointer to the receiver. The former is needed during runtime to search for the overridden implementation, the latter is used as the first argument.
In the case of a class method the receiver is again a class pointer, yet not the same as the super_class. In your case the receiver is a MyClass pointer while the super_class pointer would be NSObject.
Two side notes: I recommend against putting energy in writing the fanciest Singleton. Better leave it up to the developer to create his own instances or use the provided shared instance. And please note that double-checked locking is broken.

Properties in Objective c. copy and retain

What I have read from the apple document retain will increase the retain count by 1 , and release will decrease by 1. This is very much clear to me.
But In the case of copy and retain i am a bit confused.
Let me explain with the code i am trying.
property ---
#property(nonatomic, retain) NSMutableString *a;
#property(nonatomic, copy) NSMutableString *b;
#synthesize a = _a ,b = _b
a=[[NSMutableString alloc]initWithString:#"Hello Ankit"];
NSLog(#"a memory location A - %p", &a );
b=[[NSMutableString alloc]initWithString:#"Hello Nigam"];
NSLog(#"a memory location B- %p", &b );
c= [[NSMutableString alloc]initWithString:#"Ankit Nigam"];
NSLog(#"a memory location C %p",&c);
NSMutableString *temp =[[NSMutableString alloc]initWithString:#"hey"];
NSLog(#"temp = %# %p",temp,&temp);
self.b = temp;
NSLog(#"B is now %# %p",self.b,&b);
self.a = temp;
NSLog(#"A is now %# %p",self.a,&a);
And i get the output as -- - -
2012-05-10 03:24:34.756 retainCountTest[2655:f803] a memory location A - 0x6d314fc
2012-05-10 03:24:34.757 retainCountTest[2655:f803] a memory location B- 0x6d31500
2012-05-10 03:24:34.764 retainCountTest[2655:f803] a memory location C 0x6d31504
2012-05-10 03:24:34.764 retainCountTest[2655:f803] temp = hey 0xbfffdd04
2012-05-10 03:24:34.764 retainCountTest[2655:f803] B is now hey 0x6d31500
2012-05-10 03:24:34.765 retainCountTest[2655:f803] A is now hey 0x6d314fc
But as per I understand from the Doc the retain object must have the same memory address , where as copy object will create a new object with different memory location.
Again when i change the logs to ---
self.b = temp;
NSLog(#"B is now %# %p",self.b,&_b);
self.a = temp;
NSLog(#"A is now %# %p",self.a,&_a);
It return me a complete different memory location for both the object.
2012-05-10 03:28:49.905 retainCountTest[2688:f803] a memory location A - 0x6d4a4ac
2012-05-10 03:28:49.906 retainCountTest[2688:f803] a memory location B- 0x6d4a4b0
2012-05-10 03:28:49.907 retainCountTest[2688:f803] a memory location C 0x6d4a4b4
2012-05-10 03:28:49.907 retainCountTest[2688:f803] temp = hey 0xbfffdd04
2012-05-10 03:28:49.908 retainCountTest[2688:f803] B is now hey 0x6d4a4c0
2012-05-10 03:28:49.908 retainCountTest[2688:f803] a is now hey 0x6d4a4bc
Can any help me to understand the complete concept of these retain and copy. Also why I am getting these unexpected results.
Thanks a lot.
A property is just a declaration that allows for setters, getters, and dot-syntax accessors (interface variable hiding).
It does absolutely nothing on its own but allow you to use -[myInstance myProperty] to get the variable or use -[myInstance setMyProperty:] to set it (yes, the method name is auto-assigned to -setProperty: and -property).
When declaring a property, you have three categories - thread locking, access control, and memory management. You can only pick one of the modifiers for each category and if you do not pick one, it's auto-assigned to one automatically.
#property (<thread locking>, <access control>, <memory management>) id property;
The first category can either be atomic or nonatomic. The atomic modifier forces an #synchronized(myInstance) lock on the variable, to allow thread safety. The nonatomic does not use a synchronized-block, and is NOT thread safe. If you do not use either, it is automatically set to atomic.
The second category can either be readonly or readwrite. The readwrite modifier allows the property to be modified as well, and allows auto-generation of the -setProperty: method. When the readonly modifier is used, you cannot use the -setProperty: method. You must use the internal variable from within the object to set the variable directly.
The third category can either be assign, retain, and copy. The assign modifier means the internal object pointer is set to the pointer passed to the -setProperty: message. The retain modifier assigns the passed pointer and passes a -retain to the object.
The copy modifier does a straight-up clone of the object- a new pointer to a new object at a new address in the memory. This sets the internal object pointer to the copy of the passed object, by calling -copy on the passed object. The default modifier is assign, and the compiler will warn you if you do not set the memory management category modifier on an object - because an assign modifier on an object is frowned upon (unless explicitly declared).
For an example on -copy, look at this:
- (void)setProperty:(GXMyObject *)property {
// This points to the original passed object.
GXMyObject *original = property;
// This points to a copy of the passed object.
CGMyObject *copied = [property copy];
// This points to yet another copy of the passed object-
// Independent of the other copies and original.
_property = [property copy];
// The anotherProperty is now different on this copy
// than on the original and the other copies.
_property.anotherProperty = 4;
// This will prove that they are all individual objects.
NSLog(#"%p, %p, %p", original, copied, _property);
}
There is an optional method name declaration modifier and is used like so: getter = myCustomPropertyGetter and setter = myCustomPropertySetter: (The colon : at the end of the setter method name is required because it denotes that an argument must be passed).
The second half of this is the property synthesizer or dynamizer. Once a property is declared (for example, myView) like so:
#property (nonatomic, retain) NSView *myView;
You would either: define the setter and getter yourself; #synthesize the setter and getter; #dynamic the property to say that it exists in a category or the main class, or may be added at runtime (not a fun idea, mind you, and could cause bad runtime exceptions).
The first example, writing the methods yourself would look like this:
// In Apple's LLVM 3.1 Compiler, instance variables can be added
// within {} below the #implementation as well as the #interface,
// and in private categories (#interface GXMyClass ()) like before.
#implementation GXMyClass {
// The internal object pointer is prefixed with an _ to avoid name confusions.
NSView *_myView;
}
- (NSView *)myView {
return _myView;
}
- (void)setMyView:(NSView *)myView {
_myView = [myView retain];
}
#end
The second example would be to auto-synthesize it using the #synthesize directive:
#implementation GXMyClass
// In the new Apple LLVM 3.1 Clang compiler, the = operator when used
// next to the #synthesize directive declares an internal private
// variable and automatically sets to that variable.
#synthesize myView = _myView;
// The internal variable name is now myOtherView, because we did not use the
// = operator to assign an internal variable name to the property.
#synthesize myOtherView;
#end
Under the last example, perhaps the most confusing, because it requires the use of the #dynamic directive, you require something of a category or a runtime method addition:
#interface GXMyClass (InternalMethods)
#end
#implementation GXMyClass
// The = assignment operator does not work here.
#dynamic myView;
#end
#implementation GXMyClass (InternalMethods)
- (NSView *)myView {
return [self methodThatReturnsAnNSView];
}
- (void)setMyView:(NSView *)myView {
[self methodThatAcceptsAnNSViewArgument:myView];
}
#end
The #property declaration requires one of the three above declarations to be present- it does not do anything on its own. What it DOES allow, however is dot-syntax accessors (Java-like accessors for setting and getting properties).
For example, #property (copy) NSString *myName; could be accessed using -[myObject myName] and set using -[myObject setMyName:].
Now it can be set using myObjectInstance.myName = #"Bob"; and gotten using myObjectInstance.myName. Utilizing all the above concepts, one could create an object such as this one:
// The GXBufferQueue is a queue which buffers all requests, till they are read
// asynchronously later. The backing store is an NSMutableArray to which all
// buffer writes are appended to, and from which the first object is pulled and
// returned when the buffer is read to.
#interface GXBufferQueue
#property (nonatomic, readwrite, copy, setter = write:, getter = read) id buffer;
+ (GXBufferQueue *)queue;
#end
#implementation GXBufferQueue {
// This queue is an internal array and is 'tacked on' to the #implementation
// so no others can see it, and it can be marked #private so subclasses cannot
// use it. It is also good code practice to have #interfaces composed of only
// #properties, setters, and getters, rather than expose internal variables.
NSMutableArray *_internalQueue;
}
+ (GXBufferQueue *)queue {
return [[[GXBufferQueue alloc] init] autorelease];
}
- (id)init {
if((self = [super init])) {
_internalQueue = [[NSMutableArray alloc] init];
}
}
- (void)write:(id)buffer {
[_internalQueue addObject:buffer];
}
- (id)read {
if(!(_internalQueue.count > 0)) return nil;
id buffer = [_internalQueue objectAtIndex:0];
[_internalQueue removeObjectAtIndex:0];
return buffer;
}
#end
Note: This code was in no way tested.
Now that you have a GXBufferQueue, all the following works:
GXBufferQueue *queue = [GXBufferQueue queue];
// Option One: using the traditional message syntax:
[queue write:#"This will be now added to the buffer."];
NSLog(#"Now the string written to the queue will be read \
and removed from the queue, like a stack pop. ", [queue read]);
// Option Two: using the new dot-syntax accessors:
queue.buffer = #"As clunky as this looks, it works the same as above.";
NSLog(#"These lines work just the same as the ones above: ", queue.buffer);
As you can see, there's a lot possible with properties and a lot more that can be done with them than just variable declaration. If there are any questions or anything the community would like me to add/rectify to/in the post, please leave a comment! :D
Yes, retainCount is useless-- don't call it-- and assuming that copy will always return a new instance is incorrect.
If an immutable object is sent copy, it will typically be implemented as:
- copy { return [self retain]; }
I.e. there is no need to make an actual copy since the contents can't change.
Of course, since you are mucking about with static, compiled into the binary, strings, the implementation is likely closer to:
- retain { return self; }
- copy { return self; }
- (void)release { ; }
- (void)dealloc { ; }
Maybe -- all of the above are implementation details that may change at any time. The bottom line, though, is that all of the above fulfills the contract of retain/release/copy/etc...

How to use NSCache with a generic NSDiscardableContent implementation

I want to store various objects in an NSCache and have them automatically get removed when a memory warning hits. So I wrote the following NSDiscardableContent implementation that I use to wrap instances I put into the values in an NSCache.
But I'm never seeing them get removed from the cache when I run "Simulate Memory Warning". Is there something wrong with my NSDiscardableContent implementation? Or do I need to do something else to make the cache drop the values when a memory warning occurs?
/** #brief generic implementation of the NSDiscardableContent for storing objects in an NSCache */
#interface GenericDiscardableObject : NSObject<NSDiscardableContent>
#property (nonatomic, retain) id object;
#property (nonatomic) NSUInteger accessCount;
+ (GenericDiscardableObject *)discardableObject:(id)ob;
#end
#implementation GenericDiscardableObject
#synthesize object, accessCount;
+ (GenericDiscardableObject *)discardableObject:(id)ob {
GenericDiscardableObject *discardable = [[GenericDiscardableObject alloc] init];
discardable.object = ob;
discardable.accessCount = 0u;
return [discardable autorelease];
}
- (void)dealloc {
self.object = nil;
[super dealloc];
}
- (BOOL)beginContentAccess {
if (!self.object)
return NO;
self.accessCount = self.accessCount + 1;
return YES;
}
- (void)endContentAccess {
if (self.accessCount)
self.accessCount = self.accessCount - 1;
}
- (void)discardContentIfPossible {
if (!self.accessCount)
self.object = nil;
}
- (BOOL)isContentDiscarded {
return self.object == nil;
}
#end
As far as I can tell, the default behaviour of NSCache is to throw objects away when there is a memory warning.
So you can simply store your objects "naked" in your cache as if it was an NSDictionary, and they will be cleaned up when memory gets tight. You don't have to wrap them in a discardable object, or do anything else. E.g.
[myCache setObject:foo forKey:#"bar"]; // foo will be released if memory runs low
It's not very clear from the documentation, but as far as I can tell, the purpose of the <NSDiscardableContent> content protocol is for implementing more complex behaviour whereby an object can release subcomponents when memory is low, without necessarily releasing itself.

Passing objects into NSOperation and ensuring correct memory management policies

If I want to pass an object that was created on the main thread onto an NSOperation object, what's the standard way of doing to so that I'm not creating any memory management issues? Should I make my object's properties not have the 'nonatomic' attribute?
Right now, I allocate the objects via [[[AClass alloc] init] autorelease], keep a copy of the instance on my main thread and then pass another copy into the NSOperation as part of an NSArray. When I try to iterate through the array list objects inside NSOperation class and access one of the AClass's properties, the debugger reports that one of the member properties of AClass's instance object is already zombied while others are not. The error I'm seeing is:
-[CFString retain]: message sent to deallocated instance 0x5a8c6b0
*** -[CFString _cfTypeID]: message sent to deallocated instance 0x5a8c6b0
*** -[CFString _cfTypeID]: message sent to deallocated instance 0x5a8c6b0
I can't tell who is releasing my string properties too early but the entire object instance has not been released.
My class looks like:
#interface AClass
{
NSString *myTitle;
NSString *myDescription;
}
#property (nonatomic, retain, readonly) NSString *myTitle;
#property (nonatomic, retain, readonly) NSString *myDescription;
#end
#implementation AClass
#synthesize myTitle, myDescription;
- (void)dealloc
{
[myTitle release];
[myDescription release];
}
#end
Here's an updated snippet for an efficient, 'thread-safe' version of AClass:
/**
AClass is an immutable container:
- category methods must never change the state of AClass
*/
#interface AClass : NSObject < NSCopying >
{
#private
NSString * title;
NSString * description;
}
/**
subclassing notes:
- do not override properties: title, description
- implement #protocol NSCopying
*/
/*
1) document copy on entry here, even though the compiler has no
additional work to do.
2) nonatomic in this case - these ivars initialized and never mutate.
3) readonly because they are readonly
*/
#property (copy, readonly, nonatomic) NSString * title;
#property (copy, readonly, nonatomic) NSString * description;
/* prohibited: */
- (id)init;
/* designated initializer */
- (id)initWithTitle:(NSString *)inTitle description:(NSString *)inDescription;
#end
#implementation AClass
#synthesize title;
#synthesize description;
- (id)init
{
assert(0 && "use the designated initializer");
self = [super init];
[self release];
return 0;
}
- (id)initWithTitle:(NSString *)inTitle description:(NSString *)inDescription
{
self = [super init];
assert(self && "uh oh, NSObject returned 0");
if (0 != self) {
if (0 == inTitle || 0 == inDescription) {
assert(inTitle && inDescription && "AClass: invalid argument");
[self release];
return 0;
}
/* this would catch a zombie, if you were given one */
title = [inTitle copy];
description = [inDescription copy];
if (0 == title || 0 == description) {
assert(title && description && "string failed to copy");
[self release];
return 0;
}
}
return self;
}
- (void)dealloc
{
/* which could also happen when if your init fails, but the assertion in init will be hit first */
assert(title && description && "my ivars are not meant to be modified");
[title release], title = 0;
[description release], description = 0;
/* don't forget to call through super at the end */
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone
{
assert(self.title == title && self.description == description && "the subclasser should not override the accessors");
if ([self zone] == zone && [self class] == [AClass class]) {
/*
this is one possible (optional) optimization:
- avoid using this approach if you don't entirely understand
all the outlined concepts of immutable containers and low
level memory management in Cocoa and just use the
implementation in 'else'
*/
return [self retain];
}
else {
return [[[self class] allocWithZone:zone] initWithTitle:self.title description:self.description];
}
}
#end
Beyond that, avoid overusing autorelease calls so your memory issues are local to the callsite. This approach will solve many issues (although memory issues may still exist in your app).
Update in response to questions:
Justin Galzic: so basically, the copy
ensures that objects are local to the
caller and when the instance is shared
out to the thread on which
NSOperations is on, they're two
different instances?
actually, the copy call to an immutable string could perform a retain.
as an example: AClass could now implement #protocol NSCopying by simply retaining the 2 strings. also, if you know AClass is never subclassed, you could just return [self retain] when the objects are allocated in the same NSZone.
if a mutable string is passed to the initializer of AClass, then it will (of course) perform a concrete copy.
if you want objects to share these strings, then this approach is preferred (in most cases) because you (and all clients using AClass) now know the ivars will never change behind your back (what they point to, as well as the strings' contents). of course, you still have the ability to make the mistake of changing what title and description point to in the implementation of AClass - this would break the policy you've established. if you wanted to change what the members of AClass pointed to, you'd have to use locks, #synchronized directives (or something similar) - and then typically set up some observation callbacks so you could guarantee that your class works as expected... all that is unnecessary for most cases because the above immutable interface is perfectly simple for most cases.
to answer your question: the call to copy is not guaranteed to create a new allocation - it just allows several guarantees to propagate to clients, while avoiding all thread safety (and locking/synchronizing).
What if there are some cases where you
do want multiple classes (on the same
thread) to share this object? Would
you then make an implicit copy of this
object and then pass along to the
NSOperation?
now that i've detailed how copying immutable objects can be implemented. it should be obvious that properties of immutable objects (NSString, NSNumber, etc.) should be declared copy in many cases (but many Cocoa programmers don't declare them that way).
if you want to share a NSString which you know is immutable, you should just copy it from AClass.
if you want to share an instance of AClass you have 2 choices:
1) (best) implement #protocol NSCopying in AClass: - (id)copyWithZone: implementation added above.
now the client is free to copy and retain AClass as is most logical for their needs.
2) (BAD) expect that all clients will keep their code up to date with changes to AClass, and to use copy or retain as required. this is not realistic. it is a good way to introduce bugs if your implementation of AClass needs to change because clients will not always update their programs accordingly. some people consider this acceptable when the object is private in a package (e.g., only one class uses and sees its interface).
in short, it's best to keep the retain and copy semantics predictable - and just hide all the implementation details in your class so your clients' code never breaks (or is minimized).
if your object is truly shared and its state is mutable, then use retain and implement callbacks for state changes. otherwise, keep it simple and use immutable interfaces and concrete copying.
if an object has an immutable state, then this example is always a lock free thread safe implementation with many guarantees.
for an implementation of an NSOperation subclass, i find it best (in most cases) to:
- create an object which provides all the context it needs (e.g., an url to load)
- if the something needs to know about the operation's result or to use the data, then create a #protocol interface for the callbacks and add a member to the operation subclass which is retained by the NSOperation subclass, and which you've prohibited from pointing to another object during the lifetime of the NSOperation instance:
#protocol MONImageRenderCallbackProtocol
#required
/** ok, the operation succeeded */
- (void)imageRenderOperationSucceeded:(AClass *)inImageDescriptor image:(NSImage *)image;
#required
/** bummer. the image request failed. see the #a error */
- (void)imageRenderOperationFailed:(AClass *)inImageDescriptor withError:(NSError *)error;
#end
/* MONOperation: do not subclass, create one instance per render request */
#interface MONOperation : NSOperation
{
#private
AClass * imageDescriptor; /* never change outside initialization/dealloc */
NSObject<MONImageRenderCallbackProtocol>* callback; /* never change outside initialization/dealloc */
BOOL downloadSucceeded;
NSError * error;
}
/* designated initializer */
- (id)initWithImageDescriptor:(AClass *)inImageDescriptor callback:(NSObject<MONImageRenderCallbackProtocol>*)inCallback;
#end
#implementation MONOperation
- (id)initWithImageDescriptor:(AClass *)inImageDescriptor callback:(NSObject<MONImageRenderCallbackProtocol>*)inCallback
{
self = [super init];
assert(self);
if (0 != self) {
assert(inImageDescriptor);
imageDescriptor = [inImageDescriptor copy];
assert(inCallback);
callback = [inCallback retain];
downloadSucceeded = 0;
error = 0;
if (0 == imageDescriptor || 0 == callback) {
[self release];
return 0;
}
}
return self;
}
- (void)dealloc
{
[imageDescriptor release], imageDescriptor = 0;
[callback release], callback = 0;
[error release], error = 0;
[super dealloc];
}
/**
#return an newly rendered NSImage, created based on self.imageDescriptor
will set self.downloadSucceeded and self.error appropriately
*/
- (NSImage *)newImageFromImageDescriptor
{
NSImage * result = 0;
/* ... */
return result;
}
- (void)main
{
NSAutoreleasePool * pool = [NSAutoreleasePool new];
NSImage * image = [self newImageFromImageDescriptor];
if (downloadSucceeded) {
assert(image);
assert(0 == error);
[callback imageRenderOperationSucceeded:imageDescriptor image:image];
[image release], image = 0;
}
else {
assert(0 == image);
assert(error);
[callback imageRenderOperationFailed:imageDescriptor withError:error];
}
[pool release], pool = 0;
}
#end
If there is something I do not recommend, it is that you are keeping your reference unretained by the knowledge that it will be retained by someone else already. Because the reference is unretained, when it is removed from the array it will be released, retain count might drop to zero and object might be dealloc and now you are holding time bomb i.e. invalid reference.
I would suggest that do not autorelease the reference, and try to do break point at your dealloc and see the stack call to see who cause your object to be dealloc.

Objective-C/iPhone Memory Management Static Variables

I have a static method that creates an instance of the class and puts it in the static variable. I am wondering what the proper way of memory management is in this situation.
You can't put it in the dealloc-method, because although it can access the static variable any instance method that is created that get's released will also release the sharedInstance.
I guess there might be an option of creating a static destroy method which will manualy release the memory and can be called by the user from appWillTerminate, but that seems a bit odd.
So, again, the question:
What is the proper way of releasing a static variable?
// MyClass.m
#import "MyClass.h"
static MyClass *myClass; // How to properly do memory management
#implementation MyClass
+ (MyClass *)sharedMyClass {
if (myClass == nil) myClass = [[MyClass alloc] init];
return myClass;
}
#end
You can either not release them, which is fine since the app is shutting down anyway. Cocoa on the iPhone already does this, it doesn't completely delete everything, it just lets the app get blown away.
Or you can delete it from appWillTerminate or some other shutdown function.
You'll want to have a look at "Creating a Singleton" on the iPhone dev center to see how to properly implement that pattern. You won't be releasing your singleton, just letting it die when the application exits.
Also, if you're multithreaded you'll probably want to wrap that alloc in a #synchronize( self ) {}
Here is the full text:
Some classes of Foundation and the
Application Kit create singleton
objects. In a “strict” implementation,
a singleton is the sole allowable
instance of a class in the current
process. But you can also have a more
flexible singleton implementation in
which a factory method always returns
the same instance, but you can
allocate and initialize additional
instances.The NSFileManager class fits
this latter pattern, whereas the
UIApplication fits the former. When
you ask for an instance of
UIApplication, it passes you a
reference to the sole instance,
allocating and initializing it if it
doesn’t yet exist.
A singleton object acts as a kind of
control center, directing or
coordinating the services of the
class. Your class should generate a
singleton instance rather than
multiple instances when there is
conceptually only one instance (as
with, for example, NSWorkspace). You
use singleton instances rather than
factory methods or functions when it
is conceivable that there might be
multiple instances one day.
To create a singleton as the sole
allowable instance of a class in the
current process, you need to have an
implementation similar to Listing
2-15. This code does the following:
Declare a static instance of your
singleton object and initialize it to
nil. In your class factory method for
the class (named something like
“sharedInstance” or “sharedManager”),
generate an instance of the class but
only if the static instance is nil.
Override the allocWithZone: method to
ensure that another instance is not
allocated if someone tries to allocate
and initialize an instance of your
class directly instead of using the
class factory method. Instead, just
return the shared object. Implement
the base protocol methods
copyWithZone:, release, retain,
retainCount, and autorelease to do the
appropriate things to ensure singleton
status. (The last four of these
methods apply to memory-managed code,
not to garbage-collected code.)
Listing 2-15 Strict implementation of
a singleton static MyGizmoClass
*sharedGizmoManager = nil;
+ (MyGizmoClass*)sharedManager {
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
return sharedGizmoManager; }
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedManager] retain]; }
- (id)copyWithZone:(NSZone *)zone {
return self; }
- (id)retain {
return self; }
- (NSUInteger)retainCount {
return NSUIntegerMax; //denotes an object that cannot be released }
- (void)release {
//do nothing }
- (id)autorelease {
return self; }
If you want a singleton instance (created and
controlled by the class factory
method) but also have the ability to
create other instances as needed
through allocation and initialization,
do not override allocWithZone: and the
other methods following it as shown in
Listing 2-15.
UPDATE: There is now a much easier way to create a singleton
+ (MyClass*)sharedInstance
{
static MyClass* _sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[MyClass alloc] init];
});
return _sharedInstance;
}
Using this new style you don't need to worry about the #syncronize or overriding the memory management methods.
static variable or class remains in memory Untill lifetime of your application
So if it is UnUsed then make
Your_variable = nil;
while declaring use static _datatype variable = nil;
which help while initializing .. and memory management
///**************************
// MyClass.m
#import "MyClass.h"
static MyClass *myClass = nil;
#implementation MyClass
+ (MyClass *)sharedMyClass {
if (myClass == nil)
myClass = [[MyClass alloc] init];
return myClass;
}
#end