Where to release the shared instance in iOS - ios

I have a shared instance (a simple data controller) and in my project I don't use ARC.
static ECOMDataController *sharedInstanse;
#implementation ECOMDataController
+(ECOMDataController *)sharedInstance
{
return sharedInstanse;
}
-(id)init
{
[self checkAndCreateDataFileIfExist];
[self readAppFile];
if (sharedInstanse)
NSLog(#"The shared instance was created already.");
sharedInstanse = self;
return self;
}
And I use it in the other methods like this:
- (void)viewDidLoad
{
[super viewDidLoad];
dataController = [ECOMDataController sharedInstance];
[dataController readAppFile];
[[self tableView] reloadData];
}
As I can see from the leaks instrument - I have a memory leak here - what should I do to release the data controller? And where is better to do that?

Rocky is right: you wouldn't deallocate a singleton. Frankly, I wouldn't use that pattern at all--except for system calls like AppDelegate or NSNotificationCenter. There are a lot of pitfalls with the pattern...but that's my opinion (though I'm not alone in it).
More importantly, why are you not using ARC? There's absolutely no reason not to, and many reasons for it. Especially for a newer developer, there's no sense in fussing about memory management when the compiler will do it for you, anyway--and will do a better job of it. You have enough to learn without fussing over retain counts!

Related

Autorelease objects in ARC

