every time i make a request to my web server via NSURLSession/Connection it leaks! To be honest it is not much but if you have to make a couple hundreds or thousands of calls this gets nasty.
I have been on this for about a week now. I have tried everything. NO cache , little cache, setting everything on nil after the call is done(which is unnecessary), using datatask for sessions or just connection with requests. Every time i get a little more memory allocated and i have not found a way to solve this problem.
So i set up a little testApp:
#import "ViewController.h"
#interface ViewController ()
#property NSString *param;
#property NSURL * url;
#property NSURLConnection *test;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.param = [NSString stringWithFormat:#"hi"];
self.url = [[NSURL alloc]initWithString:#"http://127.0.0.1/xmlfile.php"];
for (int i = 0; i<20000; i++){
[self connect:self.param url:self.url];
}
NSLog(#"I AM DONE!");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSData *)connect:(NSString*)param url:(NSURL*)url{
self.test = [[NSURLConnection alloc]initWithRequest:nil delegate:self];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
return nil;
}
#end
i would love to add images of the memory usage but i am too new.
so just go here:
5k:iterations
http://i59.tinypic.com/123tts2.png
20k:
http://i59.tinypic.com/1zzqsrk.png
I have heard that this could be a problem with ios8.
Please help!
I am open for everything and would be happy if someone could prove me wrong and show me the right way. Thanks a bunch
You're never actually turning your URL into a request and giving it to the NSURLConnection. Because of that, the connection will never complete, and its memory will stay allocated. You'll find a world of difference with the above code if you add this to your connect:url: method:
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:url];
...and pass that into your NSURLConnection so it actually does something:
self.test = [[NSURLConnection alloc]initWithRequest:request delegate:self];
...because then, as soon as the connection finishes doing its work—successfully or otherwise—its memory will be deallocated.
Related
i dont know what is wrong with code below
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray * buttons;
NSMutableArray * centers;
int counter;
int index;
}
#end
#implementation ViewController
-(void)viewDidLoad
{
[super viewDidLoad];
buttons = [NSMutableArray new];
centers = [NSMutableArray new];//error here expected identifier or '('
}
//other methods
#end
i am getting two arrays, xcode works normally for buttons but it gives error for centers when creating. What may be the problem?
note: i tried deleting derived data.
Okay, I know this isn't the question you asked, but I would like to suggest an alternative to instantiating variables in viewDidLoad. It's something called "lazy instantiation", and it looks like this:
- (NSMutableArray *)buttons
{
if (!_buttons) _buttons = [NSMutableArray new];
return _buttons;
}
When you need to reset the array, just set it to nil. It won't reallocate the memory until you call it again.
P.S. Whatever you do, don't call self.buttons within that method, or you will create an infinite loop.
Just came across a bug in MapKit, wanted to see what the community is experiencing. When adding a MKUserTrackingBarButtonItem to a UIToolBar, I'm seeing the map is not releasing from memory when switching to another viewController (though I see the dealloc is firing).
Can anyone confirm they are seeing this behavior? My testing shows the map releases properly if I do not add MKUserTrackingBarButtonItem. Using iOS7, testing with Instruments/Leaks.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
MKUserTrackingBarButtonItem *userTrackingBarButtonItem = [[MKUserTrackingBarButtonItem alloc] initWithMapView:self.mapView];
[userTrackingBarButtonItem setAction:#selector(track:)];
UIBarButtonItem *flexibleSpaceBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[self setToolbarItems:[NSArray arrayWithObjects:flexibleSpaceBarButton, userTrackingBarButtonItem, flexibleSpaceBarButton, nil] animated:YES];
[self.navigationController setToolbarHidden:NO animated:NO];
}
MKUserTrackingBarButtonItem and the MKMapView each hold strong references to each other, resulting in a circular retain. This appears to be a bug in MapKit itself, and it's still present in iOS 7.1.
A solution is to add a dealloc to your view controller that contains the MapView:
-(void)dealloc
{
userTrackingBarButtonItem.mapView = nil; // Circular reference bug workaround
}
I want to add a KVO observation that removes itself after it fires once. I have seen lots of folks on StackOverflow doing stuff like this:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:#"myKeyPath"])
{
NSLog(#"Do stuff...");
[object removeObserver:self forKeyPath:#"isFinished"];
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
This seems plausible, but I'm aware that calling -removeObserver:forKeyPath: from within -observeValueForKeyPath:... can be lead to non-deterministic crashes that are hard to debug. I also want to be sure this observation only gets called once (or not at all if the notification is never sent). What's a good way to do this?
I'm answering my own question here because I've seen the pattern in the question all over the place, but haven't had a reference to a good example of a better way. I've lost days, if not weeks, of my life to debugging problems ultimately found to be caused by adding and removing observers during the delivery of KVO notifications. Without warranty, I present the following implementation of a one-shot KVO notification that should avoid the problems that come from calling -addObserver:... and -removeObserver:... from inside -observeValueForKeyPath:.... The code:
NSObject+KVOOneShot.h:
typedef void (^KVOOneShotObserverBlock)(NSString* keyPath, id object, NSDictionary* change, void* context);
#interface NSObject (KVOOneShot)
- (void)addKVOOneShotObserverForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context block: (KVOOneShotObserverBlock)block;
#end
NSObject+KVOOneShot.m: (Compile with -fno-objc-arc so we can be explicit about retain/releases)
#import "NSObject+KVOOneShot.h"
#import <libkern/OSAtomic.h>
#import <objc/runtime.h>
#interface KVOOneShotObserver : NSObject
- (instancetype)initWithBlock: (KVOOneShotObserverBlock)block;
#end
#implementation NSObject (KVOOneShot)
- (void)addKVOOneShotObserverForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context block: (KVOOneShotObserverBlock)block
{
if (!block || !keyPath)
return;
KVOOneShotObserver* observer = nil;
#try
{
observer = [[KVOOneShotObserver alloc] initWithBlock: block];
// Tie the observer's lifetime to the object it's observing...
objc_setAssociatedObject(self, observer, observer, OBJC_ASSOCIATION_RETAIN);
// Add the observation...
[self addObserver: observer forKeyPath: keyPath options: options context: context];
}
#finally
{
// Make sure we release our hold on the observer, even if something goes wrong above. Probably paranoid of me.
[observer release];
}
}
#end
#implementation KVOOneShotObserver
{
void * volatile _block;
}
- (instancetype)initWithBlock: (KVOOneShotObserverBlock)block
{
if (self = [super init])
{
_block = [block copy];
}
return self;
}
- (void)dealloc
{
[(id)_block release];
[super dealloc];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
KVOOneShotObserverBlock block = (KVOOneShotObserverBlock)_block;
// Get the block atomically, so it can only ever be executed once.
if (block && OSAtomicCompareAndSwapPtrBarrier(block, NULL, &self->_block))
{
// Do it.
#try
{
block(keyPath, object, change, context);
}
#finally
{
// Release it.
[block release];
// Remove the observation whenever...
// Note: This can potentially extend the lifetime of the observer until the observation is removed.
dispatch_async(dispatch_get_main_queue(), ^{
[object removeObserver: self forKeyPath: keyPath context: context];
});
// Don't keep us alive any longer than necessary...
objc_setAssociatedObject(object, self, nil, OBJC_ASSOCIATION_RETAIN);
}
}
}
#end
The only potential hitch here is that the dispatch_async deferred removal may marginally extend the lifetime of the observed object by one pass of the main run loop. This shouldn't be a big deal in the common case, but it's worth mentioning. My initial thought was to remove the observation in dealloc, but my understanding is that we don't have a strong guarantee that the observed object will still be alive when the -dealloc of KVOOneShotObserver is called. Logically, that should be the case, since the observed object will have the only "seen" retain, but since we pass this object into API whose implementation we can't see, we can't be completely sure. Given that, this feels like the safest way.
This is the follow up to my question earlier about the Xcode 4 static analyzer. It is not specifically a problem since I have the code now working as it needs to, but I am just wondering how things are working behind the scenes. Consider the following code:
- (IBAction)cameraButtonPressed:(id)sender
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == NO)
{
return;
}
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraUI.allowsEditing = NO;
cameraUI.delegate = self;
[self presentModalViewController:cameraUI animated:YES];
NSString *theString = [[NSString alloc] initWithString:#"cameraButtonPressed done"];
NSLog(#"%#", theString);
}
To me, the way this code looks, there are two objects (cameraUI and theString) that need to be released. However, the analyze function correctly identifies that only theString needs to be released at the end of the method, even though both objects are returned from alloc-init, which in my experience has always meant that you release when you are done.
The question I have here is, how does the static code analyzer know not to flag cameraUI as an issue?
I would call this a bug with the static analyzer. The UIImagePickerController instance assigned to cameraUI should be released or autoreleased in a non-garbage-collected environment (like iOS).
I have the following problem making me crazy.
My app has to play a tick sound every second for a specified number of times (e.g. 5) after the user has pressed a button.
I used this:
for (int w=1; w<=5; w++) {
[NSThread detachNewThreadSelector:#selector(tic) toTarget:self withObject:nil];
[NSThread sleepForTimeInterval:1.0];
}
where:
- (void)tic {
NSAutoreleasePool *ticPool = [[NSAutoreleasePool alloc] init];
player_tic = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:#"tick" ofType:#"aif"]] error:nil];
[player_tic setDelegate:self];
[player_tic play];
[ticPool drain];
}
and:
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *)player_tic successfully:(BOOL)flag {
NSLog(#"Audio finished playing.");
[player_tic release];
}
All seems to work. My problem is that the object are released together at the end.
I need that after every played sound the related 'player_tic' has to be released immediately.
Other Info:
In .m:
#synthesize player_tic;
In .h:
#interface myController : UIViewController {
...
AVAudioPlayer *player_tic;
}
#property (nonatomic, retain) AVAudioPlayer *player_tic;
On top of all, I have this warning in compilation:
local declaration of 'player_tic' hides instance variable
Please help me!
Thank you very much in advance.
--Carlo
I found System Sound Services more responsive than AVAudioPlayer.
It also solves your release problem, which is caused by the retain property of your controller. Read the reference manual on memory management for further information on retain/release.
I think you want to use self.player_tic when setting that variable, and i believe you also want to autorelease that instance. I'm not sure that setting up a separate NSAutoreleasePool is necessary either.
self.player_tic = [[[AVAudioPlayer alloc] initWithContentsOfURL:... error:nil] autorelease]