Xcode IOS5 retrieve filenames - objective-c

I wish to retrieve all filenames from the root directory with the extension *.gs and store them in an array.
I tried using directoryContentsAtPath.. but it says that this method has been deprecated in ios5. Do you know any alternatives?

You should use NSFileManager's:
– contentsOfDirectoryAtPath:error:
(See Apple's documentation on NSFileManager.)
You will end up with something like:
NSString *path = #"your/path";
NSError *error = nil;
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error];
If you feel you don't need to check for a potential error, you may pass nil for the error argument. However, I would recommend that you check whether an error occurred and display an appropriate error message in that case. You could do it like so:
if (error) {
// display some error message here
} else {
// process filenames returned by NSFileManager
}

Related

Xcode 5 [NSString writeToFile] without absolute path

I've checked out a few other posts about this topic, but I am still left with some doubt on whether or not [NSString writeToFile] is writing to the relative path.
NSError *error = nil;
BOOL success = [str writeToFile:#"someFile.txt"
atomically:YES
encoding:NSUTF8StringEncoding
error:&error];
NSString *status = success ? #"Success" : #"Failure";
if(success){
NSLog(#"Done Writing: %#",status);
}
else{
NSLog(#"Done Writing: %#",status);
NSLog(#"Error: %#",[error localizedDescription]);
}
writeToFile works when given the path to a certain folder and by NSLogging the error, I can see what kind of error occurs. However, when running the above code, no error occurs and after having done a thorough search, I think I can safely say that a file was never created. What's going on behind the scenes?
Well it's certainly working, which you confirm yourself as your code traps and reports errors very nicely. Your only issue is that you don't know where the file is being written to, and in this case, as no path has been specified it will be to the current working directory, which is a concept in pretty much all operating systems (even Windows!).
I must admit that I don't know what the default current working directory is under iOS, but you can find out yourself with:
NSString *cwd = [[NSFileManager defaultManager] currentDirectoryPath];
NSLog(#"cwd='%#'", cwd);

Objective-C error handling

anyone know how I can handle error code when there is an error on the following:
database_flag = [NSString stringWithContentsOfURL:database_flag_query encoding:NSASCIIStringEncoding error:&error];
TO explain more please find below my code
Basically I want to check mysql for a flag
if the flag is 1 then i get the ip address of the stream from the databse
else i use the local one store.
the only issue is when there is not access to the mysql server the program gets stuck!!
database_flag_query = [NSURL URLWithString:#"http://192.168.0.20/iqkradio_stream_ip_flag.php"];
database_flag = [NSString stringWithContentsOfURL:database_flag_query encoding:NSASCIIStringEncoding error:&error];
database_flag = [database_flag stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([database_flag isEqualToString: #"1"])
{
NSLog(#"URL flag is set");
database_url_query = [NSURL URLWithString:#"http://192.168.0.20/iqkradio_stream_ip_url.php"];
database_url = [NSString stringWithContentsOfURL:database_url_query encoding:NSASCIIStringEncoding error:&error];
database_url = [database_url stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
url1 = [NSURL URLWithString:[database_url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSLog(database_url);
}
else
{
NSLog(#"URL flag is not set, Reverting to stored value");
url1 = [NSURL URLWithString: [NSString stringWithFormat: #"http://radio.qkradio.com.au:8382/listen.mp3"]];
}
streamer = [[AudioStreamer alloc] initWithURL:url1];
EDIT - NSURLConnection & Timeouts - Based on the additional information and the comment stream below, and to put information in the answer (rather than the long comment stream):
see accepted answer to this question here for the timeout example. For the NSURLConnection example, checkout the apple documentation here
General Error Handling -
The following link may be helpful --> http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/ErrorHandling/ErrorHandling.html.
"Before you call this method, you’ll need to create a suitable pointer so that you can pass its address:
NSError *anyError;
BOOL success = [receivedData writeToURL:someLocalFileURL
options:0
error:&anyError];
if (!success) {
NSLog(#"Write failed with error: %#", anyError);
// present error to user
}
If an error occurs, the writeToURL:... method will return NO, and update your anyError pointer to point to an error object describing the problem.
When dealing with errors passed by reference, it’s important to test the return value of the method to see whether an error occurred, as shown above. Don’t just test to see whether the error pointer was set to point to an error."
So, for your issue, try adding:
if(!database_flag)
{
//call your error handling function
[myFunction withError: error];
}
before trimming the database_flag. If your connection isn't working, then you need to handle it before continueing to your if([database_flag isEqualToString:... code.
If that doesn't solve the problem, can you give some information/log statements on where/what the error is that is halting your application?
Hope that helps.

NSFileManager copyItemAtPath complains about a nonexistent file that does exist

I am trying to copy a file using [[NSFileManager defaultManager] copyItemAtPath: toPath: error:] but it is failing with the following error:
4: The file does not exist.
The relevant code is below, and the file does exist and the path string is correct because it is created beforehand with the exact same file path string.
NSFileManager* manager = [NSFileManager defaultManager];
NSError* error;
NSString* fileName = [Sound getFileName:Title];
NSString* oldDirectory = [NSString stringWithFormat:#"%#%#/", [settings stringForKey:#"downloadFolder"], authorFolder];
NSString* oldFile = [oldDirectory stringByAppendingFormat:#"%#.mp3", fileName];
NSString* newFile = [NSString stringWithFormat:#"%#/iTunes/iTunes Media/Automatically Add to iTunes/%#.mp3", [NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES) objectAtIndex:0], fileName];
BOOL result = [manager copyItemAtPath:oldFile toPath:newFile error:&error];
if (!result && error)
{
NSLog(oldFile);
NSLog(#"There was an error copying the file to the iTunes directory! %#", [error localizedDescription]);
}
It's not the exact code, but all relevant code should be above. If I use [manager fileExistsAtPath:oldFile] the result is YES.
What could cause the copy to fail and say the file doesn't exist, even if it does?
UPDATE:
Issue fixed. Turns out the output folder was really Automatically Add to iTunes.localized, but I didn't notice this initially when just paging through the finder. Fixing the output path solved the issue! Thanks for the help.
If any of the directories in the path of the destination don't exist, you'll get a similar error to what you'd get if the source doesn't exist. Check what [manager fileExistsAtPath:[newFile stringByDeletingLastPathComponent] isDirectory:&isDir] returns.
You're using the API wrong. You need to look at the return value of -copyItemAtPath:toPath:error:. Only if that returns NO does that mean an error occurred.
If you're using ARC, your error variable should be nil if no error occurred (although this isn't technically guaranteed), but if you're using MRR it probably won't, because you never initialized it.

How to initialize, pass argument, and check error condition using NSError**

Xcode 4.3
I've read the SO questions on NSError**, so I wrote a simple test program that uses a slightly different syntax recommended by Xcode 4.3 (see __autoreleasing below), so I'm not 100% sure if this is correct, although the code does appear to function properly. Anyway, just a simple file reader, prints an error if the file can't be found.
Questions
Would like to know if the NSError initialization, argument passing using &, and error condition checking are correct.
Also, in the readFileAndSplit.. method, I noticed a big difference between if(!*error) and if(!error), in fact, if(!error) does not work when no error condition is raised.
File Reading Method w/Possible Error Condition
-(NSArray*) readFileAndSplitLinesIntoArray:(NSError *__autoreleasing *) error {
NSString* rawFileContents =
[NSString stringWithContentsOfFile:#"props.txt"
encoding:NSUTF8StringEncoding
error:error
NSArray* fileContentsAsArray = nil;
if(!*error)
fileContentsAsArray =
[rawFileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
return fileContentsAsArray;
Caller
SimpleFileReader* reader = ...
NSError* fileError = nil;
NSArray* array = [reader readFileAndSplitLinesIntoArray: &fileError];
if(fileError){
NSLog(#"Error was : %#, with code: %li",
[fileError localizedDescription],(long)[fileError code]);
}
There are a couple of issues.
First, As per Apple's Error Handling Programming Guide, you should be checking a method's return value to determine whether a method failed or not, and not NSError. You only use NSError to get additional error information in the event that the method failed.
E.g.:
NSArray* fileContentsAsArray = nil;
NSString* rawFileContents = [NSString stringWithContentsOfFile:#"props.txt"
encoding:NSUTF8StringEncoding
error:error];
if (rawFileContents)
{
// Method succeeded
fileContentsAsArray = [rawFileContents ...];
}
return fileContentsAsArray; // may be nil
Second, NSError out parameters are typically optional and may be NULL. But if you pass a NULL error variable into your method it will crash on this line:
if (!*error) {
because you're dereferencing a NULL pointer. Instead, you must always check for NULL before referencing a pointer, like so:
if (error && *error)
{
// Do something with the error info
}
However, if you rewrite the method as indicated above then you won't be accessing the error variable at all.

NSError: Does using nil to detect Error actually turn off error reporting?

I got into the habit of coding my error handling this way:
NSError* error = nil;
NSDictionary *attribs = [[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
if (error != nil) {
DLogErr(#"Unable to remove file: error %#, %#", error, [error userInfo]);
return;
}
But looking at the documentation It seems like I got this wrong.:
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
If an error occurs, upon return contains an NSError object that describes the problem. Pass NULL if you do not want error information.
Technically there is no difference between nil and NULL so does this mean I'm actually turning this off and will never get a error message (even if the delete in the above example did fail) ?
Is there a better way to code this ?
Thanks.
First off, the following line doesn't really make sense:
NSDictionary *attribs = [[NSFileManager defaultManager]
removeItemAtPath:fullPath error:&error];
-removeItemAtPath:error: returns a BOOL value, not a dictionary.
I think I see what you’re wondering about with the NULL value. Notice carefully though, how there are 2 *'s in the error parameter in the method signature:
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
That means a pointer to a pointer. When you pass in &error, you are passing in the address of the pointer to the NSError. (Ugh, someone else can probably help me out here, as my head still starts to swim when dealing with pointers to pointers). In other words, even though you have set error to nil, you aren't passing in error to the method, you're passing in &error.
So, here’s what the re-written method should look like:
// If you want error detection:
NSError *error = nil;
if (![[NSFileManager defaultManager] removeItemAtPath:fullPath
error:&error]) {
NSLog(#"failed to remove item at path; error == %#", error);
// no need to log userInfo separately
return;
}
// If you don't:
if (![[NSFileManager defaultManager] removeItemAtPath:fullPath
error:NULL]) {
NSLog(#"failed to remove item at path");
return;
}
Passing NULL means the following:
BOOL itemRemoved = [[NSFileManager defaultManager] removeItemAtPath:fullPath
error:NULL];
i.e., the error parameter is NULL. Internally, -removeItemAtPath:error: sees if a valid pointer was passed. If it’s NULL, it simply won’t report the error as an NSError instance — but the return value will indicate whether the method completed successfully.
Also, your test is wrong. You shouldn’t be using the error output parameter to detect if an error occurred because it might be set even if the method completes successfully. Instead, you should use the return value of the method to detect errors. If the return value (in this particular case) is NO, then use the error output parameter to get information about the error:
NSError *error = nil;
BOOL itemRemoved = [[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
if (itemRemoved == NO) {
DLogErr(#"Unable to remove file: error %#, %#", error, [error userInfo]);
return;
}
Quoting the Error Handling Programming Guide,
Important: Success or failure is indicated by the return value of the method. Although Cocoa methods that indirectly return error objects in the Cocoa error domain are guaranteed to return such objects if the method indicates failure by directly returning nil or NO, you should always check that the return value is nil or NO before attempting to do anything with the NSError object.
Edit: As NSGod pointed out, -removeItemAtPath:error: returns BOOL, not NSDictionary *. I’ve edited my answer to reflect that as well.
No I do it the same way and it works just fine for detecting errors. You are not passing NULL to it you are passing a pointer to NULL to it which is a very different thing. Although another option you might want to add is.
if (error != nil){...
}else{
[NSApp presentError:error]
}