I want to write NSDictionary object to cache and also want to remove it from cache. here i store it to chache but can not remove it from chache
-(void) storeDictionary:(NSMutableDictionary *) dictionaryToStore strDictionaryName:(NSString *) strDictionaryName
{
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
//make a file name to write the data to using the
//cache directory:
NSString *fullFileName = [NSString stringWithFormat:#"%#/%#", cacheDirectory,strDictionaryName];
if (dictionaryToStore != nil) {
[dictionaryToStore writeToFile:fullFileName atomically:YES];
}
}
Help for remove it from cache.
Here are some rough code for deleting a file in cache folder, suppose you have the file path named fullFileName as showed in your code.
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL fileExist = [fileManager fileExistsAtPath:fullFileName];
if (fileExist) {
NSError *error;
BOOL ok = [fileManager removeItemAtPath:fullFileName error:&error];
NSLog(#"remove %d",ok);
if (error) {
NSLog(#"error is %#", error.description);
}
}
If you just want to write it to the cache. NSCache might be the best and the most convenient way to do that.
Here is the link: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/NSCache_Class/index.html
However, if you want to have the full manipulation. You probably stick with what you are doing. You just delete the whole when you want to delete it and override it when you want to update it. Because NSCache will be handled by system. When system does not have enough memory, it might clear your data so that you have to check it every time you want to access it. It really depends on what you want.
Related
I am creating an application. I am storing the files in Document directory. And after my work completed, delete the files from document directory as like below:
NSMutableDictionary * Dictionary = [NSMutableDictionary alloc]init];
// Next every file storing into this dictionary like below
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *baseDir = [paths objectAtIndex:0];
NSString *pathComp = [baseDir stringByAppendingPathComponent:[NSString stringWithFormat:#"IMG%d.PNG",presentCount];
fileURL = [NSURL fileURLWithPath:pathComp];
[Dictionary setObject:fileURL forKey:fileURL];
while ([[Dictionary allKeys]count]!=0) {
NSURL *deleteFileURL = [[Dictionary allKeys] lastObject];
NSLog(#"Path %#",deleteFileURL.path);
[[NSFileManager defaultManager] removeItemAtPath:deleteFileURL.path error:nil];
[Dictionary removeObjectForKey:deleteFileURL];
}
Here my problem is, after delete the files from document directory, memory is not reduced, still it's occupying as like files exist. Due to this issue, my is crashing. So please help me how to clear the memory.
Actually i am getting the files(Photos ) from the server and first placing in documents directory,and trying to save using photo library.Once i give input from dictionary to photo library, after completion handler, i am trying to delete the file.Its removed and photo saved, but memory is not reduced.
1、Remove the file after checking for the existence of a file on the path, and check the return value of removeItemAtPath: to determine if the deletion succeeded.
NSString *path = #"a/b";
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
BOOL success = [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
// Check the success's value
}
I am currently using this code to copy my SQLite database, however it is currently only checking to see if the file exists... I want to change it to check if the file isn't exactly the same, for example I am worried if a database gets corrupt or doesn't copy all the way, the app will lose functionality and the only way to fix this would be to delete the App and redownload it.
So how can I compare if two files are exactly equal?
- (void) copyDatabaseIfNeeded {
//Using NSFileManager we can perform many file system operations.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
//NSLog(#"%d",success);
if(!success) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"database01.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
- (NSString *) getDBPath
{
//Search for standard documents using NSSearchPathForDirectoriesInDomains
//First Param = Searching the documents directory
//Second Param = Searching the Users directory and not the System
//Expand any tildes and identify home directories.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
//NSLog(#"dbpath : %#",documentsDir);
return [documentsDir stringByAppendingPathComponent:#"database01.sqlite"];
}
You can use contentsEqualAtPath:andPath: method of NSFileManager for this purpose.
Use your code something like this:
......
if(!success) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"database01.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
success = [fileManager contentsEqualAtPath:defaultDBPath andPath:dbPath]; //verify if file size and content matches
if(!success) {
//report error
}
}
.......
And it should do the trick for you.
Edit - Forget this answer - use the one by Ayan.
Start by comparing the file sizes. If the sizes are different you know the files are not the same. This is a simple and quick check.
If the sizes are the same then you need to compare the files, byte by byte. An inefficient way would be to load both files into NSData objects and see if they are equal. This only works if the files will always be small enough to fit in memory.
A better approach is to open both files as streams and read them in chunks. Compare each chunk (say 2k each) until two chunks are different or you get to the end.
I want to replace core data and want to delete old core data. Does Apple allows it to delete old core data. Is there any chance to reject app.
Apple won't care, but your users might. If there is data that your users might be sorry to lose, you should make every effort to migrate it or give an option to export it when they upgrade.
If you're only using core data to cache downloaded values, then there's no problem with this at all. In fact, deleting the old store would be necessary to prevent the app crashing on upgrade, since it wouldn't be able to migrate from the existing store. The best place to do this is in the core data setup code when you receive an error - the boilerplate comments guide you toward this.
There are no problems doing that.
For example, you can check app's version in the AppDelegate:
- (void)clearCacheIfNeeded;
{
NSString *savedVersion = [[NSUserDefaults standardUserDefaults] objectForKey:#"currentVersion"];
NSString *currentVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
if (![savedVersion isEqualToString:currentVersion]) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [paths objectAtIndex:0];
NSArray *contents = [fileManager contentsOfDirectoryAtPath:cachesDirectory error:NULL];
NSEnumerator *e = [contents objectEnumerator];
NSString *filename;
while ((filename = [e nextObject])) {
NSLog(#"file name: %#", filename);
[fileManager removeItemAtPath:[cachesDirectory stringByAppendingPathComponent:filename] error:NULL];
}
[[NSUserDefaults standardUserDefaults] setObject:currentVersion forKey:#"currentVersion"];
}
}
I want to save an image with some metadata changes in a temp folder, without re-encoding the actual image data.
The only method that I found able to do this is ALAssetsLibrary/writeImageDataToSavedPhotosAlbum:metadata:completionBlock:, however, this one saves the image to the Photo Library. Instead, I want to save the image to a temp folder (for instance to share it by email, without populating the Photo Library).
I've tried using CGImageDestinationRef (CGImageDestinationAddImageFromSource), but it can only be created using a decoded image, which means it's re-encoding it when saved (tested, pixel bytes look different).
Are there any other methods/classes available for iOS that can save image data along with metadata, besides using CGImageDestinationRef? Suggestions for workarounds would also be welcomed.
This is a frustrating problem with the iOS SDK. First, I recommend filing an enhancement request.
Now, here is a potential workaround: IF the ALAsset was created by you (i.e., its editable property is YES) then you can basically read the data, write with metadata, read again, save to disk, and then write with the original metadata.
This approach will avoid creating a duplicate image.
Please read the // comments as I skipped some stuff for brevity (like building a metadata dictionary):
ALAsset* asset; //get your asset, don't use this empty one
if (asset.editable) {
// get the source data
ALAssetRepresentation *rep = [asset defaultRepresentation];
Byte *buffer = (Byte*)malloc(rep.size);
// add error checking here
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
NSData *sourceData = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
// make your metadata whatever you want
// you should use actual metadata, not a blank dictionary
NSDictionary *metadataDictionary = [NSDictionary dictionary];
// these are __weak to avoid creating an ARC retain cycle
NSData __weak *originalData = sourceData;
NSDictionary __weak *originalMetadata = [rep metadata];
[asset setImageData:sourceData
metadata:metadataDictionary
completionBlock:^(NSURL *assetURL, NSError *error) {
//now get your data and write it to file
if (!error) {
//get your data...
NSString *assetPath = [assetURL path];
NSData *targetData = [[NSFileManager defaultManager] contentsAtPath:assetPath];
//...write to file...
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [searchPaths lastObject];
NSURL *fileURL = [NSURL fileURLWithPath:documentPath];
[targetData writeToURL:fileURL atomically:YES];
//...and put it back the way it was
[asset setImageData:originalData metadata:originalMetadata completionBlock:nil];
} else {
// handle error on setting data
NSLog(#"ERROR: %#", [error localizedDescription]);
}
}];
} else {
// you'll need to make a new ALAsset which you have permission to edit and then try again
}
As you can see, if the ALAsset isn't owned by you, you will need to create one, which will add a photo to the user's library, which is exactly what you wanted to avoid. However, as you may have guessed, you cannot delete an ALAsset from the user's photo library, even if your app created it. (Feel free to file another enhancement request for that.)
So, if the photo/image was created in your app, this will work for you.
But if not, it will create an additional copy the user must delete.
The only alternative is to parse the NSData yourself, which would be a pain. There is no open-source library that I am aware of to fill this gap in the iOS SDK.
Alongside iphone-exif, and Aaron's answer, you might also want to look at the libexif c library.
see also HCO23's answer to
How to write or modify EXIF data for an existing image on the filesystem, without loading the image?
(#HCO23 has used libexif in iOS projects).
It's also worth noting that many of the 'professional' metadata editing apps in the app store seem to skirt around the issue by creating sidecar/xmp files.
Try This :
- (void)saveImage: (UIImage*)image
{
if (image != nil)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
#"test.png" ];
NSData* data = UIImagePNGRepresentation(image);
[data writeToFile:path atomically:YES];
}
}
- (UIImage*)loadImage
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
#"test.png" ];
UIImage* image = [UIImage imageWithContentsOfFile:path];
[self sendAction:path];
return image;
}
The problem is appearing on device not on simulator.
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Plist1.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSLog(#"documentsDirectory --- %#", documentsDirectory);
NSLog(#"path --- %#", path);
#try
{
if (![fileManager fileExistsAtPath:path])
{
[fileManager copyItemAtPath:documentsDirectory toPath:path error:&error];
}
}
#catch (NSException *exception)
{
NSLog(#" [exception description] -- %#", [exception description]);
}
#finally {
}
[dictEmot writeToFile:path atomically:YES];
// To verify
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSLog(#"[dict allKeys] My plist ----- %#", [dict allKeys]);
Above is the code which I have written to save two plist files in my documents directory. same method I use to save my second plist.
[self savePlist:plist1];
[self savePlist:plist2];
My problem is whenever I try to save second plist it creates hierarchy of folders inside documents directory and also not saves my plist2 file with it contents.
once it complets the 2nd method call, my app documents directory looks like below,
Documents
-> plist1
-> plist1
.
.
.
-> plist1
-> plist1
other files
I treid doing on main thread also but same result.
its not even printing exception.
What is my mistake ?
- Why its creating hierarchy ?
I don't know much about iOS but I think your problem is with stringByAppendingPathComponent:#"Plist1.plist" Check your documentation as I am supscious by the word Appending and even if you send new file name as you are hardcoding the value of the filename to Plist1.plist...
Still I am not sure as I have not done iOS coding for a long time now.