I have a recursive loop using NSTimer that runs every two seconds and calls a function that calls the setupPhpCall function:
There are 3 NSTimers that run and always hits the setupPhpCall function,
could this be where the memory leakage is happening?
-(NSString*)setupPhpCall:(NSString*)requestString :(NSString*)sciptPage{
NSData *myRequestData = [NSData dataWithBytes: [requestString UTF8String] length: [requestString length]];
// Create your request string with parameter name as defined in PHP file
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: [NSString stringWithFormat: #"http://www.xxxx.co.uk/%#", sciptPage]]];
// set Request Type
[request setHTTPMethod: #"POST"];
// Set content-type
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
// Set Request Body
[request setHTTPBody: myRequestData];
// Now send a request and get Response
NSHTTPURLResponse* urlResponse = nil;
NSError *error = [[NSError alloc] init];
NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse:&urlResponse error: &error];
// Log Response
NSString *response = [[NSString alloc] initWithBytes:[returnData bytes] length:[returnData length] encoding:NSUTF8StringEncoding];
NSLog(#"%#",response);
return response;
}
This is the recursive method thats called using NSTimer:
-(void)recurseForumActivity:(NSTimer *)timer{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
NSString *myRequestString = [NSString stringWithFormat:#"lastDate=%#&threadTitle=%#&threadCountry=%#&threadCategory=%#&threadSubCategory=%#&getData=0",lastDateForumActivity,searchThreadTitle, searchThreadCountry, searchThreadCategory, searchThreadSubCategory];
NSString *response = [self setupPhpCall:myRequestString :#"xxx.php"];
dispatch_async(dispatch_get_main_queue(), ^{
if(response.length > 0 && ![response isEqualToString:#"[]"]){
labelNewForumThreads.text = [NSString stringWithFormat:#"%# new threads...", response];
if(imageviewForumAlert == NULL){
UIImage *image = [UIImage imageNamed:#"alert.png"];
imageviewForumAlert = [UIImageView new];
[viewNav1 addSubview:imageviewForumAlert];
imageviewForumAlert.translatesAutoresizingMaskIntoConstraints = NO;
imageviewForumAlert.image = image;
NSDictionary *viewsDictionary = #{#"imageviewForumAlert":imageviewForumAlert};
NSArray *constraint_H = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-19-[imageviewForumAlert(12)]-19-|"
options:0
metrics:nil
views:viewsDictionary];
NSArray *constraint_V = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-19-[imageviewForumAlert(12)]-19-|"
options:0
metrics:nil
views:viewsDictionary];
[self.view addConstraints:constraint_H];
[self.view addConstraints:constraint_V];
}else{
imageviewForumAlert.hidden = NO;
}
/**NSDictionary *dic = [response JSONValue];
if((NSNull*)dic != [NSNull null]){
labelNewForumThreads.text = [NSString stringWithFormat:#"%d new threads...", dic.count];
}**/
}else{
imageviewForumAlert.hidden = YES;
labelNewForumThreads.text = [NSString stringWithFormat:#"%d new threads...", 0];
}
/**else{
labelNewForumThreads.text = [NSString stringWithFormat:#"%d new threads...", 0];
}**/
});
});
}
EDIT
In the console i get this error after i have left the app to run for more than one hour:
Communications error: <OS_xpc_error: <error: 0x361c0614> { count = 1, contents =
"XPCErrorDescription" => <string: 0x361c086c> { length = 22, contents = "Connection interrupted" }
}>
i have Allocation tool running aswel
this is the screenshot of allocation tool when the app crashes
EDIT
EDIT
I have also noticed when starting Instrument Allocations tool my memory usage rapidly shots up quicker, why is this?
Related
I am new to iOS i need to show particular object for key in textview or picker view using post method response.
coding:
NSString *parameter = [NSString stringWithFormat:#"username=%#",user];
NSData *parameterData = [parameter dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
url = [NSURL URLWithString: URL];
NSLog(#"%#", parameterData);
request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPBody:parameterData];
NSString *content = [NSString stringWithUTF8String:[parameterData bytes]];
}
[request setHTTPMethod:method];
[request addValue: #"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if( connection )
{
mutableData = [NSMutableData new];
}
}
delegate method:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *responseStringWithEncoded = [[NSString alloc] initWithData: mutableData encoding:NSUTF8StringEncoding];
// NSLog(#"Response from Server : %#", responseStringWithEncoded);
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData: mutableData
options:kNilOptions
error:&error]; //Now we got top level dictionary
// (2)
arrdata =[json objectForKey:#"Branches"];
//(2)
NSLog(#"%#",[arrdata valueForKey:#"id"]);
NSAttributedString * attrStr = [[NSAttributedString alloc] initWithData:[responseStringWithEncoded dataUsingEncoding:NSUnicodeStringEncoding] options:#{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
serverResponse.attributedText = attrStr;
//serverResponse.text = arrdata;
}
I am successfully showed in NSLOG as below :
But in textview it is not updating. How can I fix this?
serverResponse.text = [arrdata valueForKey:#"id"];
Try out the below code:
dispatch_async(dispatch_get_main_queue(),^ {
//Update your UI Component here
serverResponse.attributedText = attrStr;
//or uncomment below line and comment upper line
//serverResponse.text = [arrdata valueForKey:#"id"];
});
All the UI changes must be carried out in Main thread.
Hence probably this may be the issue.
so, at the end of connectionDidFinishLoading wrap textview with GCD main queue like below :
dispatch_async(dispatch_get_main_queue(),^ {
//Update text view
serverResponse.attributedText = attrStr;
});
I have a function that gets called recursively to get new data from the database depending on the latest date. My problem is that this recursive call made causes memory usage to increase. I have commented out code to see what line is cause 300kb to be Allocated every time, so whats happening is that every time the NSURLConnection is hit i get memory usage to be increased by 300kb every 10 seconds.
This is the method that gets called recursively:
-(NSString*)setupPhpCall:(NSString*)requestString :(NSString*)sciptPage{
#autoreleasepool {
//NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:0];
//[NSURLCache setSharedURLCache:sharedCache];
NSHTTPURLResponse *urlresponse = nil;
NSError *error = nil;
NSString *response = #"";
NSData *myRequestData = nil;
NSMutableURLRequest *request = nil;
NSData *returnData = nil;
myRequestData = [NSData dataWithBytes: [requestString UTF8String] length: [requestString length]];
//Create your request string with parameter name as defined in PHP file
request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: [NSString stringWithFormat: #"http://www.hugt.co.uk/%#", sciptPage]]];
// set Request Type
[request setHTTPMethod: #"POST"];
// Set content-type
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
// Set Request Body
[request setHTTPBody: myRequestData];
// Now send a request and get Response
//NSHTTPURLResponse* urlResponse = nil;
//NSError *error = nil;
//if(tmpArray.count == 0){
returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlresponse error: &error]; //THIS LINE CAUSES THE MEMORY USAGE TO INCREASE
response = [[NSString alloc] initWithBytes:[returnData bytes] length:[returnData length] encoding:NSUTF8StringEncoding];
//}
// Log Response
urlresponse = nil;
error = nil;
myRequestData = nil;
request = nil;
returnData = nil;
//NSLog(#"%#",response);/****/
//[sharedCache removeAllCachedResponses];
if(response != nil){
return response;
}
}
return nil;
}
This is what i do with the response:
-(void)recurseForumActivity{
#autoreleasepool {
__block __weak dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
myRequestStringForum = [NSString stringWithFormat:#"lastDate=%#&threadTitle=%#&threadCountry=%#&threadCategory=%#&threadSubCategory=%#&getData=0",lastDateForumActivity,searchThreadTitle, searchThreadCountry, searchThreadCategory, searchThreadSubCategory];
responseForum = [self setupPhpCall:myRequestStringForum :#"xxx.php"];
[NSThread sleepForTimeInterval:2.0f];
dispatch_async(dispatch_get_main_queue(), ^{
if(responseForum.length > 0 && ![responseForum isEqualToString:#"[]"]){
labelNewForumThreads.text = [NSString stringWithFormat:#"%# new threads...", responseForum];
if(imageviewForumAlert == NULL){
UIImage *image = [UIImage imageNamed:#"alert.png"];
imageviewForumAlert = [UIImageView new];
[viewNav1 addSubview:imageviewForumAlert];
imageviewForumAlert.translatesAutoresizingMaskIntoConstraints = NO;
imageviewForumAlert.image = image;
NSDictionary *viewsDictionary = #{#"imageviewForumAlert":imageviewForumAlert};
NSArray *constraint_H = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-19-[imageviewForumAlert(12)]-19-|"
options:0
metrics:nil
views:viewsDictionary];
NSArray *constraint_V = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-19-[imageviewForumAlert(12)]-19-|"
options:0
metrics:nil
views:viewsDictionary];
[self.view addConstraints:constraint_H];
[self.view addConstraints:constraint_V];
}else{
imageviewForumAlert.hidden = NO;
}
/**NSDictionary *dic = [response JSONValue];
if((NSNull*)dic != [NSNull null]){
labelNewForumThreads.text = [NSString stringWithFormat:#"%d new threads...", dic.count];
}**/
}else{
imageviewForumAlert.hidden = YES;
labelNewForumThreads.text = [NSString stringWithFormat:#"%d new threads...", 0];
}
/**else{
labelNewForumThreads.text = [NSString stringWithFormat:#"%d new threads...", 0];
}**/
myRequestStringForum = #"";
responseForum = #"";
concurrentQueue = nil;
[self recurseForumActivity];
});
});
}
}
I have a problem I can't deal with.
In my application, I get datas from my Web Service in JSON. It's UTF8-encoded and when I fill an UITableView everything is ok (NSLog return accents like : "\u00e9" but my UITableView shows it like : "é").
But when I set the same data in my detailTextLabel, it doesn't convert "\u00e9" to "é" ...
Tried some tricks with encoding, but nothing convincing.
Parsing methods :
- (NSDictionary*)fetchedData:(NSData *)responseData {
NSError* error;
self.json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
return self.json;
}
-(void)executeParsingWithUrl:(NSURL*)anUrl{
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:anUrl];
NSString *authStr = [NSString stringWithFormat:#"%#:%#",[[NSUserDefaults standardUserDefaults] stringForKey:#"username_ws"], [[NSUserDefaults standardUserDefaults] stringForKey:#"password_ws"]];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [Base64 encode:authData]];
[urlRequest setValue:authValue forHTTPHeaderField:#"Authorization"];
NSError *requestError = NULL;
NSHTTPURLResponse *response = NULL;
NSData *responseData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&requestError];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:responseData waitUntilDone:YES];
}
Recuperation :
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
JsonParsing *getJson = [[JsonParsing alloc] init];
[getJson executeParsingWithUrl: leUrl];
self.duration = [NSString stringWithFormat:#"%#",[[getJson.json objectForKey:#"objects"]valueForKey:#"libel"]];
});
Thanks in advance !
I managed it thanks to other people.
I my cell.detailTextLabel I used this :
cell.detailTextLabel.text = [NSString stringWithCString:[myText cStringUsingEncoding:NSUTF8StringEncoding] encoding:NSNonLossyASCIIStringEncoding];
I get four parameters from a web service (web service 2 in my flow) - slno, order, flag, name. I don't know how many times these parameters are going to be received. Out of these four paramters, I send 'name' to a label as it contains questions to be asked.
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"some url"]];
NSLog(#"Web service 2 url is = %#", url);
NSString *json = [NSString stringWithContentsOfURL:url encoding:NSASCIIStringEncoding error:&error];
NSLog(#"Json data = %# \n error = %#", json, error);
if(!error)
{
NSData *jsonData = [json dataUsingEncoding:NSASCIIStringEncoding];
NSArray *myJsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:Nil];
//NSArray *arrayLabel = [[NSArray alloc] initWithObjects:label1, label2, label3, label4, label5, label6, nil];
//NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:myJsonArray.count];
i = 0;
for(NSDictionary *myJsonDictionary in myJsonArray)
{
//UILabel *label = (UILabel *)[arrayLabel objectAtIndex:i++];
//[label setText:myJsonDictionary[#"Name"]];
NSString *name = myJsonDictionary[#"Name"];
NSLog(#"Question from ws2 is %#", name);
projectIdGobal = myJsonDictionary[#"ProjectID"];
NSLog(#"Project id from ws2 is %#", projectIdGobal);
slno = myJsonDictionary[#"SLNO"];
NSLog(#"slno from ws2 is %#", slno);
NSString *idWS2 = myJsonDictionary[#"ID"];
NSLog(#"id from ws2 is %#", idWS2);
order = myJsonDictionary[#"Order"];
NSLog(#"order from ws2 is %#", order);
flag = myJsonDictionary[#"Flag"];
NSLog(#"flag from ws2 is %#", flag);
[self putLabelsInScrollView:name];
i++;
}
NSLog(#"Number of cycles in for-each = %d", i);
[activity stopAnimating];
}
- (void) putLabelsInScrollView:(NSString *)labelText
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, yPosition_label, 261, 30)];
[label setFont:[UIFont fontWithName:#"Helvetica Neue" size:12.0f]];
label.numberOfLines = 2;
[label setText:labelText];
[self.scroll addSubview:label];
yPosition_label += 90;
UITextField *text = [[UITextField alloc] initWithFrame:CGRectMake(10, yPosition_text, 261, 30)];
text.borderStyle = UITextBorderStyleRoundedRect;
text.textColor = [UIColor blackColor];
text.font = [UIFont systemFontOfSize:12.0];
text.backgroundColor = [UIColor clearColor];
text.keyboardType = UIKeyboardTypeDefault;
text.delegate = self;
[self.scroll addSubview:text];
yPosition_text += 90;
yPosition_result = yPosition_label + yPosition_text;
[self.scroll setContentSize:CGSizeMake(self.scroll.frame.size.width, yPosition_result)];
[self.view addSubview:self.scroll];
}
Now I created a dynamically created text fields and stored the answers entered by the user in the array as follows.
- (IBAction)save:(id)sender {
NSMutableArray *mutableTextArray = [[NSMutableArray alloc] init];
for(UITextField *field in self.scroll.subviews)
{
if([field isKindOfClass:[UITextField class]])
{
if([[field text] length] > 0)
{
[mutableTextArray addObject:field.text];
//NSLog(#"Save button 1 : %#", mutableTextArray);
//NSString *str = [str stringByAppendingString:[mutableTextArray objectAtIndex:0]];
//[self fetchStrings:mutableTextArray];
}
}
}
NSLog(#"Save button 2 : %#", mutableTextArray);
[self fetchStrings:mutableTextArray];
}
Now while posting the answer to another web service (web service 3 in my flow), I must pass slno, order, flag i get from web service 2 and the 'answer' that the user enters in the dynamically created field to the 'answer' key. How shall I get these 4 parameters [slno, order, flag (from web service 2) and answer (from dynamic text field)] to post to web service 3?
- (void) fetchStrings:(NSArray *)textArray
{
NSLog(#"Array string = %#", textArray); //I get the array that the user enters in the dynamically created text field here
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSUserDefaults *getDefaults = [NSUserDefaults standardUserDefaults];
NSString *uidObject = [getDefaults objectForKey:#"UIDKEY"];
NSString *str = [NSString stringWithFormat:#"{\"ProjID\": \"%#\",\"Uid\": \"%#\",\"EmailID\": \"%#\",", projectIdGobal, uidObject, emailFromLogin];
str = [str stringByAppendingString:#"\"ProjectInviterFQAnswers\": ["];
**for (SaveAsking *saveAsk in textArray) {
str = [str stringByAppendingString:[NSString stringWithFormat:#"{\"slno\":\"%#\",\"Answer\": \"%#\",\"order\": \"%#\", \"flag\": \"%#\"},", saveAsk.slno, saveAsk.answer, saveAsk.order, saveAsk.flag]]; // I want to save the parameters here
}**
// SaveAsking is a nsobject class where I have used a self created delegate for slno answer order and flag
str = [str stringByAppendingString:#"]}"];
NSLog(#"String is === %#", str);
NSURL *url = [NSURL URLWithString:#"some url"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSData *requestData = [str dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if(error || !data)
{
NSLog(#"JSON Data not posted!");
[activity stopAnimating];
UIAlertView *alertMessage = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Data not saved" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertMessage show];
}
else
{
[activity startAnimating];
NSLog(#"JSON data posted! :)");
NSError *error = Nil;
NSJSONSerialization *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSLog(#"Response is %#", jsonObject);
}
}];
}
Please do correct my flow if you understood what am i trying to achieve. Number for iterations in left box == number of iterations in right box and the result is in the middle box which needs to be posted to web service.
Try keeping a dictionary of the requests, where the key would be the dynamically created UITextField, and the value would be another dictionary with the values that you need to send.
So , when you create the textField, after adding it to the subview, create a dictionary with your values (sino, order, flag), and set that dictionary to the textfield.
When you are ready to send the data, you'll have a direct connection between the textField and the values for your webservice3.
I get an self.usersArray with 2 elements in the format:
(
{
userCreated = "2012-01-05 12:27:22";
username = Simulator;
},
{
userCreated = "2013-01-01 14:27:22";
username = "joey ";
}
)
This is gotten in a completion block after which I call another method to fetch points for these 2 users through a helper class:
-(void)getPoints{
self.usersPointsArray = [[NSMutableArray alloc] init];
for (NSDictionary *usersDictionary in self.usersArray) {
[SantiappsHelper fetchPointsForUser:[usersDictionary objectForKey:#"username"] WithCompletionHandler:^(NSArray *points){
if ([points count] > 0) {
[self.usersPointsArray addObject:[points objectAtIndex:0]];
}
NSLog(#"self.usersPointsArray %#", self.usersPointsArray);
}];
}
}
The final self.usersPointsArray log looks like:
(
{
PUNTOS = 5;
username = Simulator;
},
{
PUNTOS = 2;
username = joey;
}
)
But the problem is that the way the call for points is structured, the self.usersPointsArray is returned twice, each time with an additional object, due to the for loop, I know.
Here is the Helper class method:
+(void)fetchPointsForUser:(NSString*)usuario WithCompletionHandler:(Handler2)handler{
NSURL *url = [NSURL URLWithString:#"http://myserver.com/myapp/readpoints.php"];
NSDictionary *postDict = [NSDictionary dictionaryWithObjectsAndKeys:usuario, #"userNa", nil];
NSData *postData = [self encodeDictionary:postDict];
// Create the request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d", postData.length] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
__block NSArray *pointsArray = [[NSArray alloc] init];
dispatch_async(dispatch_get_main_queue(), ^{
// Peform the request
NSURLResponse *response;
NSError *error = nil;
NSData *receivedData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (error) {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSLog(#"HTTP Error: %d %#", httpResponse.statusCode, error);
return;
}
return;
}
NSString *responseString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
pointsArray = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSASCIIStringEncoding] options:0 error:nil];
if (handler)
handler(pointsArray);
});
}
I cannot use the self.usersPointsArray with the initial objects, only with the finalized object. It wont always be 2 elements, i actually dont know how many it will be.
What would be the way to structure it so I get a final call when the self.usersPointsArray is complete and then I reload my tableview?
I think of your problem as a standard consumer-producer problem. You can create a queue count for the amount of items that will be processed (int totalToProcess=self.usersArray.count). Each time the completion handler is hit, it will do totalToProcess--. When totalToProcess reaches 0 you have processed all of the elements in your queue and can refresh your table.
If I understand your question correctly I believe this solves your problem. If not, hopefully I can with a bit more information.