Does NSUndoManager retain objects? - nsundomanager

I do the following:
Path2D *pathToRemove = [path copy];
[[[self undoManager] prepareWithInvocationTarget:self] removePath:pathToRemove atIndex:index];
[pathToRemove autorelease];
I also have a clear button that does:
[undoManager removeAllActions];
Problem is that the removeAllActions crashes the app. When I removed the [pathToRemove autorelease], it worked (or at least didn't crash. It could still be a memory leak). I guess I was assuming that the undoManager retained 'pathToRemove' when passed in the 'prepareWithInvocationTarget' call.
Is that not the case? If that is not the case then the crash could happen because the call to 'removeAllActions' is releasing the 'PathToRemove' object. But that would mean it is a bug in NSUndoManager which is highly unlikely.
I can say that my copyWithZone implementation is not likely to be the culprit either since NSLog outputs for '[pathToRemove description]' and '[path description]' show different addresses as expected.
Any help would be appreciated. Thanks.

According to the documentation, the prepareWithInvocationTarget: method doesn't retain the arguments passed to it. From the NSUndoManager documentation, it appears that it simply captures the NSInvocation and later replays it. NSInvocationobjects don't retain the objects in their arguments unless specifically asked to do so.
That doesn't quite explain the crash, because removeAllActions is just supposed to clear the undo stack and not do anything to the objects.
Hope this helps some in tracking down the source of the crash.

In my experience, it's not a release/retain issue. You've to clear the stack after the Undo/Redo Operation. To do this you can register your viewController for the NSUndoManagerDidUndoChangeNotification notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(clearUndoRedoStack) name:NSUndoManagerDidUndoChangeNotification object:nil];
and then clear the stack onto the specified method:
- (void)clearUndoRedoStack {
[undoManager removeAllActions];
}

Related

How do we prevent "CoreData could not fulfill a fault"?

We get "CoreData could not fulfill a fault" every once in a while. We have read through the Apple documentation but are unclear on what is allowed to be retained. We have been very careful about creating one context per thread, etc. However, one thing our app is doing is we are retaining NSManagedObjects on our UIViewControllers (usually via a NSArray or NSDictionary). I'm guessing what's going on is the object relationships are changing and we are not handling the appropriate notification.
Does anyone have any suggestions on the better design with regards to Core Data? When we get the error, I cannot see that we actually deleted anything from the context to cause the fault. Is it necessary to handle NSManagedObjectContextObjectsDidChangeNotification on our UIViewControllers if they are retaining state? Any suggestions would be appreciated.
You can register for change notifications in Core Data. This will allow you to update your managed objects when they change. See the Core Data Docs for more info. You're going to be interested in 2 methods to register and respond to changes:
[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:(your NSManagedObjectContext)];
The mergeChanges selector (your method) will call the following method to synchronize any changes from other threads. It will look something like this:
- (void)mergeChanges:(NSNotification *)notification{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
// Merge changes into the default context on the main thread
[context performSelectorOnMainThread:#selector(mergeChangesFromContextDidSaveNotification:)
withObject:notification
waitUntilDone:YES];
}

How to right dealloc object when app goes to background?

Have only one question "How to right dealloc object when app goes to background ?". I'm working on some app, everything works great and fine. When i put app to background and then start it again it's crashes. Not immediately(app stars right where i closed it) , but when i choose some of cells or just scroll tableview for example. So i'm pretty sure that app calls already released data.
here is example of dealloc
- (void)dealloc {
[anObject release];
[array release];
[locationManager release];
[currentLatitude release];
[currentLongitude release];
[filteredListContent release];
[super dealloc];
}
Any advises?
Unless you specifically deallocate things in your app delegate's applicationDidEnterBackground method, nothing should be deallocated for you automatically.
I have never experienced the problem you're having. Are you certain the same thing doesn't happen after a while even if you never put it in the background?
Here's a good explanation of how all of the backgrounding stuff fits together:
Understanding iOS 4 Backgrounding and Delegate Messaging
I review and re-write my own code. The problem was as i expected in deallocation of memory. I used autorelease where i shouldn't. It still weird cause app did crash when i open it again.
Thanks everyone, not you guys who gift to me 2 negs, you are jerks. Don't be offended,but instead of give some advise you just give ungrounded negs.
Never release any object like this. Use
- (void)dealloc {
if(anObject){
[anObject release];
anObject = nil;
}
if(array){
[array release];
array = nil;
}
//same approach for all.
[super dealloc];
}

