stringWithContentsofurl generate leaks - objective-c

im trying to get data via
NSString *string = [NSString
stringWithContentsOfURL: [NSURL
URLWithString: url]];
everything works fine, but when I run it with performance tool, it finds leaks on this line.
Here is whole mehod I use:
- (NSMutableDictionary *) getOutputImagesData: (URLParserImagesData) data
{
NSString *type = (data == URLParserImagesDataLatestImage) ? #"img" : #"size";
NSString *url = [NSString stringWithFormat: #"%s%s%s", [URLParserSiteURLforCategories UTF8String], [URLParserType UTF8String], [type UTF8String]];
//i get leaks here
NSString *string = [NSString stringWithContentsOfURL: [NSURL URLWithString: url]];
NSArray *imagesTemp = [string componentsSeparatedByString: #","];
NSMutableDictionary *outputImages = [NSMutableDictionary dictionary];
for(NSString *img in imagesTemp)
{
NSArray *splitStrings = [img componentsSeparatedByString: #"="];
if(data == URLParserImagesDataImagesCount)
{
NSNumber *integerValue = [NSNumber numberWithInt: [[splitStrings objectAtIndex:1] intValue]];
[outputImages setObject: integerValue forKey: [splitStrings objectAtIndex:0]];
}
else
[outputImages setObject: [splitStrings objectAtIndex:1] forKey: [splitStrings objectAtIndex:0]];
}
return outputImages;
}

There is nothing wrong in your code.

stringWithContentsOfURL: is deprecated. Try to use stringWithContentsOfURL:encoding:error: or stringWithContentsOfURL:usedEncoding:error: instead.

Related

FatSecret API "invalid signature"

Using this repository I was not able to make the queries work when oauth_token must be provided. I always get invalid signature. Tried a lot of solutions and tweaks in the code, nothing worked. Please help.
This is the code from the git mentioned:
NSString *OAuthorizationHeader(NSURL *url, NSString *method, NSData *body, NSString *_oAuthConsumerKey, NSString *_oAuthConsumerSecret, NSString *_oAuthToken, NSString *_oAuthTokenSecret)
{
NSString *_oAuthNonce = [NSString ab_GUID];
NSString *_oAuthTimestamp = [NSString stringWithFormat:#"%d", (int)[[NSDate date] timeIntervalSince1970]];
NSString *_oAuthSignatureMethod = #"HMAC-SHA1";
NSString *_oAuthVersion = #"1.0";
NSMutableDictionary *oAuthAuthorizationParameters = [NSMutableDictionary dictionary];
[oAuthAuthorizationParameters setObject:_oAuthNonce forKey:#"oauth_nonce"];
[oAuthAuthorizationParameters setObject:_oAuthTimestamp forKey:#"oauth_timestamp"];
[oAuthAuthorizationParameters setObject:_oAuthSignatureMethod forKey:#"oauth_signature_method"];
[oAuthAuthorizationParameters setObject:_oAuthVersion forKey:#"oauth_version"];
[oAuthAuthorizationParameters setObject:_oAuthConsumerKey forKey:#"oauth_consumer_key"];
if(_oAuthToken)
[oAuthAuthorizationParameters setObject:_oAuthToken forKey:#"oauth_token"];
// get query and body parameters
NSDictionary *additionalQueryParameters = [NSURL ab_parseURLQueryString:[url query]];
NSDictionary *additionalBodyParameters = nil;
if(body) {
NSString *string = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
if(string) {
additionalBodyParameters = [NSURL ab_parseURLQueryString:string];
}
}
// combine all parameters
NSMutableDictionary *parameters = [oAuthAuthorizationParameters mutableCopy];
if(additionalQueryParameters) [parameters addEntriesFromDictionary:additionalQueryParameters];
if(additionalBodyParameters) [parameters addEntriesFromDictionary:additionalBodyParameters];
// -> UTF-8 -> RFC3986
NSMutableDictionary *encodedParameters = [NSMutableDictionary dictionary];
for(NSString *key in parameters) {
NSString *value = [parameters objectForKey:key];
[encodedParameters setObject:[value ab_RFC3986EncodedString] forKey:[key ab_RFC3986EncodedString]];
}
NSArray *sortedKeys = [[encodedParameters allKeys] sortedArrayUsingFunction:SortParameter context:(__bridge void *)(encodedParameters)];
NSMutableArray *parameterArray = [NSMutableArray array];
for(NSString *key in sortedKeys) {
[parameterArray addObject:[NSString stringWithFormat:#"%#=%#", key, [encodedParameters objectForKey:key]]];
}
NSString *normalizedParameterString = [parameterArray componentsJoinedByString:#"&"];
NSLog(#"normalizedParameters: %#", normalizedParameterString);
NSString *normalizedURLString;
if ([url port] == nil) {
normalizedURLString = [NSString stringWithFormat:#"%#://%#%#", [url scheme], [url host], [url path]];
} else {
normalizedURLString = [NSString stringWithFormat:#"%#://%#:%#%#", [url scheme], [url host], [url port], [url path]];
}
NSString *signatureBaseString = [NSString stringWithFormat:#"%#&%#&%#",
[method ab_RFC3986EncodedString],
[normalizedURLString ab_RFC3986EncodedString],
[normalizedParameterString ab_RFC3986EncodedString]];
NSLog(#"signature base: %#", signatureBaseString);
NSString *key = [NSString stringWithFormat:#"%#&%#&",
[_oAuthConsumerSecret ab_RFC3986EncodedString],
[_oAuthTokenSecret ab_RFC3986EncodedString]];
NSLog(#"key codes: %#", key);
NSData *signature = HMAC_SHA1(signatureBaseString, key);
NSString *base64Signature = [signature base64EncodedString];
// PARKER CHANGE: changed oAuthAuthorizationParameters to parameters
NSMutableDictionary *authorizationHeaderDictionary = [parameters mutableCopy];
[authorizationHeaderDictionary setObject:base64Signature forKey:#"oauth_signature"];
NSMutableArray *authorizationHeaderItems = [NSMutableArray array];
for(NSString *key in authorizationHeaderDictionary) {
NSString *value = [authorizationHeaderDictionary objectForKey:key];
NSLog(#"KEY: %#", key);
NSLog(#"VALUE: %#", value);
// PARKER CHANGE: removed quotes that surrounded each value
[authorizationHeaderItems addObject:[NSString stringWithFormat:#"%#=%#",
[key ab_RFC3986EncodedString],
[value ab_RFC3986EncodedString]]];
}
// PARKER CHANGE: changed concatentation string from ", " to "&"
NSString *authorizationHeaderString = [authorizationHeaderItems componentsJoinedByString:#"&"];
// authorizationHeaderString = [NSString stringWithFormat:#"OAuth %#", authorizationHeaderString];
NSLog(#"final: %#", authorizationHeaderString);
return authorizationHeaderString;
}
And this is how I'm calling it:
- (void) makeUserRequestWithMethod:(NSString *)method
parameters:(NSDictionary *)params
completion:(void (^)(NSDictionary *data))completionBlock {
NSLog(#"%s", __func__);
NSMutableDictionary *parameters = [params mutableCopy];
[parameters addEntriesFromDictionary:[self defaultParameters]];
[parameters addEntriesFromDictionary:#{ #"method" : method }];
NSString *queryString = [self queryStringFromDictionary:parameters];
NSData *data = [NSData dataWithBytes:[queryString UTF8String] length:queryString.length];
NSString *authHeader = OAuthorizationHeader([NSURL URLWithString:FAT_SECRET_API_ENDPOINT],
#"POST",
data,
_oauthConsumerKey,
_oauthConsumerSecret,
_oAuthToken,
_oAuthTokenSecret
);
NSLog(#"header: %#", authHeader);
NSURL *url = [NSURL URLWithString:[FAT_SECRET_API_ENDPOINT stringByAppendingFormat:#"?%#", authHeader]];
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (data) {
id JSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
completionBlock(JSON);
} else {
completionBlock(nil);
}
}] resume];
}
I'm going to go out on a limb here and say that the code that others have proven to work is probably not at fault here, but rather first look at your own code. You say the error messages is "Invalid Signature" which sounds like it's a warning from the server you're calling, not from the code you're using.
[parameters addEntriesFromDictionary:[self defaultParameters]];
[parameters addEntriesFromDictionary:#{ #"method" : method }];
NSString *queryString = [self queryStringFromDictionary:parameters];
What happens inside [self defaultParameters] and are you 100% certain the parameters are appropriate (including spelling) for the API you're calling?
Have you verified that [self queryStringFromDictionary:parameters] prepares a properly formatting query string, and isn't introducing some error (non-escaped special characters, or percent encoding, for example)?

Error : -[NSURL rangeOfString:]: unrecognized selector sent to instance 0x6180000a0de0

I need help identifying my error. Does anyone know why it errors?
if (result == NSFileHandlingPanelOKButton) {
NSString *filePath = [[openPanel URLs] objectAtIndex:0];
NSLog(#"%#", filePath);
*CODE WORKS UP TO HERE*
NSString *strTemp = [self extractString:filePath toLookFor:#"//" skipForwardX:2 toStopBefore:#".png"];
NSLog(#"%#",strTemp);
NSString *copyScript = [NSString stringWithFormat:#"%# /tmp/%#.png", strTemp, myString];
strTemp = [[NSString alloc] init];
NSString *path = #"/Applications/APP.app/Contents/Resources/copy.sh";
NSArray *args = [NSArray arrayWithObjects:copyScript, nil];
[[NSTask launchedTaskWithLaunchPath:path arguments:args] waitUntilExit];
NSString* linkName = #"/tmp/";
NSString* extension = #".png";
NSString* fullPath = [NSString stringWithFormat:#"%#%#%#", linkName, myString, extension];
urlPathOfFile = [NSString stringWithFormat:#"URL/%#%#", myString, extension];
fileURL = [NSURL URLWithString:fullPath];
action = upload;
[self runAction];
Is it a memory error because I have too many strings?
There's a high probability that filePath points to a NSURL object, not NSString.

How can I convert the values is an NSDictionary into an NSString?

I have a method in Objective-c that takes in an NSDictionary and returns the values as a space-separated NSString. This application is cross-platform, and as such I cannot use fast enumeration. This is what I have so far, followed by the output (which shows that the String is never created):
-(NSString *)stringValuesFromDict:(NSDictionary *map)
{
NSArray *values = [map allValues];
NSString *params = [NSString string];
NSLog(#"values length: %d", [values count]);
NSLog(#"values = %#", [values description]);
for (int i = 0; i < [values count]; i++)
{
[params stringByAppendingString:[values objectAtIndex:i]];
[params stringByAppendingString:#" "];
}
NSLog(#"params = %#", params);
return params;
}
The NSDictionary:
{"arg1"="monkey"}
The output:
values length: 1
values = (
monkey
)
params =
What am I doing wrong? How can I get params to be set to monkey?
If I read the question correctly, all you need is
[[dict allValues] componentsJoinedByString:#" "]
You need a mutable string. Change this:
NSString *params = [NSString string];
to this:
NSMutableString *params = [NSMutableString string];
Then change these:
[params stringByAppendingString:[values objectAtIndex:i]];
[params stringByAppendingString:#" "];
to these:
[params appendString:[values objectAtIndex:i]];
[params appendString:#" "];
stringByAppendingString: returns a new string. So you would have to do something like this:
params = [params stringByAppendingString:[values objectAtIndex:i]];
But the disadvantage is, that every time a new string is created, which is wasting memory
You should propably use a NSMutableString instead. And then you can just call
[params appendString:[values objectAtIndex:i]];

Can't record or play with a simple recorder?

I have 2 classes, a record and a player. In my main scene, I create an instance of them and play and record. But, as I see, it only records and somehow does not play (the file is not there!)
Here is the code for both :
-(void)record {
NSArray *dirPaths;
NSString *docsDir;
NSString *sound= #"sound0.caf" ;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ;
docsDir = [dirPaths objectAtIndex:0];
NSString *soundFilePath = [docsDir stringByAppendingPathComponent:sound];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax],
AVEncoderAudioQualityKey, nil];
NSError *error;
myRecorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:settings error:&error];
if (myRecorder) {
NSLog(#"rec");
[myRecorder prepareToRecord];
myRecorder.meteringEnabled = YES;
[myRecorder record];
} else
NSLog( #"error" );
}
I can see the log of rec.
-(void)play {
NSArray *dirPaths;
NSString *docsDir;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *soundFilePath1 = #"sound0.caf" ;
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath1];
BOOL isMyFileThere = [[NSFileManager defaultManager] fileExistsAtPath:soundFilePath1];
if(isMyFileThere) {
NSLog(#"PLAY");
avPlayer1 = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:NULL];
avPlayer1.volume = 8.0;
avPlayer1.delegate = self;
[avPlayer1 play];
}
}
I DONT SEE THE LOG OF PLAY !
I call them both with:
recInst=[recorder alloc]; //to rec
[recInst record];
plyInst=[player alloc]; //play
[plyInst play];
and to stop the recorder:
- (void)stopRecorder {
NSLog(#"stopRecordings");
[myRecorder stop];
//[myRecorder release];
}
What's wrong here? Thanks.
In your record method, you're appending the file name to the path with:
NSString *soundFilePath = [docsDir stringByAppendingPathComponent:#"sound0.caf"];
You do not do that in your play method, so it's looking for the file in whatever the current working directory is, rather than the Documents directory.
You need to do:
NSString *soundFilePath1 = [docsDir stringByAppendingPathComponent:#"sound0.caf"];
instead of:
NSString *soundFilePath1 = #"sound0.caf" ;
And just another note: soundFilePath and soundFilePath1 are both local variables. Therefore, they are not visible outside their respective methods. Thus, it's not necessary to give them different names. You can call them both soundFilePath and there will not be a conflict.

JSON representation of NSDictionary

In my app a user can create UITextFields. to each field a tag is added, so that the tags correspond to the cases: 1, 2, 3, 4, ... then I add everything in a NSDictionary, and a json representation:
-(IBAction)buttonDropBoxuploadPressed:(id)sender{
//screenshot
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy_MM_dd"];
NSString *filename = [NSString stringWithFormat:#"By: %# ",
[formatter stringFromDate:[NSDate date]]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:#"%#", filename] ];
//[data writeToFile:path atomically:YES];
//NSString *destDir = #"/sandbox/";
// [[self restClient] uploadFile:filename toPath:destDir
// withParentRev:nil fromPath:path];
// [[self restClient] loadMetadata:#"/sandbox/"];
//JSON
NSString *object;
NSString *object2;
NSString *object3;
NSString *object4;
NSString *object5;
NSString *object6;
NSString *object7;
NSString *object8;
NSString *object9;
NSString *object10;
NSString *object11;
NSString *object12;
NSString *object13;
NSString *object14;
NSString *object15;
for (UITextField *text in messagename) {
int touchedtag = text.tag;
NSUInteger tagCount = touchedtag;
switch (tagCount) {
case 1:
object = [NSString stringWithFormat:#"%#", text.text];
break;
case 2:
object2 = [NSString stringWithFormat:#"%#", text.text];
break;
case 3:
object3 = [NSString stringWithFormat:#"%#", text.text];
break;
case 4:
object4 = [NSString stringWithFormat:#" %#", text.text];
break;
case 5:
object5 = [NSString stringWithFormat:#"%#", text.text];
break;
case 6:
object6 = [NSString stringWithFormat:#"%#", text.text];
break;
case 7:
object7 = [NSString stringWithFormat:#"%#", text.text];
break;
case 8:
object8 = [NSString stringWithFormat:#"%#", text.text];
break;
case 9:
object9 = [NSString stringWithFormat:#"%#", text.text];
break;
case 10:
object10 = [NSString stringWithFormat:#"%#", text.text];
break;
case 11:
object11 = [NSString stringWithFormat:#"%#", text.text];
break;
case 12:
object12 = [NSString stringWithFormat:#"%#", text.text];
break;
case 13:
object13 = [NSString stringWithFormat:#"%#", text.text];
break;
case 14:
object14 = [NSString stringWithFormat:#"%#", text.text];
break;
case 15:
object15 = [NSString stringWithFormat:#"%#", text.text];
break;
default :
break;
}
}
//arrays
NSString * objects[] = { object, object2, object3, object4, object5, object6, object7, object8, object9, object10, object11, object12, object13, object14, object15};
NSMutableArray *textnameobject = [[NSMutableArray alloc] initWithCapacity:b];
textnameobject = [NSMutableArray arrayWithObjects:objects count:b];
NSMutableArray *textnamekeys = [[NSMutableArray alloc] initWithCapacity:b];
NSString * textnumber[] = {#"title", #"title", #"title",#"title", #"title", #"title", #"title", #"title", #"title", #"title", #"title", #"title", #"title", #"title"};
textnamekeys = [NSMutableArray arrayWithObjects:textnumber count:b];
//arrays
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObject: textnameobject forKey:textnamekeys];
/*
NSArray *objects2 = [NSArray arrayWithObjects:jsonDictionary, nil];
NSArray *keys2 = [NSArray arrayWithObjects:allkeys, nil];
NSDictionary *mainDict = [NSDictionary dictionaryWithObjects:objects2 forKeys:keys2];
*/
NSString* jsonString = [jsonDictionary JSONRepresentation];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
[jsonData writeToFile:path atomically:YES];
NSString *destDir = #"/sandbox/";
[[self restClient] uploadFile:filename toPath:destDir
withParentRev:nil fromPath:path];
[[self restClient] loadMetadata:#"/sandbox/"];
//JSON
}
When I press the button I get the following error:
JSONRepresentation failed. Error trace is: (
"Error Domain=org.brautaset.JSON.ErrorDomain Code=1 \"JSON object key must be string\" UserInfo=0x2e8370 {NSLocalizedDescription=JSON object key must be string}"
)
and consequentially a dropbox error. this worked on my previous app and the code is exactly the same. the json library is added correctly. I can't understand!! Please help!
Your code, rewritten.
- (IBAction)buttonDropBoxUploadPressed: (id)sender
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat: #"yyyy_MM_dd"];
NSString *filename = [NSString stringWithFormat: #"By: %# ", [formatter stringFromDate: [NSDate date]]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex: 0];
NSString *path = [documentsDirectory stringByAppendingPathComponent: filename];
NSMutableDictionary *titles = [NSMutableDictionary dictionary];
for (UITextField *textField in messagename)
{
[titles setObject: textField.text forKey: #"title"];
// as you can see, here you're replacing the value # at key "title" with a new object on every pass
}
NSString *jsonString = [titles JSONRepresentation];
NSData *jsonData = [jsonString dataUsingEncoding: NSUTF8StringEncoding];
[jsonData writeToFile: path atomically: YES];
NSString *destDir = #"/sandbox/";
[[self restClient] uploadFile: filename toPath: destDir withParentRev: nil fromPath: path];
[[self restClient] loadMetadata: #"/sandbox/"];
}
However, regarding my comment, you're not actually serializing your text fields' text into anything usable. At the end of this, at best, you'll have something that looks like this:
{
"title": "My Text Field Value"
}
Though I'm also relatively certain that one or more of your text fields' text is nil, which is causing your JSON problem.