I am needing to use #autoreleasepool because I Am getting some high memory usage. The issue is, the objects that are taking up memory are created in one method on a background thread, then sent to a second method where they are used to update the UI.
- (void)createObjects {
TestObject = *test = [[TestObject alloc] init];
[self updateUIWithTestObject:test];
}
- (void)updateUIWithTestObject:(TestObject *)testObject {
// Update UI
self.textLabel.text = testObject.text;
}
Where would I be able to place the #autoreleasepool so that I can release the objects that I have created?
Related
Hopefully it is an appropriate question to ask. My goal is
1.add a controller into an array name 'arrControllers'
2.access and get current controller from 'arrControllers' to do sth with it
and I just wanna make sure the arrControllers should be ready before I access and use it. That is why I am using serial queue and dispatch_sycn like like following.
-(void)viewDidLoad
{
[super viewDidLoad];
firstViewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
[self setUpWithView:firstViewController];
}
and in setUpWithView: is
-(void)setUpWithView:(UIViewController*)viewController {
dispatch_queue_t queue;
queue = dispatch_queue_create("my queue", NULL);
containerController = [ContainerViewController sharedContainerController];
// What I am taking about is from now on
dispatch_sync(queue, ^{
[containerController initWithRootViewController:viewController];
});
dispatch_sync(queue, ^{
[containerController setUpView];
});
}
and initWithRootViewController: is
- (void)initWithRootViewController:(UIViewController*)rootViewController {
arrControllers = [[NSMutableArray alloc] init];
arrControllers = [NSMutableArray arrayWithObject:rootViewController];
}
and setUpView is
-(void)setUpView {
/* Process to ADD currentController TO hierarchy */
[self addChildViewController:[arrControllers lastObject]];
............................................................
}
As far as I know the compiler will execute codes line by line, it means by do following
-(void)setUpWithView:(UIViewController*)viewController {
containerController = [ContainerViewController sharedContainerController];
// Not using serial_queue and dispatch_sync
[containerController initWithRootViewController:viewController];// line1
[containerController setUpView]; //line2
}
compiler will execute line2 until it finished the task at line1.
My question is
1. is it necessary to using `serial_queue` and `dispatch_sycn`for this situation.
PS: if you think it is a bad question to ask. please comment what you think about it.
First of all, you should have a look at UIView and UIViewController life cycles, this will tell you when a UIVie or a UIViewController is "ready to be used". Second, you should check when the serial ques and GCD is used.
For the second point I can give you a short summary because it's kind of faster that the first point.
Use CGD and queues (other then main queue) if you want to do computing or other stuff, that don't involve UI changes, on a background thread without freezing the UI.
Use GCD with main queue to switch between a background queue and the main (UI) queue.
All UI operations must be performed on the main thread.
So in your case, you want to create a view controller and store it into an array, so as a suggestion, all the UI related calls of your view controllers should be performed on the UI thread, so no need for GCD or background threads.
In case you are doing some complicated stuffs on your view controller's init methods, just put those complicated stuffs on a GCD block on a separated thread.
In this situation if you do not use dispatch_sync, you will get exactly what you need:
-(void)setUpWithView:(UIViewController*)viewController {
containerController = [ContainerViewController sharedContainerController];
// Not using serial_queue and dispatch_sync
[containerController initWithRootViewController:viewController];// line1
[containerController setUpView]; //line2
}
Line 1 will execute initWithRootViewController:, going deeper and executing lines
arrControllers = [[NSMutableArray alloc] init];
arrControllers = [NSMutableArray arrayWithObject:rootViewController];
then it will return from this function one level above and proceed, moving to line 2 and going down to line
[self addChildViewController:[arrControllers lastObject]];
ALSO. Never write code like this
arrControllers = [[NSMutableArray alloc] init];
arrControllers = [NSMutableArray arrayWithObject:rootViewController];
First line creates an empty NSMutableArray and assigns a pointer to it into arrControllers.
Second line creates another array (autoreleased) and assigns a pointer to it in arrControllers again. So a link to array created in the first line is lost and it is leaked under manual memory management.
If you use manual memory management, do the following:
arrControllers = [[NSMutableArray alloc] init];
[arrControllers addObject:rootViewController];
OR
arrControllers = [[NSMutableArray alloc] initWithObjects:rootViewController,nil];
Under ARC leave only second line.
Hope I understood you correctly. Feel free to ask questions.
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.
I ran analyze on my 1st iPhone app, and I see a few potential memory leaks. The app itself works fine on the simulator.
I would like to do the right thing and clear the potential memory leaks, but some are quite puzzling. Maybe someone could help me here?
Thanks in advance.
Pier.
Error 1) The Analyzer says "Potential leak of an object stored in tempDate and tempAns"
#import "Answer.h"
#implementation Answer
#synthesize answerTiming;
#synthesize xPosition;
#synthesize earlyOrLate;
#synthesize hit;
+ (Answer *) createAnswerWithTiming :(NSDate *)paramTiming andXPosition :(float) xPosition
{
NSDate * tempDate = [[NSDate alloc] initWithTimeInterval:0 sinceDate:paramTiming];
Answer * tempAns = [[Answer alloc] init ];
[tempAns setAnswerTiming:tempDate];
[tempDate release];
[tempAns setXPosition:xPosition];
[tempAns setEarlyOrLate:0];
[tempAns setHit:false];
return tempAns;
}
- (void)dealloc {
[answerTiming release];
[self release];
[super dealloc];
}
#end
Error 2) Analyzer says (see below)
- (void)viewDidLoad
{
[super viewDidLoad];
........
...
UIImage * perfectImage = [UIImage imageNamed: #"perfect.png"];
self.perfectImageView2 = [[UIImageView alloc]initWithImage:perfectImage];
// method returns an objective C content with a +1 retain count
[self.perfectImageView2 setFrame:CGRectMake(145.0f,
150.0f,
self.perfectImageView2.image.size.width,
self.perfectImageView2.image.size.height)];
self.view.backgroundColor = [UIColor whiteColor];
UIImage * levelUpImage = [UIImage imageNamed:#"levelup.png"];
self.levelUpImageView = [[UIImageView alloc] initWithImage:levelUpImage];
[self.levelUpImageView setFrame:CGRectMake(100.0f,
400.0f,
self.levelUpImageView.image.size.width,
self.levelUpImageView.image.size.height)];
//object leaked, allocated object is not referenced later in this execution path and has a retain count of +1
self.view.backgroundColor = [UIColor whiteColor];
}
Error 3)
- (NSMutableArray *) generateQuestionTapAnswers:(NSString *) answersString withFirstBeat: (NSDate *) firstBeatTime
{
NSArray * notesToDraw = [answersString componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString: #" "]];
float noteValueOffset = 0.0;
NSMutableArray * answerArray = [[NSMutableArray alloc] init ];
// Method returns an objective C object with a +1 retain count
for (int i=1; i < notesToDraw.count; i++) // i = 0 is the time signature
{
.....
}
return answerArray;
// Object returned to caller as an owning reference (single retain count transferred to caller)
// Object leaked: Object allocated and stored into answerArray is returned from a method whose name generateQuestionTapAnswers does not start with copy, mutableCopy
}
Regarding your first and third warnings, the compiler will assume that you'll be creating an object in "a method whose name begins with alloc, new, copy, or mutableCopy" (see Advanced Memory Management Programming Guide). So, if you're returning a +1 object, make sure your method name begins with one of those four prefixes. If you create a +1 object without one of those prefixes, it won't be happy. So, for error #1, if you rename that method to be something like newAnswerWithTiming, that warning should go away. (If the calling method doesn't clean up after them, though, the warning will just be shifted to that routine, but let's take it one step at a time.)
Likewise for error #3, if you rename that method to be something like newAnswerArrayFromQuestionTapAnswers (or whatever ... I'm not sure if I understand your method name ... just make sure it starts with new), you'll similarly eliminate that warning. In both cases, just make sure to release it at the appropriate point because whomever called these two respective methods now "owns" those objects and is responsible for their cleanup.
As an aside, you don't need to do [self release] in your dealloc in your discussion of error #1. (Frankly, I'm surprised it doesn't generate an error.) You don't need it because if self wasn't already at retainCount of zero, you never would have gotten to dealloc in the first place.
Regarding error #2, how are the properties perfectImageView2 and levelUpImageView defined? If retain or strong, you're creating something with a +2 retainCount, and you probably want to add an autorelease after the alloc/init.
Quick question: I use lots of NSObject derived classes and am wondering how to properly cleanup class properties that may own instances of other classes (in the snippet below this is an array of custom class instances). Is my usage of new and finalize below correct?
My understanding is that new is a convenience method that calls both alloc and init, and finalize gets called before dealloc - at least this is what I have gleaned from reading the docs. Do I have this right?
Thanks for any tips/best practices, etc!
- (id)new {
waffleArray = [[NSMutableArray alloc] initWithCapacity:kCellCount];
for (int i = 0; i < kCellCount; i++) {
WaffleCell * cell = [WaffleCell new];
[waffleArray addObject:cell];
}
return self;
}
// clean up
- (void)finalize {
[waffleArray removeAllObjects];
waffleArray = nil;
[super finalize];
}
new on NSObject is a class method, not an instance method as you have it. Also I don't really see why you'd overload new. It would be more common to overload init so something like this:
- (id)init {
if ((self = [super init])) {
waffleArray = [[NSMutableArray alloc] initWithCapacity:kCellCount];
for (int i = 0; i < kCellCount; i++) {
WaffleCell * cell = [WaffleCell new];
[waffleArray addObject:cell];
}
}
return self;
}
As for finalize, you really don't need to do that. This is what Apple says about it:
The garbage collector invokes this method on the receiver before disposing of the memory it uses. When garbage collection is enabled, this method is invoked instead of dealloc.
With ARC enabled you wouldn't need to do anything and since the garbage collector will not be running anyway, finalize won't get called anyway. ARC will automatically generate code which will release waffleArray in dealloc for you, which is enough for proper memory management in this case because waffleArray's retain count will then drop to 0, be deallocated itself which will go and release the objects in the array.
I need your help. I have write my own custom NSOperation class called GetNewsOperation. I call it like this:
GetNewsOperation *getNewsOperation = [[GetNewsOperation alloc] initWithLocalNewsCategories:self];
[loadNewsOperationQueue addOperation:getNewsOperation];
[getNewsOperation release];
In GetNewsOperation class I have implemented init method for initialization and main method for executing operation and returning data back to the main thread.
Main method looks like this:
- (void)main {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
AppSettingsController *sharedAppSettingsController = [AppSettingsController sharedAppSettingsController];
if( [type isEqualToString:#"getCategory"] ) {
NSMutableArray *parsedData = [[NSMutableArray alloc] initWithArray:[sharedAppSettingsController getLocalNewsCategories]];
[newsViewController performSelectorOnMainThread:#selector(loadDataResponse:) withObject:[NSArray arrayWithObjects:parsedData, nil] waitUntilDone:NO];
[parsedData release]; parsedData = nil;
}
[pool release];
}
Everything works fine but I have a minor problem. When this operation is called application does not rotate on device orientation change. It changes after operation is finished.
As far as I know this operation is running for sure in new thread (not in main) cos all other elements in the app are active (not freezed). But I have only problem with orientation. The app looks kind a crappy if application does not rotate only when this operation occurs...
How can I solve this?
Thanks!
Actually it works like predicted. I was doing something else on main thread that blocked application.