AVCaptureStillImageOutput outputSettings memory leak

I'm experiencing a wierd behavior in the new AVFoundation classes in the iPhone SDK.
I have a AVCaptureStillImageOutput for taking pictures, and I am setting its outputSettings to my liking. The code follows:
AVCaptureStillImageOutput *stillImageOutput = [[[AVCaptureStillImageOutput alloc] init] autorelease];
[stillImageOutput setOutputSettings:[NSDictionary dictionaryWithObject:AVVideoCodecJPEG forKey:AVVideoCodecKey]];
[self setStillImageOutput:stillImageOutput];
(stillImageOutput property is defined as "retain")
I stumbled upon a leak in leaks, with 100% of the leak fault on the setOutputSettings line. I believe that I confine to the memory management guidelines in the code attached, still it is leaking.
My solution was to
[self.stillImageOutput setOutputSettings:nil];
in the dealloc, just before
[self setStillImageOutput:nil];
The leak indeed stopped, but it looks weird. Shouldn't the releasing of stillImageOutput release its outputSettings property as well?
Anyway, if someone else runs into this, thought I should share my solution.
Cheers!
Oded.
Yes, the releasing of stillImageOutput should release it's outputSettings property as well. Either it's an Apple bug (should let them know, your use case is pretty simple) or remove your line, and see whether anything other than your class is hanging onto that stillImageOutput object (which is holding the outputSettings).

uiimagepickerview controller creating memory leaks in iphone - why?

