Issue with allocating object and releasing ios - ios

I have a memory leak with below code.
Where self.firstURLConn is #property(nonatomic, retain).
NSMutableURLRequest* req = [[NSMutableURLRequest alloc] initWithURL:urlcachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60.0f];
self.firstURLConn = [[[NSURLConnection alloc] initWithRequest:req delegate:self] autorelease];
[req release];//memory leak here and with self.firstURLConn
Why memory is leaking here

Did you ever run Product > Analyze yet? If you did please show us the memory leaking issue log.
They will not only tell the line of your code that have memory leak issue but show the step of your code that cause the problem.
I suggest you to use Instrument tool with leaking tool. It will show the in-depth information about your code problem.
EDIT: req variable miss autorelease. because of req has been retain 2 time. change the code like this
NSMutableURLRequest* req = [[[NSMutableURLRequest alloc] initWithURL:urlcachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60.0f] autorelease];
self.firstURLConn = [[[NSURLConnection alloc] initWithRequest:req delegate:self] autorelease];
[req release];//memory leak here and with self.firstURLConn
Because of your firstURLConn has declared in retain properties. So,the dealloc method, you should set nil to this properties
- (void)dealloc
{
self.firstURLConn = nil;
[super dealloc];
}

firstURLConn will retain your req, req will be only deallocated when firstURLConn will release req.

Since the delegate method returns asynchronously (sometime in the future) you must release the NSURLConnection inside of the delegate method. Remove the autorelease and add a release in the completed and failed delegate methods.

Related

Show an AlertView, do parsing and dismiss AlertView - with GCD

I m very new to iOS, as stated in the question above; im trying to do these 3 simple step.
Show Alert view
Do parsing stuff
Dismiss Alert
I was looking for something like we have in android i.e Pre Execute, doInBackground and Post Execute().
This is what i have tried.
parserAlert = [[UIAlertView alloc] initWithTitle:#"Loading" message:#"Please Wait" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[parserAlert show];
dispatch_queue_t queue = dispatch_queue_create("com.abc.testing", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue,^{
DBHandler *myDB= [[DBHandler alloc] init];
[myDB fetchResults];
dispatch_async(dispatch_get_main_queue(),^{
[parserAlert dismissWithClickedButtonIndex:0 animated:YES];
});
});
Below is the fetchResult method.
- (void) fetchResults
{
IParser *i = [[IParser alloc] init];
[i startParse];
AGParser *ag = [[AGParser alloc] init];
[ag startParse];
GParser *g = [[GParser alloc] init];
[g startParse];
HParser *h = [[HParser alloc] init];
[h startParse];
SParser *s = [[SParser alloc] init];
[s startParse];
}
This is startParse.
NSString *url = #"http://abcd.com/Service_URL/Service.asmx/GetNotes";
NSURL *nsUrl = [[NSURL alloc] initWithString:url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:nsUrl];
NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:request delegate:self];
responseData = [[NSMutableData alloc] init];
[con start];
When i run the above code, Alerview show and dismiss within a second. Adding logs on methods i observed that fetchresults method return immediately and alert view gets dismiss. However fetchResults associated threads(Connection methods, Parser methods) keep executing but alerview is dismissed.
I need a guideline how to block the code until all associated methods are finished.
Thanks for your time.
I know this is not the answer you want, but don't use an alert view for this. A nice way to cover for time-consuming activity to is to put up a UIActivityIndicatorView, or a view that contains one, and set it spinning:
http://www.apeth.com/iOSBook/ch25.html#_uiactivityindicatorview
You can also prevent user interaction while the time-consuming activity is happening, with the shared application object's beginIgnoring... (and turn that off with endIgnoring... when you're done). Obviously you can't do that, though, if the user is to be given a Cancel button. In that case, cover everything else with an invisible view (clear background color) whose userInteractionEnabled is YES, so that it eats any touches intended for anything other than the button.
Also, it is almost never the right answer to use dispatch_sync. Once you've frozen the interface in the way I've just described, you can just do your connections (asynchronous) and parsing (on a background thread) and then come back into the main thread to dismiss the activity indicator.
Finally, you're going to want to leave yourself a way out in case things go wrong. You could run an NSTimer, for example.
EDIT: And now for the actual answer to your actual question, i.e. why is my code not pausing even though I used dispatch_sync: it's because [[NSURLConnection alloc] initWithRequest:request delegate:self] returns immediately; the networking is in yet another background thread. So your startParse returns, your fetchResults returns, and meanwhile the networking continues and the NSURLConnection delegate methods are called some time later.
Here is the link what you are looking for MBProgressHUD
First alloc the MBProgressHUD instance of it in the viewDidLoad
MBProgressHUD *progressHUD = [[MBProgressHUD alloc] initWithView:self.view];
progress.delegate=self;
[progressHUD showWhileExecuting:#selector(performBackgroundTask) onTarget:self withObject:nil animated:YES]
and in the background method
-(void)performBackgroundTask
{
//Do some stuff
}
and soon as the task in the )performBackgroundTaskmethod is completed the Activity indicator shown in the MBProgressHUD will hidden and the delegate method called
-(void)hudWasHidden
{
//Do additional stuff after completion of background task
}
Hope it will help you.