Suppose in my Database Manager which is singleton.
+ (SWDatabaseManager *)retrieveManager
{
#synchronized(self)
{
if (!sharedSingleton)
{
sharedSingleton = [[SWDatabaseManager alloc] init];
}
return sharedSingleton;
}
}
- (NSArray *)getProductDetails:(NSString *)someString
{
NSArray *temp = [self getRowsForQuery:someString];
return temp;
}
- (NSArray *)getRowsForQuery:(NSString *)sql
{
sqlite3_stmt *statement=nil;
NSMutableArray *arrayResults = [NSMutableArray arrayWithCapacity:1];
//
//Fetching data from database and adds them in to arrayResults
//
return arrayResults;
}
Now from some view controller i am calling function of Database manager like this....
[self getProductServiceDidGetDetail:[[SWDatabaseManager retrieveManager] getProductDetail: #"SomeQuery"]
- (void)getProductServiceDidGetDetail:(NSArray *)detailArray
{
[self setDataSource:[NSArray arrayWithArray:detailArray]];
[self.tableView reloadData];
}
Questions are ...
When arrayResult of getRowsForQuery will release?
Do i need to assign nil to detailArray of getProductServiceDidGetDetail?
Is there any memory leaks?
Suggestion will be appreciated.
ARC does automatic memory management. So it releases everything (your array), when you are done using it.
ARC works by adding code at compile time to ensure that objects live
as long as necessary, but no longer. Conceptually, it follows the same
memory management conventions as manual reference counting (described
in Advanced Memory Management Programming Guide) by adding the
appropriate memory management calls for you.
To help you understand better you might want to read apples docs on ARC.
You will not need to assign nil to the array, nor do you have to worry about memory leaks.
You do not have to (indeed cannot) release instance variables, but you
may need to invoke [self setDelegate:nil] on system classes and other
code that isn’t compiled using ARC.

General design - Where do I put centrally accessed objects

I have my main app delegate
I have a few UIViewController derived instances driven by a Storyboard
Say I'd like to provide a centralized persistence layer for my application - perhaps Core Data of SQLite. Where would I put those objects? I'm missing some centrally accessible "Application" class you can access from all the UIViewController instances.
Is there a pattern to follow here?
you should check the singleton pattern:
In software engineering, the singleton pattern is a design pattern
that restricts the instantiation of a class to one object. This is
useful when exactly one object is needed to coordinate actions across
the system. The concept is sometimes generalized to systems that
operate more efficiently when only one object exists, or that restrict
the instantiation to a certain number of objects. The term comes from
the mathematical concept of a singleton.
here is a source for a example implementation: What should my Objective-C singleton look like?
and here is the direct link for the modern solution:
https://stackoverflow.com/a/145395/644629
What you're describing is your model layer. There are two main ways to manage the model:
At application startup, create the main model object and hand it to the first view controller.
Make the main model object a Singleton.
The "main model object" in both cases is generally some kind of object manager. It could be a document, or it could be a PersonManager if you have a bunch of Person objects. This object will vend model objects from your persistence store (generally Core Data).
The advantage of a Singleton here is that it's a little easier to implement and you don't have to pass around the manager. The advantage of a non-Singleton is that it's easier to have more than one (for a document-based system), and it's easier to test and reason about non-singletons than singletons. That said, probably 80% of my projects use a singleton model manager.
As a side note, that you appear to already understand: never store the model in the application delegate, and never use the application delegate as a "rendezvous point" to get to the model. That is, never have a sharedModel method on the application delegate. If you find yourself calling [[UIApplication sharedApplication] delegate] anywhere in your code, you're almost always doing something wrong. Hanging data on the application delegate makes code reuse extremely difficult.
Go with a singleton pattern, which has scope of application lifetime.
#interface DataManager ()
#end
#pragma mark -
#implementation DataManager
#pragma mark - Shared Instance
static DataManager* sharedInstance = nil;
#pragma mark - Singleton Methods
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
+ (DataManager*)sharedInstance
{
#synchronized([DataManager class])
{
if (!sharedInstance) {
//[[self alloc] init];
sharedInstance = [[DataManager alloc] init];
}
return sharedInstance;
}
return nil;
}
+ (id)alloc
{
#synchronized([DataManager class])
{
NSAssert(sharedInstance == nil, #"Attempted to allocate a second instance \
of a singleton.");
sharedInstance = [super alloc];
return sharedInstance;
}
return nil;
}
#end
Declare your properties in .h file and synthesize them here in .m file.
To use that property just call:
// set value
[[DataManager sharedInstance] setSharedProperty:#"ABC"]; // If its a string
// get Value
NSLog(#"value : %#", [[DataManager sharedInstance] sharedProperty]);
Hope this is what you required.
Enjoy Coding :)

Is it good approach to use [self release], [self retain]?

I created DownloadAndParseBook class. It will not autorelesed before it gеt any data or network error.
I used [self release], [self retain]. Is it good approach to use [self release], [self retain]? Is DownloadAndParseBook contain any potential bugs?
#implementation GetBooks
-(void) books
{
for(int i =0; i<10; i++)
{
DownloadAndParseBook *downloadAndParseBook =
[[[DownloadAndParseBook alloc] init]autorelease];
[downloadAndParseBook startLoadingBook];
}
}
#end
#implementation DownloadAndParseBook
- (id)initWithAbook:(int)bookID
{
if(self = [super init])
{
[self retain];
}
return self;
}
- (void)startLoadingBook
{
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[self release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self saveResultToDatabase];
[self release];
}
#end
Self retaining is very occasionally an appropriate pattern. It's rare, but sometimes in certain kinds of multi-threaded code its important to make sure that you don't vanish in the middle of processing something. That said, this is not one of those times. I'm having trouble imagining a case where your current approach would be helpful. If someone creates your object and then never calls startLoadingBook, then it leaks. If someone calls startLoadingBook, then your object is retained anyway, because NSURLConnection retains its delegate until it finishes.
That said, I believe much of your problem is coming from the fact that your object model is wrong. Neither GetBooks nor DownloadAndParseBook make sense as classes. What you likely mean is BookManager (something to hold all the books) and BookDownloadController (something to manage the downloading of a single book). The BookManager should keep track of all the current BookDownloadControllers (in an NSSet or NSArray ivar). Each BookDownloadController should keep track of its NSURLConnection (in an ivar). You should not just create connections and have them "hang on themselves" (i.e. self-retain). This feels convenient, but it makes the code very hard to deal with later. You have no way to control how many connections you're making. You have no way to cancel connections. It becomes a mess really quickly.
No it is not a best practice.
Retaining / releasing your object should be done by the "owner" of your object.
For your particular example, the owner of your DownloadAndParseBook object is the object that does the alloc/init. That should be the oen retaining/releasing your DownloadAndParseBook instance.
Best practice here would be alloc/init for DownloadAndParseBook, retain done by the owner, all your download/parse logic, then sending a callback to the owner that all the operations are done (through a delegate for example), at which point, the ower sends a release message to your object.
The question would be: Why does an object require to retain itself? You may want to implement your class like a singleton.
Unlike the other responders I would say that your pattern might work. See also Is calling [self release] allowed to control object lifetime?
There are some other issues in your code however:
In -(void) books I guess you want to send the startLoadingBook message to downloadAndParseBook and not to self
If you create a initWithAbook method it will not be called when you init your book with the standard init method. In the current code above [self retain] will be never called
In your code above bookID will not be saved
I would not use "init" pattern here, but everything in a static function thus the caller can not make mistake with the ownership of the class.
Code:
- (id) initWithId:(int)bookId {
self = [super init];
if (self) {
// save bookId here
}
return self;
}
+ (void) startLoadingBookWithID:(int)bookId {
DownloadAndParseBook* book = [[DownloadAndParseBook alloc] initWithId:bookId];
[NSURLConnection connectionWithRequest:request delegate:book];
}
// release self when it finished the operation
// and document well that its behaviour
If you think well, NSURLConnection itself should work exactly the same way: when you don't release an NSURLConnection when it finished its work, it does it itself. However in the connectionWithRequest it also can not autorelease itself since it has to be alive until the request is served. So the only way it can work is the pattern described above
Never use [self release]. The only possible exception would be in an singleton class/object. The methods release and retain should only be sent by the owner of an object. This usually means, whichever object created the object in question, should also be the one to release it.

Passing and retaining NSString to another view when popping current view

I have a method that will dismiss the current view in the navigation controller and replace it with another view. The code looks like this
-(void)didTransferRequest:(NSString *)_transferComments {
AddRequestViewController *ar = [[AddRequestViewController alloc]
initAsTransferForRequestID:requestID
withClosingComments: _transferComments]];
UINavigationController *currentNav = self.navigationController;
[[self retain] autorelease];
[currentNav popViewControllerAnimated:NO];
[currentNav pushViewController:ar animated:NO];
[ar release];
}
[AddRequestViewController.m]
-(AddRequestViewController *)initAsTransferForRequestID:(int)requestID
withClosingComments:(NSString *)closingComments{
self = [self initWithStyle: UITableViewStyleGrouped];
if (self) {
_requestID = requestID;
_closingComments = closingComments;
}
return self;
}
The problem is that once the new view is pushed onto the nav stack, it crashes when the view attempts to access the contents passed in by _transferComments. The pointer is pointing to something else which would make sense since the view gets popped.
I was successful in using withTransferComments: [_transferComments copy] but the Analyzer identified a memory leak with this.
Is using copy safe and should I ignore the leak message or is there a better way to send the string over?
Your AddRequestViewController isn't taking ownership of _transferComments.
You need to read Cocoa Core Competencies - Memory Management and Basic Memory Management Rules.
In the code snippet you posted (without the copy), I deduce that AddRequestViewController doesn't send retain to _transferComments. If it wants to make sure _transferComments stays around, it needs to send it the retain message to take ownership of the string. When AddRequestViewController is done with the string, it needs to send it release to relinquish ownership. You would probably do this in -[AddRequestViewController dealloc].
Basically, your initAsTransferForRequestID:withClosingComments: method should look something like this:
- (id)initAsTransferForRequestID:(int)requestId withClosingComments:(NSString *)transferComments {
if (!(self = [super init]))
return nil;
_requestId = requestId;
_transferComments = [transferComments retain];
return self;
}
(Note that I'm using the common convention of naming instance variables with a leading underscore.) Your dealloc method should look like this:
- (void)dealloc {
[_transferComments release];
[super dealloc];
}
When you changed your code to copy _transferRequest, you did create a memory leak. The copy message creates an "owning" reference to the copy, and something needs to take responsibility for relinquishing that ownership. You didn't change either of your objects to do that.

View controller / memory management

i'm a little bit confused with memory management in view controllers.
Lets say i have header file like this:
#interface MyController : UIViewController {
NSMutableArray *data;
}
#property (nonatomic, retain) NSMutableArray *data;
#end
and .m file looks like that:
#implementation MyController
#synthesize data;
- (void)dealloc
{
[self.data release];
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.data == nil)
self.data = [[NSMutableArray alloc] init];
}
- (void)viewDidUnload
{
[super viewDidUnload];
[self.data release];
self.data = nil;
}
Is that ok from the correct memory management point of view? Will that work after dealloc via Memory Warning? How You do that in your apps?
Thanks for your answers ;)
While the alloc-retain calls balance out in viewDidLoad and viewDidUnload and should prove no problem memory-wise, it would be cleaner to take ownership only once and relinquishing it once rather than twice.
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.data == nil)
self.data = [NSMutableArray array];
}
and
- (void)viewDidUnload
{
[super viewDidUnload];
self.data = nil;
}
You are not guaranteed that viewDidUnload will ever get called. Unlike init/dealloc, which get called in pairs, viewDidUnload is undeterministically called. viewDidUnload is only called if there is a low memory situation and your view is not the active view.
Depending on how your model is created and the implications of it remaining in memory, it may make more sense for you not to get rid of it. An example of this may be that recreating that data may involve an expensive web service call. It therefore would be a bad user experience to have to wait for that data to get recreated. If it must absolutely go, a better strategy may be to cache the data to disk so that you can easily reconstruct it.
viewDidUnload should only contain cleaning up your IBOutlets and flushing easily recreatable data.
These lines from -viewDidUnload both release data:
[self.data release];
self.data = nil;
Since you're using the property setter in the second line, and data is a retained property, the setter will release data. This is an over-release, and it'll cause a crash either right away or later, depending on whether other objects also retain that object. To fix, simply delete the first line and rely on the setter to do the right thing.
The -dealloc method, on the other hand, shouldn't use the setter as it does now. You should change:
[self.data release];
to:
[data release];
data = nil; // this line isn't strictly necessary, but often considered good form
The reasoning here is that it's conceivable that this class could be subclassed, and someone might override the property setter in such a way that it has some side effects that could cause problems when the object is being deallocated. You should access the ivar directly -- notice that I left off the "self." so that we're dealing with the ivar and not the property accessor. (-init and -dealloc are the only places where you have to worry about that; use the property accessors everywhere else.)

Resources