iPhone DropBox API: How to load a file? - iphone

A very basic question concerning dropBox integration into an iPhone app.
I followed the setup of the DropBoxSDK and everything works fine. I can log on to my account and get it linked. So I set up everything correctly.
Now I would like to use it to simply load a file from the dropBox and save it again. Consider that you only want to sync ONE FILE (for the sake of simplicity), called 'example.txt' which is located in the 'Example' folder in my DropBox. The same 'example.txt' is saved locally on the iPhone in the Documents directory of my app.
The dropBox readme file suggest vaguely the following code which I find highly cryptic and can't really see how to load or save a file:
2. Make an request on the rest client:
[[self restClient] loadMetadata:#"/"];
3. Implement the DBRestClientDelegate methods needed to get the results of the
particular call you made:
- (void)restClient:(DBRestClient*)client
loadedMetadata:(DBMetadata*)metadata {
NSLog(#"Loaded metadata!");
}
- (void)restClient:(DBRestClient*)client
metadataUnchangedAtPath:(NSString*)path {
NSLog(#"Metadata unchanged!");
}
- (void)restClient:(DBRestClient*)client
loadMetadataFailedWithError:(NSError*)error {
NSLog(#"Error loading metadata: %#", error);
}
So my (hopefully) simple question is how I can:
check if there is an example folder in my dropbox
if not, create one and save the example.txt from app documents into this example folder
load example.txt
once programme quits: save example.txt to DropBox
I can't really find an answer to these quite basic steps in the DropBox docs on the website. The example they've provided I find too confusing... especially as it is only about loading files and not saving them as far as I can see.
I'd be grateful for any help or suggestions of how to go about this.

Ok, I found this method to save my example.txt file:
-(void) DBupload:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Example.txt"];
[self.restClient uploadFile:#"NoteBook.txt" toPath:#"/example" fromPath:filePath];
}
Turns out, no need to create a folder, dropbox will do this automatically for you if it doesn't exist.
This is for downloading the same file form dropbox:
-(void) DBdownload:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Example.txt"];
NSError *error;
[self.restClient loadFile:#"/example/Example.txt" intoPath:filePath];
if (filePath) { // check if file exists - if so load it:
NSString *tempTextOut = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:&error];
}
}
Hope this helps if you were struggling with a similar question.

Into the DBdownload function you can skip the check by implementing the DBRestClientDelegate method loadedFile and loadFileFailedWithError

Related

How to get the directory tree of iPhone App Documents Directory

In my App, I created subfolders under Documents, and subfolders under subfolders. So there is a Document tree. I want to get the tree in a way that I am able to list them in a tableview. They will look like the following, linear listing with different indent to show their level.
I am not sure whether there is some convenient way to get this done or not, when I am trying to do it using while loop and for loop.
Appreciate your suggestions.
Thanks.
Apple provides a number of classes for file system access, and even some for recursion that you're trying to do.
I suggest that you take a look at the Apple File System Programming Guide and the NSFileManager class documentation. Additionally, the NSDirectoryEnumerator class may help as well.
I do not know how to get entire hierarchy at a time. But following method can be helpful.
1 Use this to get documents derectory.
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [paths objectAtIndex:0];
2 use - (NSArray *)contentsOfDirectoryAtPath:(NSString )path error:(NSError *)error for getting list of directories in document directory.
Read this Class refrence for more details.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/Reference/Reference.html
3 Using following method you can make path of internal directory.
NSString *directoryPath = [documentPath stringByAppendingPathComponent:[MAIN_DIRECTORY stringByAppendingPathComponent:filePath]];
Using above three can together you can brows content of document directory.
Hope this is helpful
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
and
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager directoryContentsAtPath:documentsDirectory];
for (NSString *s in fileList){
NSLog(s);
}

iphone writeToFile: problem

Is there any way to save my .xml file to another directory other than "/Users/student/Library/Application Support/iPhone/Simulator/User/Applications/..."
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:#"accUserNames.xml"];
BOOL ok = [content writeToFile:appFile atomically:YES encoding:NSUnicodeStringEncoding error:nil];
if (!ok) {
NSLog(#"Error writing file !");
}
i wish to writeToFile: my .xml file to the desktop , any idea on how?
May the below code help,
NSString *documentsDirectory = #"/Users/student/Desktop/";
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:#"accUserNames.xml"];
BOOL ok = [content writeToFile:appFile atomically:YES encoding:NSUnicodeStringEncoding error:nil];
if (!ok) {
NSLog(#"Error writing file !");
}
From within the iPhone Simulator, you should be able to successfully use #"/Users/student/Desktop/accUserNames.xml" as the path to write to. However, you can't do this on an iOS device (you'll be restricted to the application's sandbox directory — it's recommended you write to the Documents folder or other folders in there, depending what type of data you're storing).
Edit: I think I understand your problem. This part of your code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
effectively finds the path to "/Users/student/Library/Application Support/iPhone/Simulator/User/Applications/..." (this is the normal place you want to save things). But if you just want to save to the desktop temporarily, you should just use appFile = #"/Users/student/Desktop/accUserNames.xml".
Note: I don't advocate this as a long-term solution, but if you just want to see the output of your program temporarily, it works fine.
If you want to upload your file to a server ("www.blahblah.com" in your example), then using the write to file methods is not the correct approach. This is only for writing data to the local file system (or on a network share, but that doesn't apply to iPhones).
If you want to transfer data to a webserver, you will need to have something on the server that will listen for a connection request, then it will need to accept the data which is transferred from your app. You cannot just write a file to "www.blahblah.com" as you would to a file system
Probably not with code, but you could try this: Open "Automator" (in the Utilities folder) and chose "Folder Action". As Input folder, you specify the directory of the documents (/Users/student/Library/Application Support/iPhone/Simulator/User/Applications/...) and then you select, from "Files & Folders", "Duplicate Finder Items" and "Move Finder Items" and select the Desktop. Hit "Save", give it a name, and all files in the documents folder should be copied to the desktop.

Problem when trying to play (with MPMoviePlayerViewController) a video/song that I downloaded and stored in a file

Here is my problem.
I have a MPMoviePlayerViewController that play some videos wich are on the web. That part works.
But in order to play them later, without internet connection, I store them on the phone with that piece of code
NSData * data = [NSData dataWithContentsOfURL:[self dataURL]];
NSArray * documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * baseDocumentPath = ([documentPaths count] > 0) ? [documentPaths objectAtIndex:0] : nil;
[data writeToFile:[baseDocumentPath stringByAppendingPathComponent:_itemId]
atomically:YES];
That part is ok, I can play the files on my iMac if i take them from the phone.
But after that when i do
NSArray * documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * baseDocumentPath = ([documentPaths count] > 0) ? [documentPaths objectAtIndex:0] : nil;
videoController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:[baseDocumentPath stringByAppendingPathComponent:file.itemId]]];
There is just a gray Window in the modal viewController. And i get no notifications from the player.
Any ideas?
Thanks.
I came across this very same problem today.
It seems that iOS won't load any media files that have the wrong file extension. IMHO this is pretty stupid behavior, as I'm storing my media files with random names (UUIDs).
A quick workaround was to use the following code to create a symlink to the original file and give it the correct extension. Now iOS will happily load the file.
// Create a symlink for iOS as it won't load any files with the wrong extension
NSString *fixedFileName = [fileName stringByAppendingString:#".mp4"];
[[NSFileManager defaultManager] createSymbolicLinkAtPath:fixedFileName
withDestinationPath:fileName error:NULL];
Hope that helps. We simply ignore the fact that an error occurred, in case the symlink already exists.
Someone found what causes the problem.
The file name has no extension (like .mp4) so the MPMovieController doesn't try to read it (that sounds crazy to me -_- ). If I manually had .mp4 to my video file. the app can read it... I'm gonna append the extension of each file to its name.
Thanks anyway :)

iPhone pathForResource vs bundlePath

I want to use pathForResource, but it doesn't look like it will create the path if one doesn't exist. Therefore I'm trying to create one manually by doing the following:
NSString *path = [NSString stringWithFormat:#"%#/%#.plist",[[NSBundle mainBundle] bundlePath],#"myFileName"];
I'm creating files dynamically, so I need to access them after I have Build and Run the application. But it puts the project in a unique id folder so the path comes out to something like:
/Users/RyanJM/Library/Application Support/iPhone Simulator/3.0/Applications/80986747-37FD-49F3-9BA8-41A42AF7A4CB/MyApp.app/myFileName.plist
But that unique id changes every time I do a build. What is the proper way to create a path that I can get to every time (even in the Simulator)?
Thanks.
Update: edited the question, hopefully to help anyone who comes across it in the future.
Update: IWasRobbed answered the proper way to get create a path URL. But the the best answer I've been able to find is from Brad Parks. Though, I do wish there was a cleaner way.
With the way you phrased your question, this is how you read a plist that has been included in the bundle before build:
NSString *propertyListPath = [[NSBundle mainBundle] pathForResource:SomeString ofType:#"plist"];
If you want to access the directories that each app has as a unique storage area for a file that you create AFTER build, you use this:
#define kFilename #”data.plist”
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
Then you can check for it and do some data handling here:
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
// do something with data here
}
You would save yourself a lot of trouble if you bought/read Beginning iPhone 3 Development specifically chapter 11 where he goes over data persistence (which is where this example came from). It's a great book.

iPhone - copying a file from resources to Documents gives an error

I am trying to copy an mp3 file from my Resources folder to a folder inside "Documents" folder of the app. On the simulator this works fine. But when I run it on a device, copying the files gives me this error
Operation could not be completed. (Cocoa error 513.)
The source and destinations paths are fine but I still cannot copy the file. Any ideas? Where can I find out what the cocoa error code 513 means?
Thanks.
Here's the relevant source code
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *folderPath = [documentsDirectory stringByAppendingPathComponent:#"Files"];
NSString *insPath = [NSString stringWithFormat:#"%#.mp3", fileName];
NSString *srcPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:insPath];
NSString *destPath = [folderPath stringByAppendingPathComponent:insPath];
NSLog(#"Src: %#, Dest: %#", srcPath, destPath);
NSError *err;
[fileManager moveItemAtPath:srcPath toPath:destPath error:&err];
NSLog(#"Err desc-%#", [err localizedDescription]);
NSLog(#"Err reason-%#", [err localizedFailureReason]);
Before making a call to moveItemAtPath, I am also creating the directory "Files" and it returns a YES.
Here's the log results
Src: /var/mobile/Applications/512D7565-7EF7-4C13-A015-19EEC3F3B465/MyApp.app/MyFile.mp3, Dest: /var/mobile/Applications/512D7565-7EF7-4C13-A015-19EEC3F3B465/Documents/Files/MyFile.mp3
Err desc-Operation could not be completed. (Cocoa error 513.)
Err reason-(null)
A question
Is there a limit to the file size when copying data from resources to Documents folder? The file I am trying to copy is about 5MB. Could that be a reason?
EDIT:
Just figured out an even simpler solution. Instead of
moveItemAtPath:toPath:error:, just use copyItemAtPath:toPath:error: ... since we truly want to copy the file from the mainBundle and not move it. I should have thought of that sooner!
E.g.
[[NSFileManager defaultManager] copyItemAtPath:mainBundleFilePath
toPath:destPath
error:&err]
See my previous comments below about why this works.
I believe I have the answer to this question. I can say for sure that the issue is not the destination file path.
I was getting the same Cocoa error 513 (NSFileWriteNoPermissionError) with pretty much the exact same code:
[[NSFileManager defaultManager] moveItemAtPath:mainBundleFilePath
toPath:destPath
error:&err]
The problem appears to be that the file, coming from the mainBundle, doesn't have suitable permissions to be moved to another place. I'm not sure if this command, if executed, would actually move the file from the mainBundle or just copy it...but either way, the file manager doesn't seem to like the idea.
The solution is simple: just read the mainBundle file into an NSData object and then write the NSData to a new file. Note the destination file path is the same in both examples, which shows us that lostInTransit is correct in saying that his file path is OK.
For this example, then, the following code will work and not throw an error:
NSData *mainBundleFile = [NSData dataWithContentsOfFile:mainBundleFilePath];
[[NSFileManager defaultManager] createFileAtPath:destPath
contents:mainBundleFile
attributes:nil];
BTW, in my own code, instead of passing a nil for attributes:, I set up an NSDictionary with a NSFileModificationDate attribute. I also wrapped the createFileAtPath:contents:attributes in an error handing if-statement. In other words,
if (![[NSFileManager defaultManager] createFileAtPath:destPath
contents:mainBundleFile
attributes:myAttributes]) {
// handle error as necessary, etc...
}
It took me a while to figure all of this out, so hopefully this solution will be helpful to others.
Are you sure you are getting the path to Documents folder correctly? The absolute path in the simulator is different than the absolute path on the device.
You should use the following to make sure you get the correct path to the Documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
The path for documentsDirectory on the the device would be something like:
/var/mobile/Applications/30B51836-D2DD-43AA-BCB4-9D4DADFED6A2/Documents
The path on the simulator would be something like:
/Volumes/Stuff/Users/johnDoe/Library/Application Support/iPhone Simulator/User/Applications/118086A0-FAAF-4CD4-9A0F-CD5E8D287270/Documents
You can read more on the File & Networking page on the dev site.
That's the NSFileWriteNoPermissionError:
http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Constants/Reference/reference.html
Somehow, you do have the wrong path and it's not letting you write there. You could also delete the app and try again, in case somehow your app documents directory was set to the wrong permissions...
I'd give us the line of code doing the copy, and print outs of each variable used in that line. Then we can see what the problem is.