Errors of key value observers and NSKVODeallocateBreak - uiscrollview

I'm implementing a UITableView as a first level view controller that contains 5 table cells. Hitting on any of these cells will present a second level view. At the top left of this level view, there is a "back" button to return to the first level view. At the second level view, swiping left or right will show adjacent views continuously that link to those adjacent table cells at the first level view.
After running, from first level view to second level view it's ok. But when hitting the "back" button, going back to first level view from second level view, the following is the issue I got.
An instance 0x7a8f130 of class UIScrollView was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object.
Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger.
Here's the current observation info: (
Context: 0x0, Property: 0x9149570>
)
I found
- (void)viewDidUnload
{
[super viewDidUnload];
[self.scrollView removeObserver:self forKeyPath:#"frame"];
[self.scrollView removeFromSuperview];
_scrollView = nil;
}
in the GDIInfinitePageScrollViewController.m that I'm using to implement an infinite scroll view controller. When I commented this out, the issue is still there.
when I set breakpoint NSKVODeallocateBreak, here is what I got
0x1170ae0: pushl %ebp
but I have no idea about what it means.
Does anyone know how to fix this issue?

The reason you are getting that message is because the UIScrollView instance is being released before its observers are removed.
The method -(void) viewDidUnload is called when the view has already been released, so that call to remove the observer is too late. In addition, this has been deprecated with iOS 6, along with -(void) viewWillUnload.
As an alternative, try removing the observer when hitting the back button.

replacing - (void)viewDidUnload with - (void)viewWillDisappear worked for me

Related

Clear memory of previous ViewControllers when using modal segues?

I've been working a photo editing app that takes pictures and passes it on to the
next view controller.
Of course I use AVSession to have the camera preview shown.
When the picture is taken the current view controller passes the image on to the view controller that has all the editing features.
I use modal segues to control transition between views.
The Problem is that when the segue happens there is a increase in memory by 4mb that never gets released.
Viewcontoller-->EditorViewcontoller
EdiorViewcontroller-->Viewcontroller
I also have a segue from the editor to camera,again there is a accumulation of memory.
A few times back and forth and the app crashes.
I can't post picture due to lack of reputation.
How can I clean the memory of the previous Viewcontroller and just have the current view controller running.
Things I've tried
*setting all the instances to nil.
*dismissing the view controller.
*setting the entire view controller to nil.
*profiled it.
*using #autorealease.
*spent hours on the internet searching for a solution.
I use this line of code to perform the segue.
[self performSegueWithIdentifier:#"effectsegue" sender:self];
I even tried using a weak self hoping it might help.
__weak ViewController *weakself=self;
[weakself performSegueWithIdentifier:#"effectsegue" sender:self];
When I profile it,it tells me these lines of code
NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
and
[self performSegueWithIdentifier:#"effectsegue" sender:self];
are taking memory.
I would like some suggestions and idea as to what can be done to clear memory of previous view controller and free memory,any other alternates other than segues.
I've been working on this for weeks and this is really not allowing me to proceed forward.
Thanks in advance.
If you're using storyboards and ARC you can create a button inside EditorViewcontroller (that you'll use to go back to Viewcontroller) and link it to the following action on your EditorViewcontroller.m file:
- (IBAction)goBack:(UIButton *)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
This should release the memory used by EditorViewcontroller

self.tableView reloadData not working in viewWillAppear

I have an Xcode app that creates a tableview and then populates this with data from an sqlite database, this works perfectly and allows me to push data to a new view and delete etc,
This tableview is the first view loaded on a tab bar controller. The problem arises when i move to another view on the same controller, i.e. create an athlete, in this view i can add a new athlete to the database (which works fine) but when i go back to the tableview on the tab bar controller, the table is the same, i have to log out and log back in to see the change in the table,
I have tried [self.tableView reloadData] in the viewWillAppear function but this does nothing. I know that the function is getting called as i have placed an NSLog in their just for peace of mind.
I have found what i think may be the solution on here but i cant get it to work!
viewWillAppear, viewDidAppear not being called, not firing
i will post my code below and a screen shot of the storyboard as im convinced it is my poor way of setting up controllers that has caused this error. Any help would be much appreciated as i am now at the meltdown stage :D
-(void)viewWillAppear:(BOOL)animated {
//[super viewWillAppear:animated];
//[self.tabBarController viewWillAppear:animated];
[self.tableView reloadData];
NSLog(#"i just ran viewwillAppear");
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
athleteObject *athObj3 = [athletes objectAtIndex:indexPath.row];
athleteIdDelete = athObj3.athId;
[self openDatabase];
[self deleteAthleteFromDataBase];
[athletes removeObjectAtIndex:indexPath.row];
[tableView reloadData];
}
reloadData works in my commitEditing function (this updates the tableview when i delete an entry via a swipe)
any help would be much appreciated, il post the screen shot below.
(cant figure out how to load a screenshot if its even possible)
It looks like athletes (a NSMutableArray I assume) is not being updated in viewWillAppear. Have you tried running the selector that populates the array from the database before calling reloadData?
Hope that helps!
I'm assuming you're setting the number of rows/sections in your code based on how many objects are returned from a database.
Set a breakpoint at this method, and get the count each time the compiler breaks. You are probably not getting any objects from the database, and therefore the compiler never runs the rest of the table view dataSource methods.

Cocoa ignore clicks but still register them?

Is it possible to have a click-through window in cocoa (as in _window.ignoreMouseEvents = TRUE), but still find out when the mouse has been clicked above the window? Or, instead of ignoring the events, registering them, and then somehow forwarding them, propagating them to whatever is behind the window?
I guess what you are looking for is the NSView method hitTest.
This method is called on every view when a mouse click is received.
- (NSView*)hitTest:(NSPoint)aPoint
{
return self;
}
Returning self would mean that the click is not forwarded to the next subviews.
Returning [super hitTest] would just forward the click to the parent view of your view hierarchy. Using this, you could simply register clicks without anything else happening.
So something like:
- (NSView*)hitTest:(NSPoint)aPoint
{
[self propagateEventToNextApplication];
return [super hitTest:aPoint];
}
Hope this helps!

Return for the first view after I'm on the fifth view of an iOS application in Xcode

I'm fairly new to xcode, and am creating a single view application with five views (xib files). I am not using navigation controller or storyboard for two reasons.
If I use Storyboard, I am forced to have my other views be UIView files. These dont have
-(void)viewDidLoad
Which prevents me from loading a few timers I have in my application.
I am able to navigate from the first page to the second and so on, all the way to the fifth page/view with the following code.
-(IBAction)pagethree {
countdown=[[Countdown alloc] initWithNibName:#"Countdown" bundle:nil];
[self.view addSubview:countdown.view];
}
However when I want to go back from the fifth view to the first page I run into a problem.
My first view is called ViewController. If I try the code from above, my app is full of errors.
I also tried using
-(IBAction)back {
[self.view removeFromSuperview];
}
but that only took me back one view.
My fifth view controller is called Statistics and the first one is called ViewController.
What can I code to get from back from the last view to the first?
Thanks
First, to answer your question, you need to do a removeFromSuperview (or similar) for each addSubview: you did. Each time you do addSubview, you're placing your new screen "on top" of the last one, like a stack. When you reach your 5th view, you have 4 other views "behind" it. (Actually, that's not exactly what addSubview does, but I'm just describing the effect in your particular situation).
But I think you're doing it wrong... You should read more about storyboards and navigation controllers. Both are used with UIViewController and support out of the box what you're trying to do by hand. For example, using a navigation controller, to push a new view controller you can do:
[navigationController pushViewController:viewController animated:YES];
You can do that as many times as you want. Then, to go back once, you do:
[navigationController popViewControllerAnimated:YES];
And to go back directly to the first one:
[navigationController popToRootViewControllerAnimated:YES];
Hope this helps.

Drill down tableview in storyboards

I am trying to make a drill down table with storyboards in a Tab bar app.
I am having a problem with working out how to get each row in a main table to point to other different tables.
This is the code I have used to detect row selection.
-(void)tableView: (UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *__strong)indexPath {
TableViewController *table = [self.storyboard instantiateViewControllerWithIdentifier:#"table"];
[self.navigationController pushViewController:table animated:YES];
}
How do I proceed please?
The real beauty to UIStoryBoards are the segues.
1. You can link one prototype cell push segue to another different table view controller
2. You can link one prototype cell push segue loop back to itself for drill downs.
[self performSegueWithIdentifier:#"segueID" sender:MyObject];
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"segueID"]) segue.destinationViewController.chosenCell = sender;
}
If the segue is from the cell click, the sender is that of the cell and you can get it's indexpath from the table, and pass new information to the upcoming view controller.
If you want the cell to take various paths when clicked, keep the didSelectRowAtIndexPath and call performSegueWithIndetifier so you can choose left or right.
Tutorial: http://jleeiii.blogspot.com/2012/05/uistoryboard-power-drill-batteries.html
GitHub: http://www.github.com/jllust/UIStoryboardExamples
I was extremely frustrated with this, as the storyboards with tableviews is really not covered ANYWHERE. I literally almost pulled my hair out trying to figure this out. So my frustration is your luck!
Comparing your code to mine, yours looks fine other than the fact that in the initial didSelectRowAtIndexPath: method, you have *_strong, which should not have the _strong part. It should just be like this: (NSIndexPath *)indexPath {
Additionally, be careful in when you are referring to the instantiateViewControllerWithIdentifier in Interface Builder. I accidentally filled out the name of the instance variable under 'TITLE' instead of 'IDENTIFIER'
I hope this helps. I completely understand your frustration.
In your storyboard, if the content is Static Cells, you can ctrl-drag from the specific row to a Navigation Controller. Then connect the Navigation Controller to your next table. Look at this screen shot. http://cl.ly/1V2y0v202y390U0A351x
My guess is that progromatically, you'll need to do something similar, segue to a NavigationController which has a table view controller as it's root view.

Resources