What is the correct way to dealloc a lock in objective-c - objective-c

I have created an NSObject, for the sole purpose of locking.
My question is, in my dealloc, how do I release(from memory) the lock. I have read that you should not modify the lock-object within synchronized. But In my scenario, I think that between the time since the #synchronized in dealloc completes, and the time that [_lockObject release] is called, another method in a different thread may acquire _lockObject. And hence if [_lockObject release] is called while _lockObject is held, bad things may happen.
What is the correct way to dispose of the lock in my dealloc method?
-(id)initWithImageFileName:(NSString*)imageFileName
{
if (self = [super init])
{
_imageFileName = [imageFileName retain];
_loadBackgroundCalled = NO;
_deallocing = NO;
_lockObject = [[NSObject alloc]init];
}
return self;
}
-(void)dealloc
{
_deallocing = YES;
#synchronized(_lockObject)
{
..... <releases some stuff>
}
[_lockObject release];
_lockObject = nil;
[_imageFileName release];
_imageFileName = nil;
[super dealloc];
}
-(void)loadBackground
{
#synchronized(_lockObject)
{
if (!_deallocing)
{
if (!_loadBackgroundCalled)
{
_loadBackgroundCalled = YES;
....
}
}
}
}
-(void)loadSprite:(XYTexture*)texture
{
#synchronized(_lockObject)
{
....
}
}
-(void)unloadBackground
{
#synchronized(_lockObject)
{
if (!_deallocing)
{
.....
_loadBackgroundCalled = NO;
}
}
}

Your object cannot be deallocated while it's being used by another object or thread. In other words, any thread that calls your object will already hold a reference to said object, and that reference will prevent the object from deallocating.
When your -dealloc method is executed you can (and must) assume that no other objects or threads hold a reference to your object, and you therefore do not have to worry about concurrency.
If -dealloc is called while your object is executing on a separate thread then that would indicate a bug in your application unrelated to this specific object. You do not solve the problem by setting flags like _deallocing, as in your example code.

Related

Objective C Singleton - Prevent Allocating Memeory More than Once

I use a sinlgeton in my application for managing data that is available to the whole application, which accessed via:
static MMProductManager *sharedInstance = nil;
+(MMProductManager*)SharedInstance {
dispatch_once( &resultsToken, ^(void) {
if ( ! sharedInstance ) {
sharedInstance = [[MMProductManager alloc] init];
}
});
return sharedInstance;
}
Everything is working as expected.
In Objective C, there does not seem to be a way to hide any object's init method, and in my case having more than instance of MMProductManager would lead to data being duplicated (in the best case scenario).
What I would like to do is guard against instantiating more than one instance. Other languages seem to have this feature; i.e. marking certain methods/classes as private. I am thinking of implementing something along like:
-(id)init {
// guard against instantiating a more than one instance
if ( sharedInstance )
return sharedInstance;
if ( (self = [super init]) ) {
self->_resultsQueue = dispatch_queue_create( kMMResultQLAbel, NULL );
self->_initialized = FALSE;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleNotification:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:0];
[self initialize];
}
return self;
}
Does this approach seem reasonable?
What would happen in the case of someone allocating this class, then calling the init described above? Would it be reasonable to override +(id)alloc? If so How would I go about doing that?
I know the convention of exposing a SharedInstance method is an implicit message to other developers to go through this method, but I would like a bit more control if possible.
You don't want to override - init (if not for some other reason) - - init is not the method that creates the instance. You want to override + alloc for this:
#implementation SingletonClass
+ (id)alloc
{
static id instance = nil;
if (instance == nil) {
instance = [super alloc];
}
return instance;
}
#end
This way you can actually prevent (almost) completely creating multiple instances of SingletonClass.
(Unless somebody falls back to calling
id trickyDifferentInstance = class_createInstance(objc_getClass("SingletonClass"), 0));
but that's very unlikely.)

NSArray become invalid when using selector

