Is MKMapView leaky - iphone

As well as my question "Removing MKMapView Annotations causes leaks." I have discovered that if you create a view based project, add a UISearchBar and MKMapView into the view's NIB, wire up the delegates (I'm not creating any methods as we don't actually need to do anything to trigger the leaks), link in the MapKit and fire up the project, then simply clicking in the UISearchBar causes a 1k+ leak. This doesn't happen unless you have both UISearchBar and MKMapView in a view. I have the same issues when creating the views from code. I thought a NIB might behave differently, but it doesn't.
Is MKMapView leaky, or am I doing something wrong.
To replicate the issue with code try the code below - I created a new "view based application" project
TestMapViewFromCodeViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface TestMapViewFromCodeViewController : UIViewController {
UISearchBar *searchBar;
MKMapView *mapView;
}
#property (nonatomic, retain) MKMapView *mapView;
#property (nonatomic, retain) UISearchBar *searchBar;
#end
TestMapViewFromCodeViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
UISearchBar * tmpSearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0,0.0,self.view.frame.size.width,40.0)];
[self.view addSubview:tmpSearchBar];
[self setSearchBar:tmpSearchBar];
[tmpSearchBar release];
MKMapView *tmpMapView=[[MKMapView alloc] initWithFrame:CGRectMake(0.0,0.0,self.view.frame.size.width,self.view.frame.size.height)];
tmpMapView.showsUserLocation=FALSE;
[self.view insertSubview:tmpMapView atIndex:0];
[self setMapView:tmpMapView];
[tmpMapView release];
}
- (void)dealloc {
[mapView release];
[searchBar release];
[super dealloc];
}
Although I've retained the subviews with mapView and searchBar, this is probably unnecessary to replicate the issue.
In testing this code prior to publishing here I've just noticed that this leak does not occur in the simulator - only on my phone...

Yes.
There is a known leaks on 3.0's MKMapViews. The leak occurs when you deallocate the MKMapView This is fixed in later releases. The workaround is to have a single MKMapView and reuse it.
https://devforums.apple.com/message/129740#129740

For what its worth, there are similar related questions here:
https://stackoverflow.com/questions/5935243/mkmapview-rame-et-fuite-memoire-apple
Can the memory used by MKMapView be released some how?
MKMapView Memory Leak in iPhone Application

Related

glkView drawInRect not called

I am learning OpenGLES and I am trying to put a GLKViewer inside an UIViewController.
I know I can come around the main issues by using GLViewController, but I am trying to learn how to do it this way.
I found this question, Nesting GLKView into UIViewController and Nested GLKView and GLKViewController but I must be missing something even though I think I am doing all the right steps because when I run my project, I am not getting to the drawInRect print line.
In the storyboard I am pointing the ViewController as the delegate of the glkview component.
I tried to keep the code as simple as possible and any help will be apreciated:
MyController.h
#import <Foundation/Foundation.h>
#import <GLKit/GLKit.h>
#interface MyGLController : UIViewController <GLKViewDelegate>
{
GLuint vertexBufferID;
}
#property (weak, nonatomic) IBOutlet GLKView *glview;
#property (strong, nonatomic) GLKBaseEffect *baseEffect;
#end
MyGLController.m
#import "MyGLController.h"
#implementation MyGLController
//#synthesize baseEffect;
-(void) viewDidLoad{
[super viewDidLoad];
self.glview.context = [[EAGLContext alloc] initWithAPI:
kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:self.glview.context];
printf("View Loaded");
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
printf("DrawInRect");
}
#end
* Update *
As far as I can tell the glkview is hooked up properly as suggested per and added the josh-knapp and called setNeedsDisplay.
In case there's something I am missing, I have uploaded a copy of the project here: https://github.com/jcrogel/OpenGLDebug.git
I am a total noob in this so I apologize for any silly oversight :)
You didn't say you hooked up the glview property of MyGLController in the storyboard, so verify that.
Next, you're setting up the glview context after it loads. Without a GLKViewController, there is nothing telling the glview it needs to be drawn. Make sure you call [self.glview setNeedsDisplay] somewhere after the context is set up.
I had a similar problem.
By default, xcode sets the enable setNeedsDisplay checkbox to NO in GLKView property list.
Once I changed it, it worked.
I see this question was already answered. But I had the same problem, with a different solution. I figured I'd post the info here on the off chance others might be able to benefit from it.
Problem Description
While using GLKView and GLKViewController, the render loop function (drawInRect) is called once, but not called again.
Possible Cause
Some methods to CViewController have been implemented incorrectly, without calling their supers. The following code illustrates three such functions. The examples below have the three functions implemented correctly, calling their supers.
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:NO];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:NO];
}
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:NO];
}

