IOS Memory leak in class method - iphone

In your opinion if I have a singleton subclass of NSObject being initialised with parameters like this:
- (MyObject *) initWithSomeParam:(NSString *)param{
self = [super init];
if (SharedInstance == nil){
SharedInstance = [super init];
SharedInstance.someProperty = param;
}
return self;
}
+ (MyObject *) objectWithSomeParam:(NSString *)param{
return [[self alloc] initWithSomeParam:param];
// Will the alloc cause a leak?
}
The user doesn't have access to the instance method, just the class. Thanks.

That's not the normal way of implementing a singleton and you are breaking the convention of init. Better would be to create a sharedInstance class method and leave the initWithParam method to be more conventional:
static MyObject *_sharedInstance = nil;
+ (MyObject *)sharedInstance:(NSString *)param
{
if (_sharedInstance == nil)
{
_sharedInstance = [MyObject alloc] initWithParam:param];
}
return _sharedInstance;
}
// This must be called during app termination to avoid memory leak
+ (void)cleanup
{
[_sharedInstance release];
_sharedInstance = nil;
}
- (id)initWithParam:(NSString *)param
{
self = [super init];
if (self != nil)
{
self.someProperty = param;
}
return self;
}
However, even that doesn't seem very comfortable; i.e. what happens if the user calls sharedInstance with a different parameter? Perhaps you want to keep a NSMutableDictionary of the initialized objects and create/return them depending on the parameter?
If so, you would do:
static NSMutableDictionary _sharedInstances = [[NSMutableDictionary alloc] init];
+ (MyObject *)sharedInstance:(NSString *)param
{
MyObject *obj = [_sharedInstances objectForKey:param];
if (obj == nil)
{
obj = [[MyObject alloc] initWithParam:param];
[_sharedInstances setObject:obj forKey:param];
}
return obj;
}
// This must be called during app termination to avoid memory leak
+ (void)cleanup
{
[_sharedInstances release];
_sharedInstances = nil;
}

Related

Cannot init a class object - xcode

I'm new to IOS development. I wrote the implementation file following like this.
#implementation Utils
+(id)alloc
{
return [self instance];
}
+(Utils *)instance
{
static Utils *utils = nil;
if (!utils) {
utils = [self init];
}
return utils;
}
-(Utils *)init
{
self = [super init];
if (self) {
mConst = [Constants instance];
mCONT_REGEXP = [mConst CONT_REGEXP];
}
return self;
}
When i call
[Utils instance];
I got the error following Like this:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[Utils<0xbff54> init]: cannot init a class object.'
Thanks for your answers.
Are you trying to create a shared singleton instance?
In that case, use the following snippet:
+ (id)sharedInstance;
{
static dispatch_once_t onceToken;
static Utils *sharedUtilsInstance = nil;
dispatch_once( &onceToken, ^{
sharedUtilsInstance = [[Utils alloc] init];
});
return sharedUtilsInstance;
}
It is better to call it "sharedInstance" so that it's more understandable the instance is shared.
remove your following method
+(id)alloc
{
return [self instance];
}
And write code as/....
+(Utils *)instance
{
static Utils *utils = nil;
if (!utils) {
unit = [[unit alloc] init];
}
return utils;
}

NSMutableArray within singleton class always returns count 0 / never retains its objects

