Leaks in passing the request using URL at NSString, Objective-C - objective-c

I getting the leak in this method even the allocated nsstring is released.
Now I am taken stringWithFormat, but still it is showing the leak at "NSData *returnData=...." line
-(BOOL)getTicket:(NSString*)userName passWord:(NSString*)aPassword isLogin:(BOOL)isLogin
{
NSString* str=#"";
if (isLogin == YES)
{
str =[NSString stringWithFormat:#"AGENT=true&LOGIN_ID=%#&PASSWORD=%#",[self _encodeString:userName],[self _encodeString:aPassword]];
}
else if (isLogin == NO)
{
str =[NSString stringWithFormat:#"AGENT=true&LOGIN_ID=%#&PASSWORD=%#",[self _encodeString:userName],[self _encodeString:aPassword]];
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:str]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:25.0];
[request setHTTPMethod: #"POST"];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
printf("\n returnString in getticket:%s",[returnString UTF8String]);
NSRange textRange;
textRange =[returnString rangeOfString:#"TICKET"];
if(textRange.location != NSNotFound)
{
NSArray* splitValues = [returnString componentsSeparatedByString:#"TICKET="];
NSString* str1 = [splitValues objectAtIndex:1];
NSArray* splitValues1 = [str1 componentsSeparatedByString:#"RESULT"];
NSString* ticket1 = [splitValues1 objectAtIndex:0];
self.ticket = ticket1;
self.isCorrectLogin = YES;
[returnString release];
return YES;
}
else
{
self.isCorrectLogin = NO;
[returnString release];
return NO;
}
return NO;
}
Please help me out of this problem.

Macbirdie is correct in that composing a string using stringByAppendingString: is horribly inefficient. I would suggest using +stringWithFormat: instead.
As for the leak, if the leak is where you say it is, then it might be a leak in the underlying framework (and it might be a false positive). Post the backtrace of the leaked object (which can be had from the Allocations instrument).

Related

objective c invisible array out of function param request

I'm triyng to get array from server. But it doesn't work. I'm mean in the function everything is okay with my array but out of it it's null. How to fix?
for(int i=1; i<5; i++){
NSString *category = [NSString stringWithFormat:#"%d",i];
NSString *encrypt = #"encrypt=93mrLIMApU1lNM619WzZje4S9EeI4L2L";
NSString *latitude = #"latitude=32.794044";
NSString *longtitude = #"longitude=34.989571";
NSString *params = [NSString stringWithFormat:#"%#&category=%#&%#&%#&area=CENTER",
encrypt,category,latitude,longtitude];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://admin.t-club.co.il/api/get-buissness"]];
NSData *postBody = [params dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postBody];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError)
{
if(!connectionError)
{
_myDict =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
_tmpArray = [_myDict objectForKey:#"result"];
NSLog(#"my array %#",_tmpArray);//here array isn't null
}
}];
[_myArray addObjectsFromArray:_tmpArray];
}
NSLog(#"my array %#",_tmpArray);//here is null
It looks like what you're aiming for is to make several async requests in sequence. This can be done by adding a little abstraction.
First, a method that makes just one request and provides a dictionary in response of the parsed JSON result...
- (void)makeRequestWithParams:(NSString *)params completion:(void (^)(NSDictionary *, NSError *))completion {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://admin.t-club.co.il/api/get-buissness"]];
NSData *postBody = [params dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postBody];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
if(!connectionError) {
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
completion(dictionary, nil);
} else {
completion(nil, connectionError);
}
}];
}
Please note that the NSURLConnnection methods have been replaced by NSSession, so this code will need to change to that soon.
Now something that calls that first method over and over. This one takes an array of request parameters as input, fills a mutable array with the dictionary results, and calls a completion block when its done...
- (void)makeManyRequestsWithParams:(NSArray *)arrayOfParams fillingArray:(NSMutableArray *)result completion:(void (^)(BOOL))completion {
if (arrayOfParams.count == 0) return completion(YES);
NSString *nextParams = arrayOfParams[0];
[self makeRequestWithParams:nextParams completion:^(NSDictionary *dictionary, NSError *error) {
if (!error && dictionary) {
[result addObject:dictionary];
NSArray *remainingParams = [arrayOfParams subarrayWithRange:NSMakeRange(1, arrayOfParams.count-1)];
[self makeManyRequestsWithParams:remainingParams fillingArray:result completion:completion];
} else {
completion(NO);
}
}];
}
Finally, your original loop's job is now limited to just assembling the parameters. Once those are in an array, call to make the requests...
- (void)test {
NSMutableArray *arrayOfParams = [NSMutableArray array];
for(int i=1; i<5; i++){
NSString *category = [NSString stringWithFormat:#"%d",i];
NSString *encrypt = #"encrypt=93mrLIMApU1lNM619WzZje4S9EeI4L2L";
NSString *latitude = #"latitude=32.794044";
NSString *longtitude = #"longitude=34.989571";
NSString *params = [NSString stringWithFormat:#"%#&category=%#&%#&%#&area=CENTER",
encrypt,category,latitude,longtitude];
[arrayOfParams addObject:params];
}
NSMutableArray *result = [NSMutableArray array];
[self makeManyRequestsWithParams:arrayOfParams fillingArray:result completion:^(BOOL success) {
if (success) {
NSLog(#"all done, result is %#", result);
} else {
NSLog(#"sadness");
}
}];
// don't expect results to be ready here. they won't be.
// see how they are logged above in the completion block?
}
NSURLConnection sendAsynchronousRequest is asynchronous meaning it will be moved to a background thread and execution will continue without waiting for the task to complete. So by the time it gets to your bottom NSLog, the request will still be processing and the value of _tmpArray will be null.
You can use sendSynchronousRequest to have the request complete before moving on.
http://codewithchris.com/tutorial-how-to-use-ios-nsurlconnection-by-example/#synchronous

TBXML with NSData in Xcode

I have a URL that returns a pretty flat XML file: <entries><title>val1</title><author>Bob</author></entries> The code runs ok:
NSString *urlString = [NSString stringWithFormat:#"http://www.somesite.php?qid=%d", __inum];
NSLog(#"urlString = %#", urlString);
NSURLResponse * response = nil;
NSError * error = nil;
NSURLRequest * urlRequest = [NSURLRequest requestWithURL: [NSURL URLWithString:urlString]];
NSData * myData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
NSLog(#"%#", myData);
TBXML *sourceXML = [[TBXML alloc] initWithXMLData:myData error:nil];
TBXMLElement *rootElement = sourceXML.rootXMLElement;
if (rootElement) {
NSLog(#"Root element found...");
TBXMLElement *qaElement1 = [TBXML childElementNamed:#"title" parentElement:rootElement];
if (qaElement1) {
NSString *idAttribute = [TBXML valueOfAttributeNamed:#"title" forElement:qaElement1];
NSLog(#"Got to the 1st call for idAttribute... %#", idAttribute);
}
else { NSLog(#"There is no value for title..."); }
}
else { NSLog(#"Root element must be null..."); }
}
It finds the root element and gets to the call for valueOfAttribute:#"title" but the value is always (null).
So my question: do I have to do something to convert the NSData back to man readable (I was under the impression TBXML gave that option to work with the NSData and did the calculation). If not, what is the call to create (and then use) an NSString in UTF8 from 'myData'?
what is the call to create (and then use) an NSString in UTF8 from 'myData'?
use initWithData:encoding:
NSString *str = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding];
or stringWithUTF8String: if you know myData is null-terminated UTF8 string
NSString *str = [NSString stringWithUTF8String:[myData bytes]];
Do not ignore error.
NSError *error = nil;
TBXML *sourceXML = [[TBXML alloc] initWithXMLData:myData error:&error];
if (error) {
// handle it, at least log it
}

Looking for guidance on how to efficiently split my json

So I understand how to split the array that holds the JSON info, but what I am stuck on is trying to get it to display everything past only the first whitespace. For instance, if you look at the JSON site (http://iam.colum.edu/portfolio/api/course?json=True) each course has a course number at beginning. I want to split each array object only displaying the course name. For instance, if you look at the site, the first object is "Computer Architecture" second is "Digital Image and Design"... etc. I don't need to know how to split the string, I can already do that, but how do I split it so it takes away "xx-xxx " (x being the course number)? The code I have currently splits at each whitespace, but that's not going to work for obvious reasons.
JSONViewController
dispatch_async(progressQueue, ^{
jstring = [JSONHelper JSONgetString:#"http://iam.colum.edu/portfolio/api/course?json=True"];
dispatch_async(dispatch_get_main_queue(), ^{
//main thread code
//textView.text = jstring;
jarray = [jstring componentsSeparatedByString:#" "];
textView.text = [jarray objectAtIndex:1];
NSString * fullString = [NSString string];
for(int i = 0; i < jarray.count; i++)
{
fullString = [fullString stringByAppendingString:[jarray objectAtIndex:i]];
}
textView.text = fullString;
NSError *error = nil;
NSArray * resultArray = [NSJSONSerialization JSONObjectWithData: [jstring dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error: &error];
if ( !resultArray ) {
NSLog(#"Error parsing JSON: %#", error);
} else {
for(NSString * course in resultArray) {
NSLog(#"Course: %#", course);
}
}
JSONHelper.h
#interface JSONHelper : NSObject
+ (NSDictionary *)JSONget:(NSString *)query;
+ (NSString *)JSONgetString:(NSString *)query;
+ (NSString *)JSONpostString:(NSString *)query;
+(NSString *)JSONpostString:(NSString *)query
withData:(NSString *)jsonData;
#end
JSONHelper.m
#implementation JSONHelper
//returns a dictionar from a get request
+ (NSDictionary *)JSONget:(NSString *)query
{
NSData *jsonData = [[NSString stringWithContentsOfURL:[NSURL URLWithString:query] encoding:NSUTF8StringEncoding error:nil] dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NSDictionary *results = jsonData ? [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error] : nil;
if (error) NSLog(#"[%# %#] JSON error: %#", NSStringFromClass([self class]), NSStringFromSelector(_cmd), error.localizedDescription);
return results;
}
//returns JSON string from get request
+(NSString *)JSONgetString:(NSString *)query
{
NSString* searchURL = [NSString stringWithFormat:query];
NSError* error = nil; //error for NSUSRLConnection
NSURLResponse* response = nil;
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] init];
NSURL* URL = [NSURL URLWithString:searchURL];
[request setURL:URL];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setTimeoutInterval:30];
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error)
{
NSLog(#"Error performing request %#", searchURL);
return 0;
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"jsonString:%#", jsonString);
return jsonString;
}
+(NSString *)JSONpostString:(NSString *)query{
NSString* searchURL = [NSString stringWithFormat:query];
NSError* error = nil;
NSURLResponse* response = nil;
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] init];
NSURL* URL = [NSURL URLWithString:searchURL];
[request addValue: #"application/json" forHTTPHeaderField:#"Accept"];
[request addValue: #"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPMethod:#"POST"];
[request setURL:URL];
[request setTimeoutInterval:15];
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error)
{
NSLog(#"Error performing request %#", searchURL);
return 0;
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"jsonString:%#", jsonString);
return jsonString;
}
+(NSString *)JSONpostString:(NSString *)query
withData:(NSString *)jsonData
{
NSString* searchURL = [NSString stringWithFormat:query];
NSError* error = nil;
NSURLResponse* response = nil;
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] init];
NSURL* URL = [NSURL URLWithString:searchURL];
[request addValue: #"application/json" forHTTPHeaderField:#"Accept"];
[request addValue: #"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPMethod:#"POST"];
[request setURL:URL];
[request setTimeoutInterval:30];
NSData* requestData = [jsonData dataUsingEncoding:NSUTF8StringEncoding];
[request addValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:requestData];
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error)
{
NSLog(#"Error performing request %#", searchURL);
return 0;
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"jsonString:%#", jsonString);
return jsonString;
}
#end
NSDictionary *dictionary = [JSONHelper JSONget:#"http://iam.colum.edu/portfolio/api/course?json=True"];
for (id course in dictionary) {
NSLog(#"%#", [course substringFromIndex:8]);
}
As you can seen all those course number has the same pattern (so I assume that won't change) and it's xx-xxxx (7 character + whitespace after this). In that cas you can easily use substring fromthe index 8 (counting from 0).
Bu if you are still eager on how to do this in case when those course numbers may have various lengths yo can try using this solution:
NSDictionary *dictionary = [JSONHelper JSONget:#"http://iam.colum.edu/portfolio/api/course?json=True"];
for (id course in dictionary) {
NSArray *courseArray = [course componentsSeparatedByString:#" "];
NSMutableString *courseName = [NSMutableString string];
for (int i = 1; i < [courseArray count] ; i++) {
[courseName appendFormat:#"%# ", courseArray[i]];
}
// Deleting last character which is whitespace
[courseName substringToIndex:courseName.length -1];
NSLog(#"%#", courseName);
[courseName setString:#""];
}
It may not be the most efficent way to handle your problem but it just works!

Change NSURLConnection from sendSynchronousRequest to sendAsynchronousRequest? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
My Code for NSURLConnection with sendSynchronousRequest works fine but how can i change it to an async request? i tried a lot but nothing would work.
if the Request is empty i´ll get an empty Array with [[]] .
How can i catch it for an Alert Message?
Please help ...
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSString *urlString = #"http://www.xyz.at/sample.php";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
NSMutableData *body = [NSMutableData data];
NSString *postWerte = [NSString stringWithFormat:#"id=%#", self.textfeld.text];
[body appendData:[postWerte dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
NSError *error = nil;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
NSLog(#"Error: %#", error.description);
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
const char *convert = [returnString UTF8String];
NSString *responseString = [NSString stringWithUTF8String:convert];
NSMutableArray *meinErgebnis = [responseString JSONValue];
NSString *cycle = #"";
NSString *kopfdaten = [NSString stringWithFormat:#"Sendungsart: %#\r\nGewicht: %# kg\r\n\r\n", [[meinErgebnis objectAtIndex:0] objectForKey:#"ParcelTypeDescription"], [[meinErgebnis objectAtIndex:0] objectForKey:#"Weight"]];
cycle = [cycle stringByAppendingString:kopfdaten];
for(int i = 1; i < meinErgebnis.count; i++)
{
NSString *myValue = [NSString stringWithFormat:#"%# PLZ: %#\r\nStatus: %#\r\n\r\n",
[[meinErgebnis objectAtIndex:i] objectForKey:#"EventTimestamp"],
[[meinErgebnis objectAtIndex:i] objectForKey:#"EventPostalCode"],
[[meinErgebnis objectAtIndex:i] objectForKey:#"ParcelEventReasonDescription"]];
cycle = [cycle stringByAppendingString:myValue];
}
self.ergebnis.text = [NSString stringWithFormat:#"%#", cycle];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[self.textfeld resignFirstResponder];
You could:
create an NSOperationQueue, and
call sendAsynchronousRequest, placing all of your NSData processing code inside the completion block.
Thus, instead of:
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// now process resulting `data`
Use:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// now process resulting `data`
}];
Alternatively, you could implement the NSURLConnectionDataDelegate methods. For more information on that, see the Using NSURLConnection section of the URL Loading System Programming Guide.
You say "if the request is empty": I assume you mean "if the data returned is empty". And you say it is [[]]. If that's really what you're getting, it sounds like an array with one item (which itself, is an empty array). Or is it [] (which is an empty array)? Or is it nil?
I'm going to assume that the data returned was [], an empty array.
I'd also suggest you consider using NSJSONSerialization, the built in JSON parser, but obviously you can use JSONValue if you really want.
Finally, your implementation is skipping the first entry (NSArray uses a zero-based index). I'm assuming that was unintentional.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"%s: sendAsynchronousRequest error: %#", __FUNCTION__, error);
return;
}
NSError *parseError;
NSArray *meinErgebnis = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (parseError) {
NSLog(#"%s: JSONObjectWithData error: %#", __FUNCTION__, parseError);
return;
}
if ([meinErgebnis count] == 0) {
NSLog(#"%s: meinErgebnis empty", __FUNCTION__);
return;
}
for (NSDictionary *dictionary in meinErgebnis)
{
// now process each dictionary entry in meinErgebnis
}
// etc.
}];

RaptureXML weird behaviour

I am getting an error (well it doesn't shows, just crashes out of app, no info on console)
that seems to happen whenever i call the method Iterate from RXML's rootXML:
-(void)valueSearch {
//FIRST CONNECTION
NSString *serverAddress = #"http://www.commix.com.br/clientes/grupoglobo/apple/valor.xml";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:serverAddress]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
NSError *requestError;
NSURLResponse *urlResponse = nil;
response = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
//SECOND CONNECTION - Just an encapsulated form of the first, since i use it in other parts
// of the code
response = [self requestWithParameters:#"valor.xml"];
//i just uncommented both. but actually only one (connection) runs.
//Creation of the rooXML so i can grab the info i need
RXMLElement *rootXML = [RXMLElement elementFromXMLData:response];
//This array is where i'll keep the info from the files.
//it`s deallocated at the end in dealloc
searchResult = [[NSMutableArray alloc] init];
//This is the culprit. Atleast it seems so, since putting NSLog before and after
//revealed so.
[rootXML iterate:#"valor" usingBlock: ^(RXMLElement *valor) {
NSLog(#"valor: %#", [valor child:#"nome"].text);
[searchResult addObject:[valor child:#"nome"].text];
}];
}
The thing is, when i comment the requestWithParametersand use the normal non-encapsulated style (//FIRST CONNECTION) i don't get errors. But if i use the second, when the program reaches [rootXML iterate: [...]]it crashes there without warning.
using RaptureXML: https://github.com/ZaBlanc/RaptureXML
It also happens in another part of the code:
-(void)vehicleSearch {
NSString *path = [[NSBundle mainBundle] pathForResource:#"idArray" ofType:#"plist"];
NSMutableArray *idArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSMutableString *serverAddress = (#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[idArray objectAtIndex:0]);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:serverAddress]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
NSError *requestError;
NSURLResponse *urlResponse = nil;
response = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
RXMLElement *rootXML = [RXMLElement elementFromXMLData:response];
searchResult = [[NSMutableArray alloc] init];
[rootXML iterate:#"modelo" usingBlock: ^(RXMLElement *modelo) {
NSLog(#"modelo: %#", [modelo child:#"nome"].text);
[searchResult addObject:[modelo child:#"nome"].text];
}];
[idArray release];
}
Happens at the same line [rootXML iterate:].
Sorry for leaks and stuff, i'm inexperienced (thats why i'm here), Thanks!
EDIT:
ACTUALLY the culprit is the line
NSMutableString *serverAddress = (#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[idArray objectAtIndex:0]);
if i pass the parameter directly, without variables, it works:
NSMutableString *serverAddress = (#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=4");
it shows correctly.
Are you sure that ,[idArray objectAtIndex:0] is an NSString?
Try to use
[NSString stringWithFormat:#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[idArray objectAtIndex:0]];`
Or even
[NSString stringWithFormat:#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[[idArray objectAtIndex:0]stringValue]];
response = [self requestWithParameters:#"valor.xml"];
if response is a property use self.response otherwise you will have memory leak issues.