I am working with an NSOperationQueue and I want to add new NSOperations to the NSOperationQueue. It is a queue that lives in a singleton instance of a class I have. It would make things a lot easier if I could move everything into the static class by passing the delegate.
Here is my code now as it lives in - this is in a cellForRowAtIndexPath
NSString *key = [NSString stringWithFormat:#"%#%#",cell.dataItem.ItemID, cell.dataItem.ManufacturerID];
if (![self.imgOperationInQueue valueForKey:key]) {
ImageOperation *imgOp = [[ImageOperation alloc] initWithItemID:cell.dataItem.ItemID withManufacturerID:cell.dataItem.ManufacturerID withReurnType:kThumbnail];
imgOp.identifier = [NSString stringWithFormat:#"%i", cell.tag];
imgOp.delegate = self;
[[SharedFunctions sharedInstance] addImageOperationToQueue:imgOp];
[imgOp release];
// store these in the dictionary so we don;t queue up requests more than once
[self.imgOperationInQueue setValue:cell.dataItem.ItemID forKey:key];
}
If I could add the delegate as a parameter I could put all of this code into the shared singleton class and call it from anywhere in my app.
I suppose that I could use an NSNotification - or can I use a block of some sort?
Just create the appropriate init method that passes in the delegate.
- (id)initWithItemID:(NSString *)itemID
withManufacturerID:(NSString *)manufacturerID
withReurnType:(NSInteger)type
delegate:(id<YourDelegate>)theDelegate
{
self = [super init];
if (self)
{
.... // Other assignments
self.delegate = theDelegate;
}
return self;
}
Related
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.)
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.
When I'm creating custom classes, I'd like to be able to skip the alloc init part of the code once I go to construct an instance of the class. Similar to how it's done with:
NSString * ex = [NSString stringWithFormat...];
Basically I already have the class set up with a custom initializer method to set up my basic variables. However, when I'm on the front end and actually making these critters I have to say:
[[Monster alloc] initWithAttack:50 andDefense:45];
and I'd rather be able to say
[Monster monsterWithAttack:50 andDefense:45];
I know it's a simple stupid thing to just get rid of the alloc part but it makes the code more readable so I'd prefer to do it that way. I originally tried just changing my method from
-(id)initWithAttack:(int) a andDefense:(int) d
to
-(id)monsterWithAttack:(int) a andDefense:(int) d
and then changing my self = [super init] to self = [[super alloc] init]; but that clearly doesn't work! Any ideas?
You have to make a class method
+(id)monsterWithAttack:(int) a andDefense:(int) d
in which you create, initialize, and return an instance (and don't forget your memory management):
+(id)monsterWithAttack:(int) a andDefense:(int) d {
// Drop the autorelease IF you're using ARC
return [[[Monster alloc] initWithAttack:a andDefense:d] autorelease];
}
What you want is a convenience constructor. It's a class method that returns a useable instance of a class and allocates memory for it at the same time.
-(id)initWithAttack:(int)a andDefense:(int)d;
+(id)monsterWithAttack:(int)a andDefense:(int)d;
+(id)monsterWithAttack:(int)a andDefense:(int)d {
//-autorelease under MRC
return [[[self class] alloc] initWithAttack:a andDefense:d];
}
-(id)initWithAttack:(int)a andDefense:(int)d {
self = [super init];
if (self){
//custom initialization
}
return self;
}
You should use a class factory method in the header of monster class.
+(id)monsterWithAttack:(int) attackValue andDefense:(int) defenseValue
in the implementetation of monster class
+(id)monsterWithAttack:(int) attackValue andDefense:(int) defenseValue {
return [[[[self class] alloc] initWithAttack:attackValue andDefense:defenseValue] autorelease];
}
The use of [self class] guarantees the correct dispatch during subclassing. If you are using ARC you can avoid the autorelease method
Class methods of this type use autorelease.
So for instance, you might say:
+ (id)
monsterWithAttack:(int) a
defense:(int) d
{
return [[Monster alloc] initWithAttack:a defense:d]
autorelease];
}
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
Please consider the following two initialization methods.
The first method simply passes the value of the parameters to their respective NSString properties, but the second allocates the properties and then initializes them using the initWithString: method. Is the allocation in the latter example necessary?
Thanks in advance.
-(id)initWithTitle:(NSString *)theTitle muscleGroup:(NSString *)theMuscleGroup equipment:(NSString *)theEquipment {
if((self = [super init])){
title = theTitle;
muscleGroup = theMuscleGroup;
equipment = theEquipment;
}
return self;
}
-(id)initWithTitle2:(NSString *)theTitle muscleGroup:(NSString *)theMuscleGroup equipment:(NSString *)theEquipment {
if((self = [super init])){
title = [[NSString alloc] initWithString:theTitle];
muscleGroup = [[NSString alloc] initWithString:theMuscleGroup];
equipment = [[NSString alloc] initWithString:theEquipment];
}
return self;
}
The first example is not safe because you are not taking ownership of the strings, so your program will get all crashy if they are later released elsewhere. The second example fixes that problem and will work perfectly well, but is more concisely written thusly:
-(id)initWithTitle2:(NSString *)theTitle muscleGroup:(NSString *)theMuscleGroup equipment:(NSString *)theEquipment {
if((self = [super init])){
title = [theTitle copy];
muscleGroup = [theMuscleGroup copy];
equipment = [theEquipment copy];
}
return self;
}
NSString gives you a copy constructor (-initWithString:), which enables you to do what you are doing in #2, but not all classes do. copy requires the class to implement the NSCopying protocol, but is more conformant with the way a Cocoa API developer would expect to be able to copy objects.
Parameter objects don't get copied when you pass them in. So your first example may not always work, it depends how you've initialized your strings.
The following is safer (although remember to release the objects in your dealloc method):
-(id)initWithTitle:(NSString *)theTitle muscleGroup:(NSString *)theMuscleGroup equipment:(NSString *)theEquipment {
if((self = [super init])){
title = [theTitle retain];
muscleGroup = [theMuscleGroup retain];
equipment = [theEquipment retain];
}
return self;
}
Example 1 will assign the pointers. It makes no attempt to retain the objects and is vulnerable to something outside changing the content of the objects.
It could work depending on how the arguments are constructed in the first place;
Example 2 will copy the string objects and retain them. As long as you release in the dealloc then its the preferable method.
FWIW
title = [theTitle copy];
or
title = [[NSString stringWithString:theTitle] retain];
are equally good in Ex 2