My simplified singleton looks like this:
#interface MyClass : NSObject {
NSMutableArray * myArray;
}
+ (MyClass*) instance;
#property(nonatomic,retain)NSMutableArray *myArray;
Then in the implementation
static MyClass * myinstance;
#synthesize myArray;
+ (MyClass*) instance {
if(myinstance == nil)
myinstance = [[MyClass alloc] init];
return myinstance;
}
- (id) init {
if(self = [super init]) {
myArray = [[NSMutableArray alloc] initWithCapacity:2];
[myArray addObject:#"Trauma"];
}
return self;
}
However when I try to access it for a tableview this always returns 0:
[[[MyClass instance] myArray] count];
Little unsure about what I'm doing wrong
The method that returns the instance of your singleton is named +instance, but when attempting to access your singleton, you are using +myinstance. Your instance of MyClass is most likely nil.

iOS - Objects being released?

I have the following piece of code:
Dummy *dummy = [[Dymmy alloc] initWithDictionary:dummyData];
DummyTableItem *dummyTableItem = [DummyTableItem itemWithDummy: dummy];
[_data addObject: dummyTableItem];
The init functions are as follows:
+ (id) itemWithDummy: (Dummy *) dummy {
DummyTableItem *item = [[[self alloc] init] autorelease];
item.dummy = dummy;
return item;
}
- (id) init {
self = [super init];
if( self ) {
dummy = nil;
}
return self;
}
with dummy declared as (nonatomic, retain)
And Dummy:
#synthesize name=_name;
- (id) initWithDictionary: (NSDictionary *) dictionary {
self = [super init];
if( self != nil ) {
if( [dictionary objectForKey:#"name"] )
_name = [dictionary objectForKey:#"name"];
}
return self;
}
with name again declared as (nonatomic, retain)
When I am trying to access later on the dummyTableItem.dummy.name to set it to a UILabel I am getting a "-[CFString isEqualToString:]: message sent to deallocated instance 0x5b37a10"
Am I doing something completely wrong with the retained objects? What am I missing here? Also in the first part of code should I release the dummyTableItem after adding it to _data (which is an NSMutableArray?)
This should solve the problem inside Dummy's #implementation :
#synthesize name=_name;
- (id) initWithDictionary: (NSDictionary *) dictionary {
self = [super init];
if (self) {
_name = [[dictionary objectForKey:#"name"] retain]; //retain it :)
}
return self;
}
Since you declared name as retain you should own it (That is why I added retain when assigning it).
Furthermore, you don't need to check if( [dictionary objectForKey:#"name"] ) because _name = [nil retain]; is nil anyways :)

Imlementation of Singleton Class

i have been using mostly the appDelegate class for global variables but recently i came to know that its not a gud way for keeping global variables so i am trying to make a singleton class as following
#implementation globalVar
static globalVar *_sharedInstance =nil;
#synthesize totalTime;
- (id) init
{
if (self = [super init])
{
}
return self;
}
+ (globalVar *) sharedInstance
{
#synchronized (self) {
if (_sharedInstance == nil) {
[[self alloc] init];
}
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (_sharedInstance == nil) {
_sharedInstance = [super allocWithZone:zone];
return _sharedInstance;
}
}
return nil;
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
-(NSUInteger)retainCount
{
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release
{
// do nothing
}
- (id)autorelease
{
return self;
}
- (void) setTotalTime:(NSString *)time
{
#synchronized(self) {
if (totalTime != time) {
[totalTime release];
totalTime = [NSString stringWithFormat:#"%#",time];
}
}
//NSLog(#"time %#",totalTime);
}
-(NSString *)getTotalTime
{
#synchronized(self) {
//NSLog(#"total %#",totalTime);
return totalTime;
}
}
when i set the value for totaltime in my appDelegate class and retrieve it in that class only i get the correct value. but when i only retrieve the value in some other class i get BAD EXCESS. i first create the sharedinstance and then only call this method then why am i getting this error??
globalVar *myEngine = [globalVar sharedInstance];
NSLog(#"about %#",[myEngine totalTime]);
in my app delegate
globalVar *myEngine = [globalVar sharedInstance];
[myEngine setTotalTime:totalTime];
NSLog(#"in app delegate%#",[myEngine getTotalTime]);
You're releasing totalTime but not retaining the new value, which means that when you access it it's already been released, causing a bad access exception.
You can correct this by changing the line where you set the value to include a call to retain:
totalTime = [[NSString stringWithFormat:#"%#",time] retain];
Have a look at the discussion here:
Is it good practice to use AppDelegate for data manipulation and Handling?

IPhone Repository for data

I'm a totally noob in IPhone development. Just start a week ago. I'm trying to have this tableview working.
I have a class I created called CustomerRepository with a method like this
- (CustomerRepository *) init {
self = [super init];
if (self) {
customerArray = [[NSMutableArray alloc] init];
Customer *cust1 = [[Customer alloc] init];
cust1.name = #"cust1";
[customerArray addObject: cust1];
[cust1 release];
}
return self;
}
- (NSMutableArray *) GetAll {
NSMutableArray *returnCustomerArray = [[[NSMutableArray alloc] init] autorelease];
for(Customer *cust in customerArray)
{
Customer *copy = [[Customer alloc]init];
copy.name = cust.name;
[returnCustomerArray addObject:copy];
[copy release];
}
return returnCustomerArray;
}
Now In my Controller
#synthezise customerArray;
viewDidLoad {
CustomerRepository *custRepo = [[CustomerRepository alloc] init];
customerArray = [custRepo GetAll];
[custRepo release];
}
- (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section {
// It always throw an exception here about -[UITableViewRowData count]: unrecognized selector sent to instance
return [customerArray count];
}
There is definitely something wrong with my code, can you guys help me point out what is wrong. Most probably an access to an instance that is already release ....
You need to retain the array returned by GetAll. Try this:
viewDidLoad {
CustomerRepository *custRepo = [[CustomerRepository alloc] init];
customerArray = [[custRepo GetAll] retain];
[custRepo release];
}
If you don't retain it, then your autorelease in -GetAll means that the returned array will eventually be released. When your -numberOfRowsInSection method fires, it's talking to a dealloc'd instance.