NSString.length gives EXC_BAD_ACCESS - objective-c

I have the following code:
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
NSString *temp;
for (int i = 0; i < [array count]; i++)
{
temp = [array objectAtIndex:i];
NSLog(#"temp length = %#", [temp length]);
}
I get an EXC_BAD_ACCESS error at the NSLog line. I assume it's erring out at the [temp length] bit. The weird thing is, I can do other methods of NSString on temp and they work fine, like [temp characterAtIndex:0].
I've also tried doing [[array objectAtIndex:i] retain];, but that doesn't seem to help.
Does anyone know why I'm getting this error?
EDIT: Turns out it was crashing at the NSLog because it was %# instead of %lu. The real problem was with other code that I had omitted from this post. After playing around with it some more, I got it working.

From my understanding, the "%#" placeholder is for object pointers, "length" returns "NSUInteger" which is not a pointer. Try "%lu" instead of "%#".

This (slightly cleaned up) version works for me:
NSError *error = nil;
NSString *path = [#"~/Desktop" stringByExpandingTildeInPath];
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:
path error:&error];
if (error) NSLog(#"%#", error);
for (NSString *path in array) {
NSLog(#"Path length = %lu", path.length);
}
As thg435 mentioned, "%#" is for object pointers, so if you pass it an arbitrary number it will throw a memory access error.

Related

How to convert NSData which contains a line break to a NSString

The following code works perfectly to convert the NSData that I got from a URL/JSON file to a NSString, EXCEPTION MADE by the cases that data contains line breaks!
What's wrong with my code?
My Code:
NSError *errorColetar = nil;
NSURL *aColetarUrl = [[NSURL alloc]initWithString:#"http://marcosdegni.com.br/petsistema/teste/aColetar3.php"];
NSString *aColetarString = [NSString stringWithContentsOfURL:aColetarUrl encoding:NSUTF8StringEncoding error:&errorColetar];
NSLog(#"NSString: %#", aColetarString);
if (!errorColetar) {
NSData *aColetarData = [aColetarString dataUsingEncoding:NSUTF8StringEncoding];
self.arrayAColetar = [NSJSONSerialization JSONObjectWithData:aColetarData options:kNilOptions error:nil];
}
NSLog(#"arrayAColetar %#", self.arrayAColetar);
Log Results:
**NSString**: [{"id_atendimento":"2","observacoes":"ABC-Enter-->
DEF-Enter-->
GFH-END"},{"id_atendimento":"1","observacoes":"123Enter-->
345Enter-->
678End"}]
**arrayAColetar** (null)
As you can see my bottom line is an empty array :(
Thanks in advance!
By checking the error message hidden under 'error:nil' I found a "Unescaped control character around character" issue and implemented the code below from Unescaped control characters in NSJSONSerialization
and got a new 'cleaned' string.
- (NSString *)stringByRemovingControlCharacters: (NSString *)inputString {
NSCharacterSet *controlChars = [NSCharacterSet controlCharacterSet];
NSRange range = [inputString rangeOfCharacterFromSet:controlChars];
if (range.location != NSNotFound) {
NSMutableString *mutable = [NSMutableString stringWithString:inputString];
while (range.location != NSNotFound) {
[mutable deleteCharactersInRange:range];
range = [mutable rangeOfCharacterFromSet:controlChars];
}
return mutable;
}
return inputString;
}

[__NSCFString count]: Unrecognized selector

I know this has been asked before, but there is no answer that I have found useful.
First off here is my code
// load the .csv file with all information about the track
NSError *error;
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"file" ofType:#"csv" inDirectory:nil];
NSString *datastring1 = [NSString stringWithContentsOfFile:filepath encoding:NSUTF8StringEncoding error:&error];
NSArray *datarow = [datastring1 componentsSeparatedByString:#"\r"];
//fill arrays with the values from .csv file
NSArray *data_seg = [datarow objectAtIndex:0]; //segment number
NSArray *data_slength = [datarow objectAtIndex:1]; //strait length
NSArray *data_slope = [datarow objectAtIndex:2]; //slope
NSArray *data_cradius = [datarow objectAtIndex:3]; //circle radius
NSArray *data_cangle = [datarow objectAtIndex:4]; //circle angle
NSLog(#"%i", [data_seg count]);
Okay, so there is the code, and I read that is has something to do with autorelease, but I was not able to add a retain like NSArray *data_seg = [[datarow objectAtIndex:0] retain]
When I run the code, I get [__NSCFString count]: unrecognized selector sent to instance 0x9d1ad50
Any help is appreciated, I'm not good at programming, and I am very new.
componentsSeparatedByString method returns an NSArray of NSString. Every item that you extract from datarow array is an NSString and an NSString doesn't respond to 'count'. Your code starting at //fill arrays is incorrect. Every objectAtIndex call will return an NSString*.
This is another way of saying that the datatype for data_seg is NSString* (not NSArray*).
With the corrected code snippet, the problem is because data_seg is a string, and -count is not a method of NSString. It seems you think data_seg is an NSArray.
Look at the documentation for -[NSString componentsSeparatedByString:] and see what it returns -- strings! So you get back an array of strings. So what you want is:
NSString *data_seg = [datarow objectAtIndex:0]; //segment number
NSLog(#"my segment number is: %#", data_seg);

Determine folder Size

With this code I determine the file size if the checkbox is NSOnState, but with a folder value is always 0. The directory is correct.
Can you help me?
unsigned long long resultsize=0;
if(imagehistoryS.state == NSOnState) {
NSString *path = [NSString stringWithFormat:#"Users/Giovanni/Desktop/test", [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
NSNumber *fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil] objectForKey:NSFileSize];
resultsize += [fileSize doubleValue];
}
[result setStringValue:[NSString stringWithFormat:#"Total size items selected: %f", resultsize]];
You're passing in a string, and yet specifying the NSUserDomainMask. I've tried this and it works.
NSUInteger resultSize = 0;
NSFileManager *fm = [[NSFileManager alloc] init];
NSURL *LibraryURL = [[fm URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *previewsURL = [LibraryURL URLByAppendingPathComponent:#"/Caches/com.apple.Safari/Webpage Previews"];
resultSize = [[[fm attributesOfItemAtPath:[previewsURL path] error:nil] objectForKey:NSFileSize] unsignedIntegerValue];
NSLog(#"Size: %lu", resultSize);
This is for an ARC environment.
Note, I'm using NSURLs instead of NSString filepaths as much as possible. Also, you don't need to hardcode the user's name in the search path.
Updated to show the specific folder as requested in the comments
In you stringWithFormat you are missing the format specifier %#.

EXC_BAD_ACESS error

I get that error EXC_BAD_ACESS at the following line:
NSString *titleVarName = [[NSString alloc] initWithFormat:#"%#%#",#"occasionTitle",i];
Here is the for loop where the above code line is located:
for (i=0; i < count; ++i)
{
//Save the occasionS details to NSUserDefaults
NSString *titleVarName = [[NSString alloc] initWithFormat:#"%#%#",#"occasionTitle",i];
NSString *dateVarName = [[NSString alloc] initWithFormat:#"%#%#",#"occasionDate",i];
NSString *imageVarName = [[NSString alloc] initWithFormat:#"%#%#",#"occasionImage",i];
[[NSUserDefaults standardUserDefaults] setValue:[[[self displayedObjects] objectAtIndex:i]
title] forKey:titleVarName];
[[NSUserDefaults standardUserDefaults] setValue:[[[self displayedObjects] objectAtIndex:i]
date] forKey:dateVarName];
[[NSUserDefaults standardUserDefaults] setValue:[[[self displayedObjects] objectAtIndex:i]
imagePath] forKey:imageVarName];
//release
[titleVarName release];
[dateVarName release];
[imageVarName release];
[self dismissModalViewControllerAnimated:YES];
}
Isn't ok to alloc objects and release them inside a for loop?
You need to use %d or %i specifier instead of %# to specify an integer. If %# is used with int then it will try to access the object at the address specified by the int. For example, if the value of i is one then it is trying to access the object at address one which will cause a bad access.
NSString *titleVarName = [[NSString alloc] initWithFormat:#"%#%d",#"occasionTitle",i];
And also you don't need alloc and release here, though that is not the reason of bad access. You can use a convenience constructor.
NSString *titleVarName = [NSString stringWithFormat:#"occasionTitle%d", i];
// release not required
Do the same for dateVarName and imageVarName too.
Assuming i is an int, that line should be
NSString *titleVarName = [[NSString alloc] initWithFormat:#"%#%i",#"occasionTitle",i];
%# is used for Cocoa objects, not primitives like an int, float or bool;
Use the %# format specifier only for NSObject objects.
As i is an integer in your code, you have to use %d or %i for integers.
Moreover, there is no need to include the string using %#, you can use the static string directly in your format string:
NSString *titleVarName = [[NSString alloc] initWithFormat:#"occasionTitle%i",i];

Alter NSString to get nothing back

At two stages of my app's runtime, I am sending an NSString to the following method.
I receive no warnings or errors in the code editor or the debugger, but when I NSLog the output (secondString), I only get given the memory address of the object.
Is there something I am not doing right here?
- (NSString*)validateString
{
NSString *firstString = [NSString stringWithFormat:#"%#", self];
[firstString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSMutableString *secondString = [firstString mutableCopy];
[secondString replaceOccurrencesOfString:#"&" withString:#"%26" options:NSCaseInsensitiveSearch range:NSMakeRange([secondString length], 0)];
secondString = [NSString stringWithFormat:#"%#", secondString];
NSLog (#"%# and %#", firstString, secondString);
return secondString;
[firstString release];
[secondString release];
}
I'd appreciate any help.
Thanks,
Ricky.
Ugh that code is wrong on so many levels.
Here's a simpler version:
- (NSString*)validateString {
NSString *firstString = [self stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *secondString = [firstString stringByReplacingOccurrencesOfString:#"&" withString:#"%%26" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [firstString length])];
NSLog (#"%# and %#", firstString, secondString);
return secondString;
}
The construct [NSString stringWithFormat:#"%#", aString] is a pretty useless statement, especially when you have copy available. You also have a memory leak and a crash in your code (you create a copy of a string [+1 retain count], assign an autoreleased string into the same variable [+0 retain count, original string lost and leaked], and then release the autoreleased string [crash when the autorelease pool drains]).
First some comments:
1) Everything after the return will not be executed, so the last to statements are useless (dead code).
2) If not created with +alloc, you can assumed that NSString instances are autoreleased, thus you do not need to send the -release message to firstString.
Edit: As Peter Hosey pointed out, you must however release the string obtained by -mutableCopy.
To answer your question:
-stringByAddingPercentEscapesUsingEncoding: returns a pointer to the newly created instance, so you have to save it.
- (NSString*)validateString
{
NSString *firstString = [NSString stringWithFormat:#"%#", self];
firstString = [firstString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSMutableString *secondString = [firstString mutableCopy];
[secondString replaceOccurrencesOfString:#"&" withString:#"%26" options:NSCaseInsensitiveSearch range:NSMakeRange([secondString length], 0)];
secondString = [NSString stringWithFormat:#"%#", secondString];
NSLog (#"%# and %#", firstString, secondString);
[secondString release];
return secondString;
}
You need to use %%26 if you want the string "%26"
your NSMakeRange is backwards
your return is too early, and you don't need to release the strings anyway