How to call a method using a shared instance? - iphone

I have a method which calculates loan payments based on car price, interest rate and number of years, this method is in my model and is accessed through my main view controller.
I created a singleton in the model but since I created it the method that calculates the payments stopped working for some reason. I have made sure that I have created the shared instance, It was working before I implemented the singleton.
Any help would be appreciated. I have not received any errors.
Here is the singleton I created.
+(id) sharedCalculatorBrain
{
static id sharedCalculatorBrain = nil;
if (sharedCalculatorBrain == nil)
{
sharedCalculatorBrain = [[sharedCalculatorBrain alloc]init];
}
return sharedCalculatorBrain;
}
Here is how I have created the object.
CalculatorBrain * brain = [CalculatorBrain sharedCalculatorBrain];
and I call the method by using:
[brain calculatePaymentPlan:[self.txtLoanAmount.text doubleValue] :[self.txtInterestRate.text doubleValue] :[self.txtNumberOfYears.text doubleValue]];

Not sure if it is a typo, but check your code if you allocate the singleton instance using:
sharedCalculatorBrain = [[sharedCalculatorBrain alloc] init];
Because if this is the case, you need to do:
sharedCalculatorBrain = [[CalculatorBrain alloc]init];
Hope this helps, good luck with your project!

Related

Initializing a static singleton object with NSCoder

