iCloud Drive - Read & Write (NSData) - objective-c

Trying to save custom objects as NSData then upload to iCloud Drive
any direction?
I tried already the Key-Value Method, but it is limited for 1MB :/
is it the correct way?
if yes, how can I read from the iCloud path?
+(void)iCloudWrite:(NSData*)data
{
NSURL* ubiq = [[NSFileManager defaultManager]URLForUbiquityContainerIdentifier:nil];
NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:#"Documents"] URLByAppendingPathComponent:#"iCloudHistory.zip"];
MyDocument *mydoc = [[MyDocument alloc] initWithFileURL:ubiquitousPackage];
mydoc.dataContent = data;
[mydoc saveToURL:[mydoc fileURL] forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success)
{
if (success)
{
NSLog(#"Synced with icloud");
}
else
NSLog(#"Syncing FAILED with icloud");
}];
}
EDITED:

// 1. Any file can be uploaded to iCloud container of any size (yes you should be having that much of space in iCloud) lets take an example SampleData.zip
// 2. This method will upload or sync SampleData.zip file in iCloud container, iCloud actually checks the metadata of your file before it uploads it into your iCloud container (so for first time it will upload the file and from next time it will only upload the changes)
-(void) iCloudSyncing:(id)sender
{
//Doc dir
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"SampleData.zip"];
NSURL *u = [[NSURL alloc] initFileURLWithPath:filePath];
NSData *data = [[NSData alloc] initWithContentsOfURL:u];
//Get iCloud container URL
NSURL *ubiq = [[NSFileManager defaultManager]URLForUbiquityContainerIdentifier:nil];// in place of nil you can add your container name
//Create Document dir in iCloud container and upload/sync SampleData.zip
NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:#"Documents"]URLByAppendingPathComponent:#"SampleData.zip"];
Mydoc = [[MyDocument alloc] initWithFileURL:ubiquitousPackage];
Mydoc.zipDataContent = data;
[Mydoc saveToURL:[Mydoc fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success)
{
if (success)
{
NSLog(#"SampleData.zip: Synced with icloud");
}
else
NSLog(#"SampleData.zip: Syncing FAILED with icloud");
}];
}
// 3 Download data from the iCloud Container
- (IBAction)GetData:(id)sender {
//--------------------------Get data back from iCloud -----------------------------//
id token = [[NSFileManager defaultManager] ubiquityIdentityToken];
if (token == nil)
{
NSLog(#"ICloud Is not LogIn");
}
else
{
NSLog(#"ICloud Is LogIn");
NSError *error = nil;
NSURL *ubiq = [[NSFileManager defaultManager]URLForUbiquityContainerIdentifier:nil];// in place of nil you can add your container name
NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:#"Documents"]URLByAppendingPathComponent:#"SampleData.zip"];
BOOL isFileDounloaded = [[NSFileManager defaultManager]startDownloadingUbiquitousItemAtURL:ubiquitousPackage error:&error];
if (isFileDounloaded) {
NSLog(#"%d",isFileDounloaded);
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
//changing the file name as SampleData.zip is already present in doc directory which we have used for upload
NSString* fileName = [NSString stringWithFormat:#"RecSampleData.zip"];
NSString* fileAtPath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSData *dataFile = [NSData dataWithContentsOfURL:ubiquitousPackage];
BOOL fileStatus = [dataFile writeToFile:fileAtPath atomically:NO];
if (fileStatus) {
NSLog(#"success");
}
}
else{
NSLog(#"%d",isFileDounloaded);
}
}
}
//4 voila its done :)
Don't forget to add following parameters to your plist
<key>NSUbiquitousContainers</key>
<dict>
<key>YourCloudContainerID</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerName</key>
<string>YourCloudContainerName</string>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
</dict>
</dict>

Related

writeToFile does not work after removeItemAtPath

I have an iOS app that at times needs to store UIImage objects locally.
I am using [UIImagePNGRepresentation(image) writeToFile:full_path options:NSAtomicWrite error:nil]; to save the image and [file_manager removeItemAtPath:full_path error:NULL]; to delete the file.
This all works great, however, whenever I delete a file, should I decide to save a new file (which just so happens to have the same name as the old file), the save code doesn't work and returns the following error:
: ImageIO: CGImageReadCreateDataWithMappedFile 'open' failed
error = 2 (No such file or directory)
: ImageIO: CGImageReadCreateDataWithMappedFile 'open' failed
error = 2 (No such file or directory)
: ImageIO: PNG zlib error
So heres what I don't get, why can't I save a file with the same name as the old file, after I have deleted the old file?
The reason I ask this, is that, my app will save certain image files and then when they are no longer needed, my app will delete them. However, there are times when my app needs the image files again (could be a few hours after deletion or a few weeks). When this happens, my app will load the appropriate image data and then try to save it. And thats when the error occurs.
Whats going wrong here?
Thanks for your time, Dan.
UPDATE - Here are the methods I have setup to save/access and delete my image files
-(void)save_local_image:(UIImage *)image :(NSString *)file_name {
// Get the app documents directory link.
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
// Add the new file name to the link.
NSString *database_link = [[NSString alloc] initWithString:[documents stringByAppendingPathComponent:file_name]];
// Save the image data locally.
[UIImagePNGRepresentation(image) writeToFile:database_link options:NSAtomicWrite error:nil];
}
-(UIImage *)get_local_image:(NSString *)file_name {
// Create the return data.
UIImage *image_data = nil;
// Get the app documents directory.
NSArray *directory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] error:NULL];
// Only check for data if at least
// one file has been saved locally.
if ([directory count] > 0) {
// Loop through the different local files.
for (NSString *path in directory) {
// Get the full local file URL.
NSString *full_path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:path];
// Get the range of the file name.
NSRange range = [full_path rangeOfString:file_name];
// Get the image data if it exists.
if ((range.location != NSNotFound) || (range.length == [file_name length])) {
// Load the image file in.
image_data = [UIImage imageWithContentsOfFile:full_path];
break;
}
}
}
return image_data;
}
-(void)delete_local_image:(NSString *)file_name {
// Get the app documents directory.
NSArray *directory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] error:NULL];
// Only check for data if at least
// one file has been saved locally.
if ([directory count] > 0) {
// Loop through the different local files.
for (NSString *path in directory) {
// Get the full local file URL.
NSString *full_path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:path];
// Get the range of the file name.
NSRange range = [full_path rangeOfString:file_name];
// Delete the local image data if it exists.
if ((range.location != NSNotFound) || (range.length == [file_name length])) {
NSError *testError = nil;
// Delete the image file.
NSFileManager *file_manager = [[NSFileManager alloc] init];
BOOL success = [file_manager removeItemAtPath:full_path error:&testError];
NSLog(#"%d", success);
if (testError != nil) {
NSLog(#"%#", testError.localizedDescription);
}
break;
}
}
}
}
I am using this to save and read:
- (void) saveImageToFile:(NSString *) urlImg withNameNumber:(int)numberName andQuestionId:(int) questionID
{
NSString* documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString* foofile = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:#"gallery%d%d.jpg",numberName,questionID]];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:foofile];
if (!fileExists) {
NSData *tempImgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#%#",#"https://testurl/",urlImg]]];
NSString *filename = [NSString stringWithFormat:#"gallery%d%d.jpg",numberName,questionID];
NSString *imagePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:filename];
[tempImgData writeToFile:imagePath atomically:YES];
}
}
-(UIImage*) readImageFromFile:(int)numberName andQuestionId:(int) questionID
{
NSString * documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
return [UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#/gallery%d%d.jpg",documentsDirectoryPath,numberName,questionID]];
}

How to Upload file to google drive only if it is not exist?

I use xcode to develope iphone application.
i upload Database files to my google drive with this code.
- (void)uploadDB{
GTLDriveFile *file = [GTLDriveFile object];
file.title = [NSString stringWithFormat:#"User:%#DB.sqlite",UserName];
file.descriptionProperty = #"Uploaded from iOS ";
file.mimeType = #"application/x-sqlite3";
// Attach a DB file to the email
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//make a file name to write the data to using the documents directory:
NSString *fileName = [NSString stringWithFormat:#"%#/%#",
documentsDirectory,DB_File];
NSData *data = [NSData dataWithContentsOfFile:fileName];
GTLUploadParameters *uploadParameters = [GTLUploadParameters uploadParametersWithData:data MIMEType:file.mimeType];
GTLQueryDrive *query = [GTLQueryDrive queryForFilesInsertWithObject:file
uploadParameters:uploadParameters];
UIAlertView *waitIndicator = [self showWaitIndicator:#"Uploading to Google Drive"];
[self.driveService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
GTLDriveFile *insertedFile, NSError *error) {
[waitIndicator dismissWithClickedButtonIndex:0 animated:YES];
if (error == nil)
{
NSLog(#"File ID: %#", insertedFile.identifier);
[self showAlert:#"Google Drive" message:#"File saved!"];
}
else
{
NSLog(#"An error occurred: %#", error);
[self showAlert:#"Google Drive" message:#"Sorry, an error occurred!"];
}
}];
}
My problem that it is always save it as a new file, I wand that it will check if this file name exist on drive and replace it.
Thanks
The title of a file in Drive is not unique. Instead, you should use the resource id. The first time you upload the database file, remember the resource id that it gives back to you on success and then update that from then on.

How to zip folders in Ipad

In my Application,I am taking screenshots of image View and then I am saving those screen shots in document folder of the application.Now I want to Email all those images with the same folder structure they are in.Zipping all the folders containing the images?
-(void)ZipFile2{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [paths objectAtIndex:0];
BOOL isDir=NO;
NSArray *subpaths;
NSString *exportPath = docDirectory;
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:exportPath isDirectory:&isDir] && isDir){
subpaths = [fileManager subpathsAtPath:exportPath];
}
NSString *archivePath = [docDirectory stringByAppendingString:#"Uploads.zip"];
ZipArchive *archiver = [[ZipArchive alloc] init];
[archiver CreateZipFile2:archivePath];
for(NSString *path in subpaths)
{
NSString *longPath = [exportPath stringByAppendingPathComponent:path];
if([fileManager fileExistsAtPath:longPath isDirectory:&isDir] && !isDir)
{
[archiver addFileToZip:longPath newname:path];
}
}
BOOL successCompressing = [archiver CloseZipFile2];
if(successCompressing)
NSLog(#"Success");
else
NSLog(#"Fail");
}
I use this code but the zip file is not created in my Ipad ??? can you Help Me
ZipArchive has a delegate protocol which sends a message whenever a error occurs.
add below ZipArchive allocation.
archiver.delegate = self
Add protocol to header class and then implement the following method:
- (void)ErrorMessage:(NSString*) msg {
NSLog(#"Zip error: %#", msg);
}

connect to sqlite

I'm having some issue connecting to my sqlite database.. I'm using xcode version 4.4.1
here's my code..
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"signature.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ] == NO)
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
status.text = #"Connected..";
} else {
status.text = #"Failed to open/create database..";
}
}
[filemgr release];
Any suggestion..?
Thanks,
Boom
There is no need to check if the database exists; sqlite3_open_v2() (reference) will create the database, if it does not exist, if you pass the flag SQLITE_OPEN_CREATE:
NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPath:#"signature.db"];
if (sqlite3_open_v2([dbPath UTF8String], &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE) == SQLITE_OK)
{
status.text = #"Connected..";
// Check the schema and install if it doesn't exist
sqlite3_close(database);
} else {
status.text = #"Failed to open/create database..";
}
You may wish to check if the DB file is in place if you have one in your app's bundle that is pre-built so you can drop it into your documents folder. Of course, as you enhance your app, any schema changes will need to be done in code. Here is some code that I use (that works, but needs to updated a bit)
When opening/creating the DB I use this to specify where the DB file will be. I don't put it with the init because my location is different between iOS and Mac OS X and I want the DB code to work with both:
NSString *dbFilePath;
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolderPath = searchPaths[0];
dbFilePath = [documentFolderPath stringByAppendingPathComponent: #"MyDBFile.db"];
MyDB* appDB = [[EasySpendLogDB alloc] initWithFile:dbFilePath];
if(!appDB) {
// show error
return;
}
This is in my DB access class. It uses some wrapper classes I wrote:
- (id) initWithFile: (NSString*) filePathName {
if(!(self = [super init])) return nil;
BOOL myPathIsDir;
BOOL fileExists = [[NSFileManager defaultManager]
fileExistsAtPath: filePathName
isDirectory: &myPathIsDir];
NSString *backupDbPath = [[NSBundle mainBundle]
pathForResource:#"MyDBFile"
ofType:#"db"];
if (backupDbPath != nil && !fileExists) {
[[NSFileManager defaultManager]
copyItemAtPath:backupDbPath
toPath:filePathName
error:nil];
}
db = [[ABSQLiteDB alloc] init];
if(![db connect:filePathName]) {
return nil;
}
[self checkSchema]; // this is where schema updates are done (see project sample)
return self;
}
You may also want to check out this objective-c wrapper I wrote that has a sample project: https://github.com/AaronBratcher/ABSQLite

Appending NSString while using NSApplicationSupportDirectory to create a new directory

I have been trying to create a new file inside of my application support folder while using NSApplicationSupportDirectory; I can write a file to it, but I have been unable to create a folder inside of Application Support.
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *applicationDirectory = [paths objectAtIndex:0];
//make a file name to write the data to using the application support: (attempting to create the blasted directory inside of application support directory
NSString *fileName = [NSString stringWithFormat:#"%#/managersemail.txt",
applicationDirectory];
//create content - formats with the managersemail.txt location
NSString* content = [NSString stringWithFormat:#"%#",[nameField stringValue]];
//save content to the documents directory
[content writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
NSDictionary* errorDict;
The code that I have listed above works great, except for the part about creating the folder in which I want to place the managersemail.txt. I tried to mimic the stringWithFormat that is listed in the NSString* content and then varying several ways however to no avail! Any thoughts?
NSAppleEventDescriptor* returnDescriptor = NULL;
Perhaps the solution provided on Cocoa with Love might be useful?
Excerpt:
- (NSString *)findOrCreateDirectory:(NSSearchPathDirectory)searchPathDirectory
inDomain:(NSSearchPathDomainMask)domainMask
appendPathComponent:(NSString *)appendComponent
error:(NSError **)errorOut
{
// Search for the path
NSArray* paths = NSSearchPathForDirectoriesInDomains(
searchPathDirectory,
domainMask,
YES);
if ([paths count] == 0)
{
// *** creation and return of error object omitted for space
return nil;
}
// Normally only need the first path
NSString *resolvedPath = [paths objectAtIndex:0];
if (appendComponent)
{
resolvedPath = [resolvedPath
stringByAppendingPathComponent:appendComponent];
}
// Check if the path exists
BOOL exists;
BOOL isDirectory;
exists = [self
fileExistsAtPath:resolvedPath
isDirectory:&isDirectory];
if (!exists || !isDirectory)
{
if (exists)
{
// *** creation and return of error object omitted for space
return nil;
}
// Create the path if it doesn't exist
NSError *error;
BOOL success = [self
createDirectoryAtPath:resolvedPath
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (!success)
{
if (errorOut)
{
*errorOut = error;
}
return nil;
}
}
if (errorOut)
{
*errorOut = nil;
}
return resolvedPath;
}
Maybe you can try using the NSFileManager to create the folder, then write the file into the folder.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *applicationSupport = [[NSString stringWithString:#"~/Library/Application Support/'YOUR APP'] stringByExpandingTildeInPath];
if ([fileManager fileExistsAtPath:applicationSupport] == NO)
[fileManager createDirectoryAtPath:applicationSupport withIntermediateDirectories:YES attributes:nil error:nil];
NSString *fileName = [NSString stringWithFormat:#"%#/managersemail.txt", applicationSupport];
NSString* content = [NSString stringWithFormat:#"%#",[nameField stringValue]];
//save content to the documents directory
[content writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
So something like that should work. Feel free to leave comments to ask questions.