I'm having a problem with a Core Data project on the iPhone. The scenario occurs when a user starts to add an object, then cancels during the process.
If the user hits cancel and returns to the list of objects, a dummy object is listed there, representing the one they were in the middle of creating. This is never saved to the database - saves occur as expected when the user hits the save button.
When the view controller where the user adds data is loaded, I create a new Thing object - this is the Core Data entity that I am adding:
myThing = [NSEntityDescription insertNewObjectForEntityForName:#"myThing" inManagedObjectContext:managedObjectContext];
I tried to delete this in my cancel method as follows:
[managedObjectContext deleteObject:myThing];
When I do this, I get a EXC_BAD_ACCESS when I hit cancel. Stepping through the code in the debugger, it gets through the cancel method fine, but this is being generated in the root view controller where I list my objects and also where I was before I tried to create this object.
All I'm trying to achieve is allowing the user to add a new object, but cancel part-way through.
Any ideas what is causing this error? I am unable to generate a stack trace from this unfortunately :(
Your approach to the object cancel is typical and appropriate.
Memory errors are common and can be tough to debug. Have you run the static analyzer? You may want to set your "myThing" reference to nil after deleting it from the context.
Do you know for sure that it is the cancel workflow that is leading to the memory error?
You can also turn on NSZombie and find out what released object is being accessed. That will help you quickly track this issue down. Google NSZombie for a few examples of how to use it.
Related
I've recently been playing around with OSX programming (usually an iOS guy) but I've hit a strange issue with NSCollectionView that I just can't seem to debug.
When I change the data that my data source uses to populate the collection with items, I call reloadData() on the collection view as usual and sometimes hits an assertion. The error I get is Parameter indexPath out of bounds or nil. If I don't change the data the app always crashes at the same point(s) though sometimes, usually the first time, it works just fine and only crashes subsequently.
Now, I've debugged this numerous times. The data is correct and at no point in my code do I ever see a nil index path. The assertion always occurs on the makeItemWithIdentifier call, and always on the last item in the collection. If I continue, I either see what I expect or else some of the cells from the previous collection are still there behind the new cells.
At one point I refactored the code slightly and found the error occurring in NSCollectionViews itemAtIndexPath: function instead.
Has anyone else seen this error and, if so, what caused it?
Update 2: I now know what is causing this issue, but have no idea how to prevent it. What happens is this: the user clicks an item in the collection view. That item changes the data object that the data source is reading from calls reloadData during the collection view delegate's didSelectItemsAtIndexPaths method. For some reason, after execution of this method, the collection view is queried again for the cell with that index path. If the table has been reloaded in the meantime then that cell is gone, leading to the exception. In short: you can't call 'reload' on a collection view while a mouse event is being processed on one of its cells without getting an annoying assertion. So if anyone can think of a way around this issue, I'd love to hear it!
I'm trying to minimize memory usage in my app, and one of the things I'm doing is calling finish() in the onPause method (which I know is not the best way to do things). For the most part, it seems to be working well, but when the user clicks the back button from the next activity, it logically skips over the finished activity and goes back further. Is it possible to have that activity in the back stack and just get recreated if the user presses back?
No. This conclusion comes from the task and backstack documentation as well as the activity documentation and a general understanding of how a stack data structure works.
A stack data strucure only has 2 possible operations push/put, which adds something to the collection, and pop, which removes it. Stacks folow a last in first out model, or LIFO, where by last thing added - in your case an activity - is the first thing removed when pop is called.
Within the android lifecycle activities are generally popped from the stack when the back button is pressed. At that point onDestroy() is called and the activity is removed (you can verify this by overriding the onDestroy() method and logging the results if you want to check). Alternativly you can force onDestroy() to be called by calling finish() as you are. Finishing an activity effectivly does the same thing as pressing back. The activity is destroyed and must be recreated before it can be added to the stack.
For what you're trying to do the stack would have to incorporate some intermediate state in which an activity does not exist but rather something akin to a reference is held that, when moved to the top, would indicate that the corresponding activity should be recreated. Since this is not how the sack works - it only holds activities - that state cannont exist and so the result you are talking about is not possible.
Your Goal is to minimize memory usage,Just make use of activity life cycle, You can do this alternative(if you need)
-Just leave onCreate() method blank.(only do setContentView(layout))
-Override onResume();
-whatever you were doing in onCreate just copy paste to onResume().
-and In onPause(), Recycle your all bitmaps and set them to null(I think you are using Bitmaps thats why you are very cautious about it ). and remove your views.
Now what will happen, when you launch your new activity, onPause() would be called. that will remove your all bitmap and views. and when you come back, onResume() will be call.(onCreate will not be called). and that will again initialize your view and bitmaps.
No, i don't think that is possible. Once you finish the Activity it's gone. You could, however, implement and handle your own stack. On back pressed, you would just start the closed Activity again.
I made my project in storyboard in, due to issue with the custom UITableViewCell I have made a new project, copied all of the data to my new classes and copied my buttons, images etc from the storyboard views to new project's nib/xib files.
Now When I click on any button my app crashes without any error and it opens delegate file and highlights this line of code
return UIApplicationMain(argc, argv, nil, NSStringFromClass([ThisOrThatAppDelegate class]));
I have already made connections for the required actions from IB to controller. Also I have tried Command+Shift+K for clean code. But the problem is still there.
You have to find out first what the problem is:
use the Debug build config and are using lldb or gdb
make sure you have a breakpoint on all exceptions
make sure you have the "Breakpoints" button top left enabled.
run the app
You should break into the debugger. You need to get to a point where the debugger catches the exception.
Then edit your question and tell us what exception you get. I'm going to guess you'll be getting a objc_msgSend() error, which means that some object is trying to message a non-existent or dealloced object. If that turns out to be true, then you can enable "Zombies" (which lets all objects stay around) and see if one of those gets messaged.
If nothing seems to help, then what you need to do is start adding NSLog messages to track your app as it comes up (or use breakpoints, your choice). This takes a long time so you might work backwards - see if your appDelegate application:didFinishLaunchingWithOptions: gets called, and also if you get to the end of it.
Unforunately this type of problem can be take a lot of time to track down. Some object has probably queued a message up for another object on the main queue, so when you get the crash you don't get to see who did what when.
Also, with objc_msgSend problems, when the debugger stops you cannot easily see what object was messaged - but if you turn off the debugger and let the app actually crash, you can find the crash report in the Console app and get more info from that.
I have a MonoTouch tab view application. On one of my tabs, when a user clicks a button, I want to show another view. I do this with the following code:
UIView.BeginAnimations("flip");
UIView.SetAnimationDuration(1);
UIView.SetAnimationTransition(UIViewAnimationTransition.FlipFromRight, View, true);
NewFilesViewController newFilesViewController = new NewFilesViewController();
newFilesViewController.View.Frame = new System.Drawing.RectangleF(View.Frame.Top, this.View.Frame.Left, this.View.Frame.Width, this.View.Frame.Height);
View.AddSubview(newFilesViewController.View);
UIView.CommitAnimations();
On the new view, when I click a button, I get an error:
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries
used by your application.
Should I be adding the view to the window instead? Is there a better way to do this?
This is likely (the code does not have enough context to be 100% sure) because newFilesViewController is not referenced anywhere later in the code. As such it can be disposed the next time the Garbage Collector (GC) is invoked. However the native code still except the view to exists and this will crash when it tries to call the (disposed) instance.
Fix: Promote your newFilesViewController local variable to a field. That will keep the reference alive (as long as the type's instance is alive) and the GC won't collect it.
I have been trying to design the Undo/Redo functionality in one of my app using NSUndoManager class and seeing some design difficulties.
In my app, I just have one method
-(IBAction) addLastBall:(Ball *)ball
So, when a user chooses a button in the UI, I add a ball object to my array list. However, I don't have any action button to remove a ball, this is the design of the UI workflow and can't be changed.
So, to implement a undo I called the following piece of code inside the addLastBall method
[undoManager registerUndoWithTarget:self selector:#selector(removeBall:) object:ball];
After doing this, removeBall method gets called with the ball object when the user tried to perform the undo. All is good for now.
But, I am not sure how to handle the redo part now, when the user tries to redo, I am not sure which method would get called, because I need to add the ball object the user just removed using the undo operation.
Any insights would be very helpful.
Thanks so much.
A redo simply performs the undo actions registered while the corresponding undo was executing. Therefore, the most straightforward solution is to simply to register an undo action in the removeBall: method.
- (void)removeBall:(Ball *)ball {
[undoManager registerUndoWithTarget:self
selector:#selector(addLastBall:)
object:ball];
...
}
Note that it is sometimes clearer to useprepareWithInvocationTarget: to register undo actions:
[[undoManager prepareWithInvocationTarget:self] addLastBall:ball];
By the way, be sure to keep the retain count of the ball above zero in the removeBall: method — the undo manager will not retain the ball for you, and if it gets deallocated, then undoing the remove will crash.
No method get's called.
The NSUndoManager simply saves the reverse of the undo operation (redo), that will be done, if the user choses redo.
It's all implemented in NSUndoManager, so you don't have to worry about it.
If you want your method to be called on redo, you should think about creating your own undo manager, but I wouldn't advice you to. It can get very complicated and besides, the NSUndoManager takes care of everything perfectly.