I am uploading Zips containing folders of images from my application on a remote server in my iOS app. The function is called in a separate NSThread so it should not block the UI. Here I create batches of folders containing images (of max 10 MB) and upload them on remote server by giving calls to an SP on remote server. The problem is each call to this method increases my live bytes depensing on the size of zip file which never comes down again. Bellow is my code:
-(IBAction)syncPressed:(id)sender
{
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *strServerFolderPath = [[paths objectAtIndex:0]stringByAppendingPathComponent:app.objDataAccess.tempServerIPAddress];
NSString *strImagesFolderPath=[strServerFolderPath stringByAppendingPathComponent:@"Images"];
NSString *strDatabaseImagesPath=[strImagesFolderPath stringByAppendingPathComponent:app.objDataAccess.tempDBName];
NSArray *arrOfDirectoryToZip=[[NSFileManager defaultManager] contentsOfDirectoryAtPath:strDatabaseImagesPath error:NULL];
int iZippedFolderCounter=0;
if(app.viewController.arrADataSyncProgress==nil)
app.viewController.arrADataSyncProgress=[[NSMutableArray alloc]init];
else
[app.viewController.arrADataSyncProgress removeAllObjects];
unsigned long long int iSizeOfFolder=[app.globalVcImageViewController folderSize:strDatabaseImagesPath];
int iNoOfBatches=iSizeOfFolder/10485760;
if(iSizeOfFolder%10485760>0)
iNoOfBatches++; //We will need to add one more batch for remainings
int iCounter=1;
//Add batch objects in array initially so that they can be updated at correct time
while(iCounter<=iNoOfBatches)
{
SyncProgress *objSync=[[SyncProgress alloc]init];
objSync.cSyncName=[NSString stringWithFormat:@"Batch %d",iCounter];
objSync.iSyncStatus=0;
objSync.cSpName=@"UploadImageData";
objSync.cStartSyncTime=@" ";
objSync.cEndTime=@" ";
[app.viewController.arrADataSyncProgress addObject:objSync];
objSync=nil;
iCounter++;
}
[app.viewController.tblviwSyncProgress performSelectorInBackground:@selector(reloadData) withObject:nil];
float fPerBatchIncrement=100.0/iNoOfBatches;
[Flurry logEvent:@"Sync started"];
[app.objLogger writetoLogFileWithMessage:@"Sync started" withMethodName:@"syncPressed:" withLoggerLevel:eLoggerInfo];
int iBatchCounter=0;
//Upload images batchwise
while(iBatchCounter<iNoOfBatches)
{
NSMutableArray *arrmPathsToZip=nil;
unsigned long long int iSizeOfBatch=0;
//In each batch 10 MB or remaining folders are zipped
while(iZippedFolderCounter<arrOfDirectoryToZip.count && (iSizeOfBatch+[app.globalVcImageViewController folderSize:[strDatabaseImagesPath stringByAppendingPathComponent:[arrOfDirectoryToZip objectAtIndex:iZippedFolderCounter]]])<10485760 && iZippedFolderCounter<arrOfDirectoryToZip.count)
{
//Add Paths to temporary array
if(arrmPathsToZip==nil)
arrmPathsToZip=[[NSMutableArray alloc]init];
[arrmPathsToZip addObject:[strDatabaseImagesPath stringByAppendingPathComponent:[arrOfDirectoryToZip objectAtIndex:iZippedFolderCounter]]];
iSizeOfBatch+=[app.globalVcImageViewController folderSize:[strDatabaseImagesPath stringByAppendingPathComponent:[arrOfDirectoryToZip objectAtIndex:iZippedFolderCounter]]];
iZippedFolderCounter++;
}
//Give the zip a random unique name
NSString *strRandomFolderName=[NSString stringWithFormat:@"%f",[[NSDate date] timeIntervalSince1970]];
NSString *strZipPath= [strImagesFolderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.zip",strRandomFolderName]];
//Create zip from the folder
BOOL bSuccess = [SSZipArchive createZipFileAtPath:strZipPath withContentsOfDirectoris:arrmPathsToZip];
arrmPathsToZip=nil;
if(!bSuccess)
{
[app removeCustomLoader];
UIAlertView *altError=[[UIAlertView alloc]initWithTitle:app.strAppName message:@"Error occured while gathering data" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
[altError show];
altError=nil;
}
else
{
//Update sync progress object
SyncProgress *objSyncProgress=(SyncProgress*)[app.viewController.arrADataSyncProgress objectAtIndex:iBatchCounter];
objSyncProgress.cStartSyncTime = [app.loginView getCurrentTimeInUTCFormatToString];
[app.viewController.tblviwSyncProgress performSelectorInBackground:@selector(reloadData) withObject:nil];
NSData *dat=[NSData dataWithContentsOfFile:strZipPath];
//[Base64 initialize];
NSString *strZipEncoded = [Base64 encode:dat];
NSString *cDBToken=app.dbToken;
//Get Key From GUID
NSString *cGUID=[app.loginView generateUuidString];
int iKey = [app.loginView KeyFromGUID:cGUID];
//Encrypt Parameter
cDBToken=[app.loginView encrypt:cDBToken withShiftCount:iKey];
cDBToken= [NSString stringWithFormat:@"%@##%@",cGUID,cDBToken];
NSString *strUserName=[app.loginView encrypt:app.LoginUsrnm withShiftCount:iKey];
NSString *strPassword=[app.loginView encrypt:app.LoginPswd withShiftCount:iKey];
NSString *strSPName=[app.loginView encrypt:@"_wspIICInsertImages" withShiftCount:iKey];
//SOAP Request
NSMutableString *soapMsg =[[NSMutableString alloc] initWithFormat:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\
<soap:Envelope\
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\
xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\
<soap:Body>\
<UploadImageData\
xmlns=\"http://tempuri.org/\">\
<DBToken><![CDATA[%@]]></DBToken>\
<UserName><![CDATA[%@]]></UserName>\
<Password><![CDATA[%@]]></Password>\
<DeviceID>1</DeviceID>\
<BatchSize>1</BatchSize>\
<DocString><![CDATA[%@]]></DocString>\
<fileName><![CDATA[%@]]></fileName>\
<SPName><![CDATA[%@]]></SPName>\
</UploadImageData>\
</soap:Body>\
</soap:Envelope>",cDBToken,strUserName,strPassword,strZipEncoded,strRandomFolderName,strSPName];
NSURL *url = [NSURL URLWithString:app.webServiceName];
NSMutableURLRequest *req =
[NSMutableURLRequest requestWithURL:url];
NSString *msgLength =
[NSString stringWithFormat:@"%d", [soapMsg length]];
[req addValue:@"text/xml; charset=utf-8"
forHTTPHeaderField:@"Content-Type"];
[req addValue:msgLength
forHTTPHeaderField:@"Content-Length"];
//add gzip-encoding to HTTP header
[req setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
[req addValue:@"http://tempuri.org/UploadImageData"
forHTTPHeaderField:@"SOAPAction"];
[req setHTTPMethod:@"POST"];
[req setHTTPBody: [soapMsg dataUsingEncoding:NSUTF8StringEncoding]];
soapMsg=nil;
[req setTimeoutInterval: 60];
//call method to connect to webservice by passing request object
NSURLResponse* urlResponse = nil;
NSError *error;
NSData *responseData = [NSURLConnection sendSynchronousRequest:req returningResponse:&urlResponse error:&error];
NSString *strResponse=[[NSString alloc]initWithData:responseData encoding:NSUTF8StringEncoding];
[[NSFileManager defaultManager] removeItemAtPath:strZipPath error:NULL];
if(iZippedFolderCounter<arrOfDirectoryToZip.count)
app.viewController.fPercentageSync=app.viewController.fPercentageSync+fPerBatchIncrement;
else
app.viewController.fPercentageSync=100;
app.viewController.fDataSize+=dat.length/(1024.0*1024);
dat=nil;
//Update sync progress object
objSyncProgress=(SyncProgress*)[app.viewController.arrADataSyncProgress objectAtIndex:iBatchCounter];
if([[app stringBetweenString:@"<UploadImageDataResult>" andString:@"</UploadImageDataResult>" withstring:strResponse] isEqualToString:@"true"])
{
objSyncProgress.iSyncStatus=1;
}
else
objSyncProgress.iSyncStatus=2;
objSyncProgress.cEndTime=[app.loginView getCurrentTimeInUTCFormatToString];
[app performSelectorInBackground:@selector(setHUDSubtitle:) withObject:[NSNumber numberWithFloat:app.viewController.fPercentageSync]];
[app.viewController.tblviwSyncProgress performSelectorInBackground:@selector(reloadData) withObject:nil];
responseData=nil;
strResponse=nil;
strZipEncoded=nil;
}
iBatchCounter++;
}
btnSync.selected=NO;
[Flurry logEvent:@"Sync completed"];
[app.viewController.actSyncProgress stopAnimating];
[app removeCustomLoader];
NSDateFormatter *formatter=[[NSDateFormatter alloc]init];
formatter.dateFormat=@"dd-MM-yyyy hh:mm:ss a";
NSString *strSyncCompletionDate=[formatter stringFromDate:[NSDate date]];
[app.objDataAccess insertIntoDatabaseUserName:app.LoginUsrnm syncCompletionTime:strSyncCompletionDate dataSize:app.viewController.fDataSize serverName:app.loginView.tempServerName databaseName:app.loginView.tempDBName];
[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}
The call to above function is given as bellow:
[NSThread detachNewThreadSelector:@selector(syncPressed:) toTarget:self withObject:nil];
Any pointers where am I going wrong will be most appreciated!
EDIT: After using instruments to see allocations, I noted that they are pointing towards te line shown in bellow screenshot:
NSData *responseData = [NSURLConnection sendSynchronousRequest:req returningResponse:&urlResponse error:&error];
I have also enclosed my code in @autoreleasepool Please help as I am still not getting how can I avoid this.