I'm working on an iPhone app and facing some troubles with my shared singleton class.
I'm using a shared singleton to store two variables
int gameRuns and int totalScore
'gamRuns' just increments every time the user loads the app, and 'totalScore' is obvious :D
the issue is as follows, I load the singleton and init using my own method when the app loads using this code:
+ (SingletonLevelState*)sharedLevelStateInstance {
static SingletonLevelState *sharedLevelStateInstance;
#synchronized(self) {
if(!sharedLevelStateInstance) {
//Init a singleton
sharedLevelStateInstance = [[SingletonLevelState alloc] init];
sharedLevelStateInstance->gameRuns = 1;
sharedLevelStateInstance->totalScore = 0;
}
}
return sharedLevelStateInstance;
}
This is working great as I can reference this class from any other class and always get a pointer to the same object, so this works fine from other objects:
sharedLevelState = [SingletonLevelState sharedLevelStateInstance];
sharedLevelStateInstance.gameRuns++;
Now I added the NSCoder protocol, and added the two methods initWithCoder and encodeWithCoder as follows :
- (void) encodeWithCoder: (NSCoder *)coder
{
//encode level data
[coder encodeInt:self->gameRuns forKey:#"gameRuns"];
[coder encodeInt:self->totalScore forKey:#"totalScore"];
}
- (id) initWithCoder: (NSCoder *) coder
{
if(self = [super init]){
self->gameRuns = [coder decodeIntForKey:#"gameRuns"];
self->totalScore = [coder decodeIntForKey:#"totalScore"];
}
return self;
}
Now when the app loads, I check to see if we already have a saved sate, if it exists, I just unarchive the class with that file, if not, I init that class using my custom method above, then set its defaults, encode it to file so we have a saved state, here's the code:
//Load Level state
sharedLevelStateInstance = [SingletonLevelState sharedLevelStateInstance];
//Check if file is saved
NSFileManager *fm = [[NSFileManager alloc] init];
NSString *gameStatePath = [NSString stringWithString:[self getSavePath]];
if([fm fileExistsAtPath:gameStatePath]){
[self loadState];
sharedLevelStateInstance.gameRuns = sharedLevelStateInstance.gameRuns+1;
NSLog(#"Loaded %d times", [sharedLevelStateInstance gameRuns]);
}
[fm release];
Now the last line in the if statement works perfectly, it increments every time I load the app as expected and I feel really happy lol.
However, the problem arises when I try to get a reference of the singleton in another class by doing the following:
sharedLevelStateInstance = [SingletonLevelState sharedLevelStateInstance];
NSLog(#"Played: %d times", sharedLevelStateInstance.gameRuns);
It always counts back to 1, I know what happens but I'm not sue what's the best way to solve it, when I initWithCoder the singleton, It's not returning a static object, it creates a new one, when I init my sharedLevelStateInstance, it calls my first custom method, initializing it to the defaults hardcoded.
So StackOverflow, can you please help me ?!
I just need to know what's the best way to get a reference to the same object without allocating a new one every time I initWithCoder !
Thanks :)
So, you code should probably look like this:
if(self = [[SingletonLevelState sharedLevelStateInstance] retain])
Which sets the variables of the singleton, and returns the singleton. Be sure to retain the singleton, so that when the NSCoder releases this instance, it doesn't fully deallocate your singleton.

question related to Iphone autorelease usage

Could someone help me please understand how allocation and memory management is done and handled in following scenario. i am giving a Psuedo code example and question thats troubling me is inline below:
interface first
{ NSDecimalNumber *number1;
}
implementation
.....
-(void) dealloc {
[number1 release];
[super dealloc];
}
=================================
interface second
{ NSDecimalNumber *number2;
}
implementation second
.....
- (First*) check
{
First *firstObject = [[[First alloc] init] autorelease];
firstObject.number1 = [[NSDecimalNumber alloc] initWithInteger:0];
**// do i need to autorelease number1 as well?**
return firstObject;
}
Your code is correct as is. If you autoreleased the object, its reference count would reach zero and it would be dealloced, and then if you later tried to use the value stored in number1 your app would crash.
The only enhancement I'd add is releasing any existing value. i.e.
[number1 release];
number1 = [[NSDecimalNumber alloc] initWithInteger:0];
If you don't do this, the previous object assigned to number1 will leak each time check is called.
As you're allocing the NSDecimalNumber, you need to release it. (As you're doing so in the dealloc.)
Whilst it's hard to provide a meaningful example based on your sample code (as "number1" isn't actually used), the general rule is that you're responsible for any object you alloc, copy or new. If the object was only required in the scope of a function, you could of course autorelease it.
There's a good blog article over at http://interfacelab.com/objective-c-memory-management-for-lazy-people/ that I'd recommend reading as it provides good examples (including some edge cases) and is easy to follow.

IPhone memory management

I am a bit lost with the memory management. I've read that you should release whenever you alloc. But when you get an instance without the alloc, you shouldnt release.
What about this situation, just need to know If I was coding correctly. I'm still new on iphone dev.
I have a class CustomerRepository it has a method
- (MSMutableArray *) GetAllCustomers() {
MSMutableArray *customers = [[MSMutableArray alloc] init];
Customer *cust1 = [[Customer alloc] init];
cust1.name = #"John";
Customer *cust2 = [[Customer alloc] init];
cust2.name = #"Tony";
[customers addOjbect:cust1];
[customers addOjbect:cust2];
[cust1 release];
[cust2 release];
return customers;
}
Then I have a UIViewController
- (void) LoadCustomers() {
CustomerRepository *repo = [[CustomerRepository alloc] init];
MSMutableArray *customers = [repo GetAllCustomers];
// Iterate through all customers and do something
[repo release];
}
So in this scenario ... the MSMutableArray will never be release? Where should it be release?
If you alloc an object in a function that you need to return from the function then you can't release it inside the function. The correct way to do this is to autorelease the object.
MSMutableArray *customers = [[MSMutableArray alloc] init];
// ..... do work
return [customers autorelease];
This is the approach taken by the connivence constructors like
[NSString stringWithString:#"test"];
This method will return you an autoreleased string so that you don't need to release it.
And if you don't do this then you should name your function accordingly that the caller knows that it owns the returned object and thus needed to be released. These are conventions, not a rule imposed by the compiler or run-time environment but following convention is extremely important, specially when multiple people are involved in the project.
Whenever you create and return an object from a method or function, that object should be autoreleased. The exceptions are when the method starts with Create or New (or Alloc, obviously), or when the object is being cached within the method.
The other answers which suggest releasing it in LoadCustomers are incorrect, because GetAllCustomers does not imply a transfer of ownership like CreateCustomersArray or NewCustomersArray would. However, you can't release the object in GetAllCustomers either because then the object would be deallocated before returning it. The solution is autorelease.
The customers array should be released after you are done iterating it. You delegated the creation of the array to your repo object but your LoadCustomers method owns the array.
Another approach would be to have your CustomerRepository expose an allCustomers property. You could lazily initialize the array in your getter and then release the array when the CustomerRepository is released. That would keep your calls to alloc and release in the same object.
it should be released in your view controller, LoadCustomers() since you are allocing it in the method you are calling, it is still owned by YOU.

Apple Singleton example query?

I am a little confused by this snippet of code (presented in the CocoaFundamentals guide) that overrides some of the methods when creating a singleton instance.
static id sharedReactor = nil;
+(id)sharedInstance {
if(sharedReactor == nil) sharedReactor = [[super allocWithZone:NULL] init];
return sharedReactor;
}
.
+(id)allocWithZone:(NSZone *)zone {
return[[self sharedInstance] retain];
}
-(id)retain {
return self;
}
In the code where the singleton instance is created the +sharedInstance method calls [super allocWithZone:NILL] from the superclass (which in my case is NSObject) The allocWithZone above is only called if you attempt to use it to create a new singleton.
The bit I am confused about is the use of retain, especially seeing as retain is also overridden to return self. Can anyone explain this, could it not be written:
+(id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
-(id)retain {
return self;
}
EDIT_001:
Based on comments and reading various posts on the web I have decided to go with the following (see below) I have chosen to go for a shared singleton approach where if needed I would have the option of creating a second or third instance. Also at this stage as I am only using the singleton for the model portion of MVC for a simple iPhone app I have decided to leave thread safety out. I am aware its important and as I get more familiar with iPhone programming I will likely use +initialize instead (keeping in mind the subclass issue where it can be called twice) Also I have added a dealloc, firstly to log a message should the singleton be released, but also to clean things up properly should the singleton be no longer required.
#interface SharedManager : NSObject
+(id)sharedInstance;
#end
#implementation SharedManager
static id myInstance = nil;
+(id)sharedInstance {
if(myInstance == nil) {
myInstance = [[self alloc] init];
}
return myInstance;
}
-(void)dealloc {
NSLog(#"_deal: %#", [self class]);
[super dealloc];
myInstance = nil;
}
#end
In testing I found that I had a set the static variable to nil in the dealloc or it maintained its pointer to the original object. I was initially a little confused by this as I was expecting the scope of the static to be the instance, I guess its the class instead, which makes sense.
cheers gary
First, don't use this code. There is almost never a reason to do all this for a simple singleton. Apple is demonstrating a "Forced Singleton," in that it is impossible to create two of them. It is very rare to really need this. You can almost always use the "shared singleton" approach used by most of the Cocoa objects that have a singleton constructor.
Here's my preferred way of implementing shared singleton:
+ (MYManager *)sharedManager
{
static MYManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[self alloc] init];
}
return sharedManager;
}
That's it. No other code is required. Callers who use +sharedManager will get the shared instance. Callers who call +alloc can create unique instances if they really want to. This is how such famous "singletons" as NSNotificationCenter work. If you really want your own private notification center, there is no reason the class should forbid it. This approach has the following advantages:
Less code.
More flexible in cases where a non-shared instance is useful.
Most importantly: the code does what it says it does. A caller who thinks he's making a unique instance with +alloc doesn't encounter surprising "spooky action at a distance" behavior that requires him to know an internal implementation detail of the object.
If you really need a forced singleton because the object in question maps to a unique resource that cannot be shared (and it's really rare to encounter such a situation), then you still shouldn't use +alloc trickery to enforce it. This just masks a programming error of trying to create a new instance. Instead, you should catch the programming error this way:
+ (MYManager *)sharedManager
{
static MYManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[self alloc] initSharedManager];
}
return sharedManager;
}
- (id)init
{
NSAssert(NO, #"Attempting to instantiate new instance. Use +sharedManager.");
return nil;
}
// Private method. Obviously don't put this in your .h
- (id)initSharedManager
{
self = [super init];
....
return self;
}
There is a good example of different singleton methods with comments here on SO:
What does your Objective-C singleton look like?
If it helps, the example has a different approach to allocWithZone: which returns nil.

Initialize a class only once

I have a class that contains a few instance methods which need to be called from another class. I know how to do that -
TimeFormatter *myTimeFormatter = [[TimeFormatter alloc] init];
[myTimeFormatter formatTime:time];
However, I don't want to have to alloc and init TimeFormatter every time I need to call one of its methods. (I need to call TimeFormatter's methods from various methods in another class).
I tried putting
TimeFormatter *myTimeFormatter = [[TimeFormatter alloc] init];
"by itself", or not in any blocks, but when I compile, I get an "initializer element is not constant" error.
Any input is greatly appreciated!
You can use the singleton pattern. You can read more about it here.
Specifically, you'd do something like:
static TimeFormatter* gSharedTimeFormatter = nil;
#implementation TimeFormatter
+ (TimeFormatter*)sharedTimeFormatter {
if (!gSharedTimeFormatter) {
#synchronized(self) {
if (!gSharedTimeFormatter) {
gSharedTimeFormatter = [[TimeFormatter alloc] init];
}
}
}
return gSharedTimeFormatter;
}
...
#end
Notice that we check if the variable is null, and if it is, we take a lock, and check again. This way, we incur the locking cost only on the allocation path, which happens only once in the program. This pattern is known as double-checked locking.
However, I don't want to have to alloc and init TimeFormatter every time I need to call one of its methods. (I need to call TimeFormatter's methods from various methods in another class).
I think it's worth clarifying some OOP terminology here.
The reason you need to alloc and init TimeFormatter is because your methods are instance methods. Because they're instance methods, you need an instance, and that's what alloc and init provide. Then you call your methods on (send messages to) the instance ([myTimeFormatter formatTimeString:…]).
The advantage of allowing instances is that you can keep state and settings in each instance, in instance variables, and make the latter into publicly-visible properties. Then you can deliberately have multiple instances, each having its own settings configured by whatever's using that instance.
If you don't need that functionality, you don't need to make these instance methods. You can make them class methods or even C functions, and then you don't need a TimeFormatter instance. With class methods, you send messages directly to the class ([TimeFormatter formatTimeString:…]).
And if you do want settings shared among all instances (and you don't have any state to keep), then you're right that you can just have one instance—a singleton.
The reason for that parenthesis is that shared state is bad, especially if two threads may use the time formatter concurrently. (For that matter, you could say that about settings, too. What if one thread wants seconds and the other doesn't? What if one wants 24-hour and the other wants 12-hour?) Better to have each thread use its own time formatter, so that they don't get tripped up by each other's state.
(BTW, if TimeFormatter is the actual name of your class: You are aware of NSDateFormatter, right? It does let you only format/parse the time.)
Here's a detail example of a sharedMethod. Credit goes here
#implementation SearchData
#synthesize searchDict;
#synthesize searchArray;
- (id)init {
if (self = [super init]) {
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"searches.plist"];
searchDict = [[NSDictionary alloc] initWithContentsOfFile:finalPath];
searchArray = [[searchDict allKeys] retain];
}
return self;
}
- (void)dealloc {
[searchDict release];
[searchArray release];
[super dealloc];
}
static SearchData *sharedSingleton = NULL;
+ (SearchData *)sharedSearchData {
#synchronized(self) {
if (sharedSingleton == NULL)
sharedSingleton = [[self alloc] init];
}
return(sharedSingleton);
}
#end
A very nice, and easy, way to setup a Singleton is to use Matt Gallager's SYNTHESIZE_SINGLETON_FOR_CLASS.
It sounds like you want to make TimeFormatter a singleton, where only one instance can be created. Objective-C doesn't make this super easy, but basically you can expose a static method that returns a pointer to TimeFormatter. This pointer will be allocated and initialized the first time in, and every time after that same pointer can be used. This question has some examples of creating a singleton in Objective-C.
You are trying to declare your variable outside the class? If to do it the way you want to do it you gotta declare it as static so
static TimeFormatter *myFormatter=...
From the name of the class though i dont see why you would wnat to keep one instance of your class... you can also do this with a singleton as described above, that is if you want to keep one instance of your class for the app as a whole.