uiimagepickerview controller creating memory leaks in iphone - why?
Try to implement ui image picker view controller in your application & debug it.
You will find memory leaks in your application.
Why ui image picker view controller creates memory leaks.
-(void)addPhotos:(id)sender
{
if(imagePickerController==nil){
imagePickerController=[[UIImagePickerController alloc]init];
imagePickerController.delegate=self;
imagePickerController.sourceType=UIImagePickerControllerSourceTypeSavedPhotosAlbum;
imagePickerController.allowsImageEditing=YES;
imagePickerController.navigationBar.barStyle=UIBarStyleBlackOpaque;
}
[self.navigationController presentModalViewController:imagePickerController animated:YES];
}
dealloc of my view controller.
- (void)dealloc {
if(PhotoDateArray!=nil)[PhotoDateArray release];
if(imagePickerController!=nil) [imagePickerController release];
if(objDetail!=nil) [objDetail release];
if(Picimage!=nil) [Picimage release];
if(mySavePhotoController!=nil) [mySavePhotoController release];
if(LoadingAlert!=nil);
[super dealloc];
}
Video link explaining how I am getting the memory leak in it..
http://www.yourfilelink.com/get.php?fid=508534
Even though you have the nil check, it's still possible to leak memory. I think what is happening here is that you are calling alloc / init multiple times, but only releasing once. My guess it that addPhoto: is wired up to some button click, dealloc would only be called once when the delegate is trying to destroy. This creates a situation like this:
button click
alloc / init
button click
alloc / init (memory leak on first alloc'd picker)
close window
dealloc (free second alloc'd picker)
A better way might be the way Apple does it in the PhotoLocations and iPhoneCoreDataRecipes examples:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
[self presentModalViewController:imagePicker animated:YES];
[imagePicker release];
Then listen for the didFinishPickingImage and imagePickerControllerDidCancel messages to your delegate and a call to [self dismissModalViewControllerAnimated:YES]; in both places should suffice.
I dont know about the rest of the code, but do you ever have a release?
[imagePickerController release]
UIImagePickerController loads and initializes PhotoLibrary.framework the first time it is shown. This memory won't be reclaimed until your application is closed.
(the code you posted doesn't appear to have leaks as-is, but that doesn't mean it won't interact with the rest of your application in a way that causes them)
I can explain this because I was having the same problem.
Don't test memory on the simulator!
If you test the apple code on a device the memory problem disappears.
I was having a memory alloc leak which I found in Instruments. All I was doing was opening and closing the image picker (open/cancel) and using Apple code, my code and other people's code, just like yours above.
All were showing the allocation going up and up each time, as if the picker was not being released. If you tried to release it, it would crash (over released).
Then I found a really helpful web page which basically stated:
"This doesn't happen when testing on the device"
So I switched from the simulator and ran the tests on the device. Lo & behold there was no allocation increase and it behaved normally.
This however is totally evil and now we can place no trust in the simulator to do a reliable job.
I want to add this to save people, the time, pain and bewilderment of wondering wtf is going on!

OCUnit testing NSNotification delivery

For a game I'm developing, I have several model classes that trigger notifications when their state changes. Then, the view subscribes to those notifications and can react on them.
I'm doing my unit tests for the model with OCUnit, and want to assert that the expected notifications were posted. For that, I'm doing something like this:
- (void)testSomething {
[[NSNotificationCenter defaultCenter] addObserver:notifications selector:#selector(addObject:) name:kNotificationMoved object:board];
Board *board = [[Board alloc] init];
Tile *tile = [Tile newTile];
[board addTile:tile];
[board move:tile];
STAssertEquals((NSUInteger)1, [notifications count], nil);
// Assert the contents of the userInfo as well here
[board release];
}
The idea is that the NSNotificationCenter will add the notifications to the NSMutableArray by calling its addObject: method.
When I run it, however, I see that addObject: is being sent to some other object (not my NSMutableArray) causing OCUnit to stop working. However, if I comment out some code (such as the release calls, or add a new unit test) everything starts working as expected.
I'm assuming this has to o with a timing issue, or NSNotificationCenter relying on the run loop in some way.
Is there any recommendation to test this? I know I could add a setter in Board and inject my own NSNotificationCenter, but I'm looking for a quicker way to do it (maybe some trick on how to replace the NSNotificationCenter dynamically).
Found the problem. When testing notifications you need to remove the observer after you have tested it. Working code:
- (void)testSomething {
[[NSNotificationCenter defaultCenter] addObserver:notifications selector:#selector(addObject:) name:kNotificationMoved object:board];
Board *board = [[Board alloc] init];
Tile *tile = [Tile newTile];
[board addTile:tile];
[board move:tile];
STAssertEquals((NSUInteger)1, [notifications count], nil);
// Assert the contents of the userInfo as well here
[board release];
[[NSNotificationCenter defaultCenter] removeObserver:notifications name:kNotificationMoved object:board];
}
If you fail to remove the observer, after a test runs and some local variables are released, the notification center will try to notify those old objects when running any subsequent test that triggers the same notification.
There are no timing issues or runloop related problems since everything in your code is non-concurrent and should be executed immediately. NSNotificationCenter only postpones notification delivery if you use an NSNotificationQueue.
I think everything is correct in the snippet you posted. Maybe there's an issue with the mutable array 'notifications'. Did you init and retain it correctly? Try to add some object manually instead of using the notification trick.
If you suspect your tests have timing issues - you may want to consider injecting your own notification mechanism into your board object (which is probably just a wrapper of the existing apple version).
That is:
Board *board = [[Board alloc] initWithNotifier: someOtherNotifierConformingToAProtocol];
Presumably your board object posts some notification - you would use your injected notifier in that code:
-(void) someBoardMethod {
// ....
// Send your notification indirectly through your object
[myNotifier pushUpdateNotification: myAttribute];
}
In your test - you now have a level of indirection that you can use for testing, so you can implement a test class the conforms to your AProtocol - and maybe counts up the pushUpdateNotification: calls. In your real code you encapsulate the code you probably already have in Board that does the notification.
This of course is a classic example of where MockObjects are useful - and there is OCMock which well let you do this without having to have a test class to do the counting (see: http://www.mulle-kybernetik.com/software/OCMock/)
your test would problably have a line something like:
[[myMockNotifer expect] pushUpdateNotification: someAttribute];
Alternatively you could consider using a delegate instead of notifications. There is a good pro/con set of slides here: http://www.slideshare.net/360conferences/nsnotificationcenter-vs-appdelegate.