Following is my code(with some unrelated thing omitted):
#implementation HomeSceneController
...
#synthesize options = _options; // _options is a NSArray object with 4 elements
- (id)init
{
if (self = [super initWithNibName:#"HomeScene" bundle:nil]) {
_currentOptionIndex = 0;
// Following code add two key event observations, when up arrow or down arrow key is pressed, the corresponding function will be fired.
[self addObservation:_KEY_UPARROW_ selector:#selector(UpArrowPressHandler)];
[self addObservation:_KEY_DOWNARROW_ selector:#selector(DownArrowPressHandler)];
}
return self;
}
- (void)loadView {
[super loadView];
// init _options
_options = [NSArray arrayWithObjects:
_localGameOption,
_networkGameOption,
_controlSettingOption,
_quitOption,
nil];
[self selectOption:_localGameOption];
}
....
// in these two functions, _options become nil! I don't know why...
- (void)UpArrowPressHandler {
if (_currentOptionIndex > 0) {
[self deselectOption:_options[_currentOptionIndex]];
_currentOptionIndex--;
[self selectOption:_options[_currentOptionIndex]];
}
}
- (void)DownArrowPressHandler {
if (_currentOptionIndex < 3) {
[self deselectOption:_options[_currentOptionIndex]];
_currentOptionIndex++;
[self selectOption:_options[_currentOptionIndex]];
}
}
#end
when I press up arrow key, the UpArrowPressHandler function is fired. However, the problem is, the _options array become nil.
Can anyone tell me why and how to fix it?
//===========================================================================================
Additional problem:
In the following program:
import "Deep.h"
#implementation Deep
- (id)init {
if (self = [super init]) {
_name = #"Deep";
}
return self;
}
- (void)test {
NSLog(_name);
}
#end
The test method can correctly print "Deep" when I call it somewhere else.
However, according to #ATaylor's explanation, _name should be released.
So, where is my problem?
That's because _options is getting assigned an autoreleased object, which gets released once you leave the method it was called from.
Try assigning it to 'self.options', which will (most likely) call 'retain' on the object, or call 'retain' explicitly.
Once more in code:
Either use:
self.options = [NSArray ...];
Or:
_options = [[NSArray ...] retain];
Please don't forget to release your 'options', once you're done with it, either by:
self.options = nil;
or:
[_options release];
Please only go for ONE of these options, because otherwise you'll get weird behaviour with the retain count.
You see, Apple gives us a number of 'convenience functions', which return autoreleased objects, meaning we don't have to bother with their release.
As a general rule of thumb:
Call release for every alloc/retain you call yourself.
To answer the second question:
_name = #"Deep";
is an assignment to a variable, equivalent to 'const char *_name = "Deep";' from C.
There is no need to release that, for the simple reason, that you didn't create or retain it. (No new, No alloc, no retain, no copy).
The object will not get autoreleased either, because you didn't call any sort of method, which would cause the variable to be autoreleased.
Also, see this answer, which deals with the exact problem.
Just for clarification, to get a string, there are three types of methods.
NSString *someString;
someString = #"MyString"; //No retain, no release, static String.
someString = [NSString stringWithFormat...]; //Autoreleased object, disappears after the method expires.
someString = [[NSString alloc] initWithFormat...]; //Alloced object, must be released.

Singleton in iOS 5?

Hi I had an implementation previous versions of iOS for a singleton as follows:
.h file
#interface CartSingleton : NSObject
{
}
+(CartSingleton *) getSingleton;
.m file
#implementation CartSingleton
static CartSingleton *sharedSingleton = nil;
+(CartSingleton *) getSingleton
{
if (sharedSingleton !=nil)
{
NSLog(#"Cart has already been created.....");
return sharedSingleton;
}
#synchronized(self)
{
if (sharedSingleton == nil)
{
sharedSingleton = [[self alloc]init];
NSLog(#"Created a new Cart");
}
}
return sharedSingleton;
}
//==============================================================================
+(id)alloc
{
#synchronized([CartSingleton class])
{
NSLog(#"inside alloc");
NSAssert(sharedSingleton == nil, #"Attempted to allocate a second instance of a singleton.");
sharedSingleton = [super alloc];
return sharedSingleton;
}
return nil;
}
//==============================================================================
-(id)init
{
self = [super init];
}
However on the web I see people have implemented the Singleton design pattern using this code:
+ (id)sharedInstance
{
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init]; // or some other init method
});
return _sharedObject;
}
Could someone who is experience please guide me.
Im a newbie and thoroughly confused between the old iOS implementation of the Singleton and the new one and which is the correct one?
Thanks a lot
Strictly speaking, you must use:
+ (MySingleton*) instance {
static dispatch_once_t _singletonPredicate;
static MySingleton *_singleton = nil;
dispatch_once(&_singletonPredicate, ^{
_singleton = [[super allocWithZone:nil] init];
});
return _singleton;
}
+ (id) allocWithZone:(NSZone *)zone {
return [self instance];
}
Now you guarantee that one cannot call alloc/init and create another instance.
Explanation: The instance method is at the class level and is your main access method to get a reference to the singleton. The method simply uses the dispatch_once() built-in queue that will only execute a block once. How does the runtime guarantee that the block is only executed once? Using the predicate you supply (of type dispatch_once_t). This low-level call will guarantee that even if there are multiple threads trying to call it, only one succeeds, the others wait until the first one is done and then returns.
The reason we override allocWithZone is because alloc calls allocWithZone passing nil as the zone (for the default zone). To prevent rogue code from allocating and init-ializing another instance we override allocWithZone so that the instance passed back is the already initialized singleton. This prevents one from creating a second instance.
The dispatch_once snippet is functionally identical to other one. You can read about it at http://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpages/man3/dispatch_once.3.html.
This is what I use for singletons:
+ (MySingleton*) getOne {
static MySingleton* _one = nil;
#synchronized( self ) {
if( _one == nil ) {
_one = [[ MySingleton alloc ] init ];
}
}
return _one;
}
NOTE: In most cases, you do not even need to use #synchronized (but it is safe this way).
A singleton is a special kind of class where only one instance of the class exists for the current process. (In the case of an iPhone app, the one instance is shared across the entire app.) Some examples in UIKit are [UIApplication sharedApplication] (which returns the sole instance of the application itself), and [NSFileManager defaultManager] (which returns the file manager instance). Singletons can be an easy way to share data and common methods across your entire app.
Rather than create instances of the singleton class using alloc/init, you'll call a class method that will return the singleton object. You can name the class method anything, but common practice is to call it sharedName or defaultName.
Please check a link with best answer
:http://www.idev101.com/code/Objective-C/singletons.html

Objective-c Async memory management

I've had a look around but have been unable to find a definitive answer to this question.
If I have a class that performs an async operation, when and how do I release it?
-(void)main
{
AsyncObject *async = [[AsyncObject alloc] initWithDelegate:self];
[async goDoSomething];
}
-(void)didSomething:(Result*)result
{
}
When do I release *async?
You could keep a private property to save the value, or, if you have control over the AsyncObject, pass the instance in the didSomething: selector.
I think the first option is better since you know the object will be retained until you get your delegate call.
Option 1:
ClassName.m
#interface ClassName ()
#property (nonatomic, retain) AsyncObject* async;
#end
#interface
//...
-(void)main
{
async = [[AsyncObject alloc] initWithDelegate:self];
[async goDoSomething];
}
-(void)didSomething:(Result*)result
{
[async release];
async = nil;
}
Option 2:
-(void)aysncObject:(AsyncObject*)async didSomething:(Result*)result {
[async release];
}
If your object runs its asynchronous task on a background thread, or is the target of a timer, or uses GCD and is referenced within the scope of the dispatched block (the ^ {} kerjigger) then it will be retained for you for the lifetime of that background operation.
So the normal use case would be:
AsyncObject *async = [[AsyncObject alloc] initWithDelegate:self];
[async goDoSomething];
[async release];
Now, it's possible to work in the background with an object that is not retained (e.g. by using a __block-scoped reference to the object with GCD, or by detaching your worker thread with pthreads instead of NSThread/NSOperation) but there are no typical use cases I can think of offhand where that would happen. In such a case, you should ensure that -goDoSomething internally retains and releases self for the duration of the operation.
(If somebody can think of a case where the object is not retained for you, please post in the comments and I'll update my answer.)
Thanks for the help guys, I did a bit of experimenting with NSURLConnection to see how it handled it (As you autorelease that and it will continue on with it's async operations).
Turns out at the beginning of every async step it internally bumps its retain count and at the end of every async step it internally releases itself.
This means that it can be sent autorelease/release and it won't actually be release until it has completed it's current operation.
// MAIN.M
-(void)main
{
AsyncObject *async = [[[AsyncObject alloc] initWithDelegate:self] autorelease];
[async goDoSomething];
}
-(void)didSomething:(Result*)result
{
}
// ASYNCOBJECT.M
-(void) goDoSomething
{
[self retain];
}
-(void) finishedDoingSomething
{
[delegate didSomething:result];
[self release]
}

What happens to alloc if initWithX fails?

It is common practice to write MyClass* obj = [[MyClass alloc] initWithX:X] in Objective-C. initWithX is usually defined as
- (MyClass*) initWithX: (MyArgClass*) X {
if (self = [super init]) {
// initialize
}
return self;
}
My question is: what if initialize fails? I don't want to throw exceptions, but, how do I indicate error? If I return nil, the caller will not be able to release the pointer.
If initialization fails for any reason you should release self. For an exception that may occur in your initialization you need to add you #try #catch as appropriate so you can release self.
- (MyClass*) initWithX: (MyArgClass*) X {
if (self = [super init]) {
// initialize
if(myInitializationCodeFailed)
{
[self release];
return nil;
}
}
return self;
}
Update
If it is possible for your initialization fail I would not raise an exception from with in your initialization code. If you would like to provide the caller with information I would refactor the initializer to accept an NSError to be returned.
- (MyClass*) initWithX: (MyArgClass*) X error:(NSError**)error {
As Alexei Sholik points in the comments check out the Handling Initialization Failure section of Allocating and Initializing Objects.
Basically, this answers your question.
Handling Initialization Failure
In general, if there is a problem during an initialization method, you should call the release method on self and return nil.
There are two main consequences of this policy:
Any object (whether your own class, a subclass, or an external caller) that receives nil from an initializer method should be able to deal with it. In the unlikely case that the caller has established any external references to the object before the call, you must undo any connections.
You must make sure that dealloc methods are safe in the presence of partially initialized objects.
...