Finding the cause of memory leak in Instruments

I have run the leaks in Instruments and it is showing me a memory leak with a 100% value. I am able to see the line of code that is causing the problem. But not really sure what the error is..
- (void) listAllBooks {
if (marrListFromDB != nil) {
[marrListFromDB removeAllObjects];
marrListFromDB = nil;
}
marrListFromDB = [[NSMutableArray alloc] init];
ServerCommunicationAPI *servApi = [[ServerCommunicationAPI alloc] init];
servApi.delegate = self;
NSURL *url = [NSURL URLWithString:kLISTCONTENTS];
[servApi listBooksWithDeviceID:singleton.g_strdevID deviceKey:singleton.g_strdevID andSessionString:singleton.g_strSessionID sessionKey:#"sessionKey" URL:url andRequestMethod:#"POST"];
}
The line of error is the last one. Not sure why it is causing a memory leak... Need some guidance..
It is hard to tell from the information provided, but maybe the delegate property of ServerCommunicationAPI is declared as (strong)? In this case servApi could never be released, because it keeps a strong reference to itself (retain cycle).
I suggest that you check in instruments which kind of object leaks, this would make the answer much easier.
Try out this. May it resolve your memory leak problem.
- (void) listAllBooks {
if (marrListFromDB != nil) {
[marrListFromDB removeAllObjects];
marrListFromDB = nil;
}
ServerCommunicationAPI *servApi ;
marrListFromDB = [[NSMutableArray alloc] init];
if(servApi == nil){
ServerCommunicationAPI *servApi = [[ServerCommunicationAPI alloc] init];
}//Every time it going to alloc. It's strong object may be due do this memory leak happens.
servApi.delegate = self;
NSURL *url = [NSURL URLWithString:kLISTCONTENTS];
[servApi listBooksWithDeviceID:singleton.g_strdevID deviceKey:singleton.g_strdevID andSessionString:singleton.g_strSessionID sessionKey:#"sessionKey" URL:url andRequestMethod:#"POST"];
}
Just another idea: Maybe you execute your code in a separate thread for which no autorelease pool has been set up? In this case the message sent to servApi could create autorelease objects that cannot be released later since no autorelease pool exists.
So, if your code is not executed in the main thread, please check if an autorelease pool has been set up using a #autoreleasepool {...} block for your thread.

ASIHTTP Request is not working and application is crashing when i tried to release the Object of my Class

In my Main class i am creating an object of my AlbumFetcher class and calling some functions and relasing the object .
AlbumFetcher *_albumFetcher = [[AlbumFetcher alloc] init];
[_albumFetcher getData];
[_albumFetcher release];
When i relaesed the object after calling some functions , ASIHTTP request finish method is not calling and application is crashing . But when i am not releasing the object everything is working perfect . What i have to do
AlbumFetcher *_albumFetcher = [[AlbumFetcher alloc] init];
[_albumFetcher getData];
//[_albumFetcher release]; // now ASIHTTP Request n everything is working fine .....
In AlbumFetcher Class i have this functions ...
-(void)getData{
_fullsizeURL = [NSURL URLWithString:#"http://mysite.com/site/alb_iphone"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:_fullsizeURL];
[request setDelegate:self];
[request setDidFinishSelector:#selector(albumrequestDone:)];
[request setDidFailSelector:#selector(albumrequestFailed:)];
[request startAsynchronous];
}
- (void)albumrequestDone:(ASIHTTPRequest *)request{
// here my code
}
- (void)albumrequestFailed:(ASIHTTPRequest *)request{
// here my code
}
So where i am going wrong and where i have to release the object .
In your case, ASIHTTPRequest works asynchronously, i.e. in another thread. So your request is not done after [_albumFetcher getData] finishes.
Your request is not finished until albumrequestDone:request or albumrequestFailed:request finished. My suggestion is put [self release] at the end of those two functions.

iOS - Track URL connections

I'm currently trying to log all URL connections made in my app. Is there a debug switch, or network activity monitor tool I can use to do this?
Or is my only alternative to include NSLog statements throughout the source base?
Thanks,
Ash
All NSURLConnections of your application use a shared cache class for default
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLCache_Class/Reference/Reference.html
So, one thing you could do is subclass the default cache, and then at the cachedResponseForRequest NSURLCache method, you can to track you requests.
#interface CustomNSURLCache : NSURLCache {
}
#end
#implementation CustomNSURLCache
-(NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
NSLog(#"connection will send request for url: %#", request);
return [super cachedResponseForRequest:request];
}
#end
At your AppDelegate didFinishLaunchingWithOptionsmethod, set the shared cache to an instance of your cache.
CustomNSURLCache *customCache = [[CustomNSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:51200 diskPath:nil];
[NSURLCache setSharedURLCache:customCache];
[customCache release];
(being 0 the default value for MemoryCapacity and 512000 for DiskCapacity)
Now when you create a new connection
NSURLRequest *request1 = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://stackoverflow.com"]];
[[NSURLConnection alloc] initWithRequest:request1 delegate:self];
you should see something like this at your console
connection will send request for url: <NSURLRequest https://stackoverflow.com/>
In Instruments there is a Network Activity Monitor under the System Instruments. I have not personally used it though so I don't know if it does what you want.

iPhone memory management problems

I detach a thread calling my method which has a while-loop. Even though I have them marked as autoreleasepool, I release the objects manually, since the while-loop can continue on for a some time.
The problem is that after a while, the app crashes due to memory problems. If I look in Instruments, I can see a huge pile of NSStrings allocated and a stairway to heaven is created in the graph. What have I failed to release?
while (keepGettingScores)
{
NSString *jsonString = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSDictionary *json = [jsonString JSONValue];
[jsonString release];
NSMutableArray *scores = [[NSMutableArray alloc] init];
[scores setArray:(NSMutableArray*)[[jsonString JSONValue] objectForKey:#"scores"]];
NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:#"totalScore" ascending:NO];
[scores sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
[sorter release];
[self performSelectorOnMainThread:#selector(updatePlayerTable:) withObject:scores waitUntilDone:NO];
[scores release];
[NSThread sleepForTimeInterval:1.0];
}
I don't see anything glaring, could there be an issue under the hood in your JSON library?
Are you draining your pool after your thread is finished executing?
You need to create an NSAutoreleasePool and call its drain method when your thread is finished executing.
In one of my projects, I had a thread that needed to create a lot of autorelease objects and found it useful to periodically drain the pool as the thread was running.
- (void)doStuff:(NSObject *)parent {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* Do lots of stuff *.
/* Periodically, I'd drain and recreate the pool */
[pool drain];
pool = [[NSAutoreleasePool alloc] init];
/* The rest of my stuff */
[pool drain];
}
And doStuff: is called using detachNewThreadSelector:
ok some BIG problems i see is
1
this..
[self performSelectorOnMainThread:#selector(updatePlayerTable:) withObject:scores waitUntilDone:NO];
is passing scores which could be getting retained by something else and that would also retain all the objects it contains.
2
scores is a nsmutablearray and is explicitly defined as NOT THREAD SAFE yet you are passing it across threads.
3
those [blah JSONvalue] things should be autoreleased and that is not apple api, apple has no public JSON api for iphone. that is most likely SBJSON library which puts categories on apple classes(nsstring, nsarray, nsdictionary, etc) for convenient JSON parsing.

Resources