iOS6 and automatic view unloading

Update:
To clarify the context of the question; the question is not on how to avoid the problem, but to clarify what the piece of documentation means, as my experiment suggests that the views I was expecting to unload, based on the documentation, are not unloading. I would like to understand if this is a bug, or if I am misunderstanding the documentation. To solve the problem instead, I know that setting the images in viewWillAppear instead of viewDidLoad, and setting the images to nil in viewDidDisappear, is releasing the memory and the app doesn't crash. However, I would like to understand if the memory should have been released with the initial code, as the experiment is to simulate having such view controllers as outlets, and setting your UI images (backgrounds...) in Interface Builder, instead of setting them in code in viewWillAppear...
Original:
I am trying to understand some new aspect of iOS6, as documented in the View Controller Programming Guide:
On iOS 6 and Later, a View Controller Unloads Its Own Views When Desired
The default behavior for a view controller is to load its view hierarchy when the view property is first accessed and thereafter keep it in memory until the view controller is disposed of. The memory used by a view to draw itself onscreen is potentially quite large. However, the system automatically releases these expensive resources when the view is not attached to a window. The remaining memory used by most views is small enough that it is not worth it for the system to automatically purge and recreate the view hierarchy.
Let's say I am creating a simple app, with a rootViewController.
This rootViewController has a few child View Controllers, all declared as IBOutlets instead of being allocated in code.
#property(nonatomic,strong) IBOutlet ChildViewController *childViewController1;
#property(nonatomic,strong) IBOutlet ChildViewController *childViewController2;
#property(nonatomic,strong) IBOutlet ChildViewController *childViewController3;
#property(nonatomic,strong) IBOutlet ChildViewController *childViewController4;
#property(nonatomic,strong) IBOutlet ChildViewController *childViewController6;
#property(nonatomic,strong) IBOutlet ChildViewController *childViewController7;
#property(nonatomic,strong) IBOutlet ChildViewController *childViewController8;
#property(nonatomic,strong) IBOutlet ChildViewController *childViewController9;
#property(nonatomic,strong) IBOutlet ChildViewController *childViewController10;
The rootViewController has a few buttons, pressing each of those does a simple presentModalViewController operation on each childViewController
-(IBAction)showChild1Action:(id)sender{
[self presentModalViewController:self.childViewController1 animated:true];
}
Each childViewController has a close button that dismisses the child view controller.
-(IBAction)closeAction:(id)sender{
[self dismissModalViewControllerAnimated:true];
}
My expectation from the documentation was that the child view controller view objects would be released from memory, as the child view controllers are dismissed.
However I purposely tested with large view objects, and running profile on such an app, the memory usage just keeps growing as each child controller gets presented, and the app eventually crashes after I present child controller #7 or so.
What is your understanding of what has changed in iOS6 in that aspect?
RootViewController.h
#import <UIKit/UIKit.h>
#import "ChildViewController.h"
#interface RootViewController : UIViewController
#property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController1;
#property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController2;
#property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController3;
#property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController4;
#property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController5;
#property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController6;
#property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController7;
#property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController8;
#property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController9;
#property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController10;
-(IBAction)showChild1Action:(id)sender;
-(IBAction)showChild2Action:(id)sender;
-(IBAction)showChild3Action:(id)sender;
-(IBAction)showChild4Action:(id)sender;
-(IBAction)showChild5Action:(id)sender;
-(IBAction)showChild6Action:(id)sender;
-(IBAction)showChild7Action:(id)sender;
-(IBAction)showChild8Action:(id)sender;
-(IBAction)showChild9Action:(id)sender;
-(IBAction)showChild10Action:(id)sender;
#end
RootViewController.m
#import "RootViewController.h"
#interface RootViewController ()
#end
#implementation RootViewController
#synthesize level2ViewController1;
#synthesize level2ViewController2;
#synthesize level2ViewController3;
#synthesize level2ViewController4;
#synthesize level2ViewController5;
#synthesize level2ViewController6;
#synthesize level2ViewController7;
#synthesize level2ViewController8;
#synthesize level2ViewController9;
#synthesize level2ViewController10;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
-(IBAction)showChild1Action:(id)sender{
self.level2ViewController1.index=0;
[self presentModalViewController:self.level2ViewController1 animated:true];
}
-(IBAction)showChild2Action:(id)sender{
self.level2ViewController2.index=1;
[self presentModalViewController:self.level2ViewController2 animated:true];
}
-(IBAction)showChild3Action:(id)sender{
self.level2ViewController3.index=2;
[self presentModalViewController:self.level2ViewController3 animated:true];
}
-(IBAction)showChild4Action:(id)sender{
self.level2ViewController4.index=3;
[self presentModalViewController:self.level2ViewController4 animated:true];
}
-(IBAction)showChild5Action:(id)sender{
self.level2ViewController5.index=4;
[self presentModalViewController:self.level2ViewController5 animated:true];
}
-(IBAction)showChild6Action:(id)sender{
self.level2ViewController6.index=5;
[self presentModalViewController:self.level2ViewController6 animated:true];
}
-(IBAction)showChild7Action:(id)sender{
self.level2ViewController7.index=6;
[self presentModalViewController:self.level2ViewController7 animated:true];
}
-(IBAction)showChild8Action:(id)sender{
self.level2ViewController8.index=7;
[self presentModalViewController:self.level2ViewController8 animated:true];
}
-(IBAction)showChild9Action:(id)sender{
self.level2ViewController9.index=8;
[self presentModalViewController:self.level2ViewController9 animated:true];
}
-(IBAction)showChild10Action:(id)sender{
self.level2ViewController10.index=9;
[self presentModalViewController:self.level2ViewController10 animated:true];
}
#end
ChildViewController.h
#import <UIKit/UIKit.h>
#interface ChildViewController : UIViewController
#property(nonatomic,weak) IBOutlet UIImageView *image1;
#property NSInteger index;
-(IBAction)closeAction:(id)sender;
#end
ChildViewController.m
#import "ChildViewController.h"
#interface ChildViewController ()
#end
#implementation ChildViewController
#synthesize image1;
#synthesize index;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
if(self.index==0)
[self.image1 setImage:[UIImage imageNamed:#"IMG1.JPG"]];
if(self.index==1)
[self.image1 setImage:[UIImage imageNamed:#"IMG2.JPG"]];
if(self.index==2)
[self.image1 setImage:[UIImage imageNamed:#"IMG3.JPG"]];
if(self.index==3)
[self.image1 setImage:[UIImage imageNamed:#"IMG4.JPG"]];
if(self.index==4)
[self.image1 setImage:[UIImage imageNamed:#"IMG5.JPG"]];
if(self.index==5)
[self.image1 setImage:[UIImage imageNamed:#"IMG6.JPG"]];
if(self.index==6)
[self.image1 setImage:[UIImage imageNamed:#"IMG7.JPG"]];
if(self.index==7)
[self.image1 setImage:[UIImage imageNamed:#"IMG8.JPG"]];
if(self.index==8)
[self.image1 setImage:[UIImage imageNamed:#"IMG9.JPG"]];
if(self.index==9)
[self.image1 setImage:[UIImage imageNamed:#"IMG10.JPG"]];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-(IBAction)closeAction:(id)sender{
[self dismissModalViewControllerAnimated:true];
}
When using Instruments I get these observations:
The memory allocation instrument is showing what I would expect to see: total allocation that goes up when child view controller is presented, goes down when child view is dismissed
However the activity indicator is telling a different story, with real memory increasing with every presentModalViewController, and never decreasing when dismissing them
The answer I eventually got back from Apple:
Your "large resources" happen to be images that you've loaded cached
via +imageNamed:. Because they are loaded cached, they are exempted
from the automatic cleanup. Generally only content generated via
-drawRect: or by Core Animation is automatically released here. Because your views continue to exist, they continue to hold a
reference to these cached images, and we can't purge them on memory
warning either
Looks like cached resource isn't part of the automatic cleanup mentioned in the doc, and those resources only get deallocated when they stop being referenced.
Sounds like you have a leak somewhere. Even if the system isn't releasing those views, memory use should max out after you've presented all 10 child controllers. If memory use grows without bound, your child controllers are probably giving up their views (and so creating new ones each time they're presented), but the views aren't being deallocated -- classic symptom of an over-retain situation. Try cutting the number of child controllers down to two and see if the same thing eventually happens. Or, use Instruments to look for a leak.
Update: -[UIImage imageNamed] has a reputation for never releasing the images it loads -- that may be the reason for your memory growth. Try loading the images using a different method, or not at all (since they're not really important to the experiment).
Instead of using imageNamed: use initWithContentsOfFile.
For example:
__weak NSString *filePath = [[NSBundle mainBundle] pathForResource:#"image" ofType:#"png"];
self.imageView.image = [[UIImage alloc] initWithContentsOfFile:filePath];
Because alloc method is being used, GC is marking this object. You can even mark the filePath string for GC cleanup.

Memory Management: Is insertSubview retaining it's views?

The question is if insertSubview is retaining the views and if I'm doing it right.
I would say yes. Since I'm not using the property anymore I don't receive an EXC_BAD_ACCESS. I think when releasing the view all subviews are also released. And so mapView is over-released. I'm right or do I still have a memory management issue?
My ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController <MKMapViewDelegate> {
MKMapView *mapView;
// ...
}
//#property (nonatomic, retain) MKMapView *mapView;
// ...
#end
My ViewController.m
#import "MapViewController.h"
#implementation MapViewController
//#synthesize mapView;
- (void)viewDidLoad {
[super viewDidLoad];
//self.mapView=[[[MKMapView alloc] initWithFrame:self.view.bounds] autorelease];
mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
[self.view insertSubview:mapView atIndex:0];
[mapView release];
// ...
}
- (void)dealloc {
//[mapView release];
[super dealloc];
}
#end
- (void)dealloc {
//[mapView dealloc];
[super dealloc];
}
You should never call dealloc directly (save for [super dealloc]; at the end of the method). That will most assuredly cause a crash in most situations.
Since that isn't the source of your crash, you have an over-release somewhere. Use Instrument's Zombie Detection to figure out where.
Yes, you are correct on all counts:
the call to insertSubView: should be retaining the mapView that you are passing it.
releasing your reference to the mapView after you add it to the parent view
the parent view will release all the retained subviews when it is released
As a rule, you should not worry about whether or how another object will retain an instance you give it. That's up to that object to deal with; you only have to worry about making sure an instance that you intend to directly access later is retained. Don't rely on another object to keep an instance retained for you.
In your example, you have an instance (mapView) which is accessible to MapViewController but MapViewController does not have it's own retention for it. self.view could release mapView at any time for any number of reasons and you'd suddenly have bad memory there.

Sharing a UIView between UIViewControllers in a UITabBarController

I have a UIScrollView that houses a gallery of images the user can scroll through. This view needs to be visible on each of three separate UIViewControllers that are housed within a UITabBarController. Right now, I have three separate UIScrollView instances in the UITabBarController subclass, and the controller manages keeping the three synchronized (when a user scrolls the one they can see, programmatically scrolling the other two to match, etc.), which is not ideal.
I would like to know if there is a way to work with only ONE instance of the UIScrollView, but have it show up only in the UIViewController that the user is currently interacting with. This would completely eliminate all the synchronization code. Here is basically what I have now in the UITabBarController (which is where all this is currently managed):
#interface ScrollerTabBarController : UITabBarController {
FirstViewController *firstView;
SecondViewController *secondView;
ThirdViewController *thirdView;
UIScrollView *scrollerOne;
UIScrollView *scrollerTwo;
UIScrollView *scrollerThree;
}
#property (nonatomic,retain) IBOutlet FirstViewController *firstView;
#property (nonatomic,retain) IBOutlet SecondViewController *secondView;
#property (nonatomic,retain) IBOutlet ThirdViewController *thirdView;
#property (nonatomic,retain) IBOutlet UIScrollView *scrollerOne;
#property (nonatomic,retain) IBOutlet UIScrollView *scrollerTwo;
#property (nonatomic,retain) IBOutlet UIScrollView *scrollerThree;
#end
#implementation ScrollerTabBarController
- (void)layoutScroller:(UIScrollView *)scroller {}
- (void)scrollToMatch:(UIScrollView *)scroller {}
- (void)viewDidLoad {
[self layoutScroller:scrollerOne];
[self layoutScroller:scrollerTwo];
[self layoutScroller:scrollerThree];
[scrollerOne setDelegate:self];
[scrollerTwo setDelegate:self];
[scrollerThree setDelegate:self];
[firstView setGallery:scrollerOne];
[secondView setGallery:scrollerTwo];
[thirdView setGallery:scrollerThree];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self scrollToMatch:scrollView];
}
#end
The UITabBarController gets notified (as the scroll view's delegate) when the user scrolls one of the instances, and then calls methods like scrollToMatch: to sync up the other two with the user's choice.
Is there something that can be done, using a many-to-one relationship on IBOutlet or something like that, to narrow this down to one instance so I'm not having to manage three scroll views? I tried keeping a single instance and moving the pointer from one view to the next using the UITabBarControllerDelegate methods (calling setGallery:nil on the current and setGallery:scrollerOne on the next each time it changed), but the scroller never moved to the other tabs.
Thanks in advance!
Certainly you should use only one instance of your scroller view. And it will works fine without any troubles. Use method setGallery: like you did, just ensure you add your singleScrollerForAll view to view of current controller in setGallery method:
-(void)setGallery:(UIView *)aScrollerView{
[self.view addSubview:aScrollerView];
}
and call:
[firstView setGallery:singleScrollerForAll];
or
[secondView setGallery:singleScrollerForAll];
and no need to do anything in other two controllers, because when you call addSubview: the subView will be automatically removed from previous superview.

UITextField Memory Leak

In my code, there is an memory leak, when the Keyboard appears for the first time when I am about to enter values in the UITextField. Can someone please give me some idea about this.
In the Interface File
IBOutlet UITextField *userEmail;
#property (nonatomic, retain) IBOutlet UITextField *userEmail;
Implementation File
#synthesize userEmail;
- (void)dealloc
{
[userEmail release];
}
- (void)viewDidUnload
{
self.userEmail = nil;
}
-(IBAction) emailOver:(id)sender{
[sender resignFirstResponder];
}
In the one of the functions NSLog(#"User Email: %#",[userEmail text]); Memory Leak occurs when the keyboard appears for the first time Do I have implement UITextFieldDelegate? Thanks
Consider that there's a bug in the iPhone simulator: if you write an almost empty project, putting only a UITextField in the XIB, and no code, you'll have a leak when you tap on the UITextField. On the contrary, if you try to build and run on the device, you'll have no leak. So It may be your case!! Give it a try, and let us know..
One problem is that your dealloc method is missing the MANDATORY [super dealloc] line.
- (void)dealloc
{
[userEmail release];
[super dealloc];
}
You don't need IBOutlet defined twice. One or the other should do.
UITextField *userEmail;
#property (nonatomic, retain) IBOutlet UITextField *userEmail;
I don't see anything else in your code that would cause a problem. What other methods do you have in your #implementation file.
I think you're right caprosky. Using a very simple test project I've Run With Monitoring Tools -> Leaks and as soon as I click on UITextField there is a memory leak that rises continuously.
I'll forget this for now and keep it in mind next time I'm using a UITextField (no