I have a plist file in my application data that i want to update from a webserver every 24 hours. Is there a way to check when the file is last modified or should i, in some way register the date and time when i update the file, and use that to compare to?
if (lastMod > currentDate){
[arrayFromXml writeToFile:path atomically:YES];
}
You can use NSFileManager for this:
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:#"path/to/my/file" error:nil];
NSDate *date = [attributes fileModificationDate];
// compare 'date'
// date > now
if ([date compareTo:[NSDate date]] == 1)
{
[arrayFromXML writeToFile:#"path/to/my/file" atomically:YES];
}
you can store the NSDate in NSUserDefaults when saving..and then compare it with current time to check the difference,,
Related
I am trying to figure out how to save a NSDate value into my plist file thats in my application.
I am currently doing this but am stuck on the actual part where I have to save it.
NSString *datePlistPath = [[NSBundle mainBundle] pathForResource: #"my-Date" ofType: #"plist"];
NSMutableDictionary *dict = [NSDictionary dictionaryWithContentsOfFile: datePlistPath];
// to be saved to plist
NSDate *date = [NSDate date];
// this is where I start to get abit lost, I want to set the date to the right plist value then commit the changes
[dict setObject:date forKey:#"my-Date"];
[dict writeToFile:datePlistPath atomically:YES]; // error happening here.
any help would be appreciated
UPDATE: once it hits the last line of code there this is the error that is generated...
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
Use NSMutableDictionary dictionaryWithContentsOfFile
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile: datePlistPath];
it provide u NSDictionary not NSMutableDictionary if u use NSDictionary dictionaryWithContentsOfFile
Also u cannot update plist in application bundle instead store in Document Directory.
Refer dit-objects-in-array-from-plist link
I think solution in your case is simple like
Replace
NSMutableDictionary *dict = [NSDictionary dictionaryWithContentsOfFile: datePlistPath];
with
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile: datePlistPath];
NSMutableDictionary *dict = [NSDictionary dictionaryWithContentsOfFile: datePlistPath];
replace NSDictionary with NSMutableDictionary.
You cannot write a file to
NSBundle
. Files can be stored only in Documents directory, temp directory and some pre defined locations. you can try the following code. It worked fine for me.
NSArray *paths =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0]
stringByAppendingPathComponent:#"file.plist"];
NSDate *currentDate = [NSDate date];
NSMutableDictionary *d = [NSMutableDictionary new];
[d setObject:currentDate forKey:#"my-date"];
[d writeToFile:filePath atomically:YES];
You can't write to files in your own bundle. You don't say exactly what you are using the date for, but if you just want to persist this one NSDate across launches, you probably want to write this date to NSUserDefaults.
Docs here:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/
Your code to write it would just look like:
[[NSUserDefaults standardUserDefaults] setObject:date forKey:#"my-Date"];
and to read it back you would do
NSDate* myDate = (NSDate*)[[NSUserDefaults standardUserDefaults] objectForKey:#"my-Date"];
// Be prepared for a nil value if this has never been set.
I am downloading images to my app which after a few weeks the user will not care about. I download them to the app so they will not have to be downloaded every launch. The problem is I do not want the Documents folder to get bigger than it has to over time. So I thought I could "clean up" file older than a Month.
The problem is, there will be a few files in there that WILL be older than a month but that I do NOT want to delete. They will be Static Named files so they will be easy to identify and there will only be 3 or 4 of them. While there might be a few dozen old files I want to delete. So heres an example:
picture.jpg <--Older than a month DELETE
picture2.jpg <--NOT older than a month Do Not Delete
picture3.jpg <--Older than a month DELETE
picture4.jpg <--Older than a month DELETE
keepAtAllTimes.jpg <--Do not delete no matter how old
keepAtAllTimes2.jpg <--Do not delete no matter how old
keepAtAllTimes3.jpg <--Do not delete no matter how old
How could I selectively delete these files?
Thanks in advance!
Code to delete files which are older than two days. Originally I answered here. I tested it and it was working in my project.
P.S. Be cautious before you delete all files in Document directory because doing so you might end up losing your Database file(If you are using..!!) there which may cause trouble for your Application. Thats why I have kept if condition there. :-))
// Code to delete images older than two days.
#define kDOCSFOLDER [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"]
NSFileManager* fileManager = [[[NSFileManager alloc] init] autorelease];
NSDirectoryEnumerator* en = [fileManager enumeratorAtPath:kDOCSFOLDER];
NSString* file;
while (file = [en nextObject])
{
NSLog(#"File To Delete : %#",file);
NSError *error= nil;
NSString *filepath=[NSString stringWithFormat:[kDOCSFOLDER stringByAppendingString:#"/%#"],file];
NSDate *creationDate =[[fileManager attributesOfItemAtPath:filepath error:nil] fileCreationDate];
NSDate *d =[[NSDate date] dateByAddingTimeInterval:-1*24*60*60];
NSDateFormatter *df=[[NSDateFormatter alloc]init];// = [NSDateFormatter initWithDateFormat:#"yyyy-MM-dd"];
[df setDateFormat:#"EEEE d"];
NSString *createdDate = [df stringFromDate:creationDate];
NSString *twoDaysOld = [df stringFromDate:d];
NSLog(#"create Date----->%#, two days before date ----> %#", createdDate, twoDaysOld);
// if ([[dictAtt valueForKey:NSFileCreationDate] compare:d] == NSOrderedAscending)
if ([creationDate compare:d] == NSOrderedAscending)
{
if([file isEqualToString:#"RDRProject.sqlite"])
{
NSLog(#"Imp Do not delete");
}
else
{
[[NSFileManager defaultManager] removeItemAtPath:[kDOCSFOLDER stringByAppendingPathComponent:file] error:&error];
}
}
}
You can get the file creation date, look at this SO Post and then just compare the dates. and create two different arrays for files needs to be deleted and non to be deleted..
My two cents worth. Change meetsRequirement to suit.
func cleanUp() {
let maximumDays = 10.0
let minimumDate = Date().addingTimeInterval(-maximumDays*24*60*60)
func meetsRequirement(date: Date) -> Bool { return date < minimumDate }
func meetsRequirement(name: String) -> Bool { return name.hasPrefix(applicationName) && name.hasSuffix("log") }
do {
let manager = FileManager.default
let documentDirUrl = try manager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
if manager.changeCurrentDirectoryPath(documentDirUrl.path) {
for file in try manager.contentsOfDirectory(atPath: ".") {
let creationDate = try manager.attributesOfItem(atPath: file)[FileAttributeKey.creationDate] as! Date
if meetsRequirement(name: file) && meetsRequirement(date: creationDate) {
try manager.removeItem(atPath: file)
}
}
}
}
catch {
print("Cannot cleanup the old files: \(error)")
}
}
To find creation date of your file, you can refer to a very useful StackOverflow post:
iOS: How do you find the creation date of a file?
Refer to this post, this may help you in deleting them. You can just get a rough idea on what needs to be done for deletion of those data from Documents Directory:
How to delete files from iPhone's document directory which are older more than two days
Hope this helps you.
Here's a function that doesn't use string comparison for the dates and prefetches the modification time in the enumerator:
+ (NSArray<NSURL *> *)deleteFilesOlderThan:(NSDate *)earliestDateAllowed
inDirectory:(NSURL *)directory {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSDirectoryEnumerator<NSURL *> *enumerator =
[fileManager enumeratorAtURL:directory
includingPropertiesForKeys:#[ NSURLContentModificationDateKey ]
options:0
errorHandler:^BOOL(NSURL *_Nonnull url, NSError *_Nonnull error) {
NSLog(#"Failed while enumerating directory '%#' for files to "
#"delete: %# (failed on file '%#')",
directory.path, error.localizedDescription, url.path);
return YES;
}];
NSURL *file;
NSError *error;
NSMutableArray<NSURL *> *filesDeleted = [NSMutableArray new];
while (file = [enumerator nextObject]) {
NSDate *mtime;
if (![file getResourceValue:&mtime forKey:NSURLContentModificationDateKey error:&error]) {
NSLog(#"Couldn't fetch mtime for file '%#': %#", file.path, error);
continue;
}
if ([earliestDateAllowed earlierDate:mtime] == earliestDateAllowed) {
continue;
}
if (![fileManager removeItemAtURL:file error:&error]) {
NSLog(#"Couldn't delete file '%#': %#", file.path, error.localizedDescription);
continue;
}
[filesDeleted addObject:file];
}
return filesDeleted;
}
If you don't care about the files that got deleted you could make it return BOOL to indicate whether there were any errors, or simply void if you just want to make a best-effort attempt.
To selectively keep some of the files, either add a regular expression argument to the function that should match files to keep, and add a check for that in the while loop (seems to fit your use case best), or if there's a discrete amount of files with different patterns you could accept a NSSet with the filenames to keep and check for inclusion in the set before proceeding to the delete.
Also just mentioning this here since it might be relevant for some: The file system on iOS and OSX doesn't store mtime with greater precision than a second, so watch out for that if you require millisecond-precision or similar.
Corresponding test case to drop into your test suite if you want:
#interface MCLDirectoryUtilsTest : XCTestCase
#property NSURL *directory;
#end
#implementation MCLDirectoryUtilsTest
- (void)setUp {
NSURL *tempdir = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
self.directory = [tempdir URLByAppendingPathComponent:[NSUUID UUID].UUIDString isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager createDirectoryAtURL:self.directory
withIntermediateDirectories:YES
attributes:nil
error:nil];
}
- (void)tearDown {
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:self.directory error:nil];
}
- (void)testDeleteFilesOlderThan {
NSFileManager *fileManager = [NSFileManager defaultManager];
// Create one old and one new file
[fileManager createFileAtPath:[self.directory URLByAppendingPathComponent:#"oldfile"].path
contents:[NSData new]
attributes:#{
NSFileModificationDate : [[NSDate new] dateByAddingTimeInterval:-120],
}];
[fileManager createFileAtPath:[self.directory URLByAppendingPathComponent:#"newfile"].path
contents:[NSData new]
attributes:nil];
NSArray<NSURL *> *filesDeleted =
[MCLUtils deleteFilesOlderThan:[[NSDate new] dateByAddingTimeInterval:-60]
inDirectory:self.directory];
XCTAssertEqual(filesDeleted.count, 1);
XCTAssertEqualObjects(filesDeleted[0].lastPathComponent, #"oldfile");
NSArray<NSString *> *contentsInDirectory =
[fileManager contentsOfDirectoryAtPath:self.directory.path error:nil];
XCTAssertEqual(contentsInDirectory.count, 1);
XCTAssertEqualObjects(contentsInDirectory[0], #"newfile");
}
In Swift 3 and 4, to delete a specific file in DocumentsDirectory
do{
try FileManager.default.removeItem(atPath: theFile)
} catch let theError as Error{
print("file not found \(theError)")
}
I am currently coding an app which calls a text file from a store, displays it and then increments so that the next file can be loaded when needed. I have got the base code to work by the use of a button click however I want it to be able to call the text file only when 24 hours has past since the last one was loaded effectively making it update every day.
I am trying to do this by using NSDate and NSUserDefaults to store the previous time that a file was called and then compare it to the current time, if it has been more than 24 hours increment and call the next.
However after trying to add things and change around the base code below I just cannot work out how to get it to work. I don't know if this is just because I have not had enough experience and don't know the language well enough or if I am just being a bit silly and missing something really simple.
Any help would be greatly appreciated.
NSDate *nowDate = [NSDate date];
[[NSUserDefaults standardUserDefaults] setObject:nowDate forKey:#"LastLoaded"];
NSDate *lastLoaded = [[NSUserDefaults standardUserDefaults] objectForKey:#"LastLoaded"];
NSDate *checkDate = [NSDate dateWithTimeIntervalSinceNow:-24*60*60];
if([lastLoaded compare:checkDate] == NSOrderedAscending) {
static int number = 1;
NSString *filePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%i",number++] ofType:#"txt"];
if (filePath) {
NSString *textFromFile = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
if (textFromFile) {
textView.text = textFromFile;
}
}
}
There is a bug in your code. You are not retrieving the last update date from NSUserDefaults. You are retrieving the current date, as you are overwriting the LastUpdatedate with current date in the very second line of code.
//NSDate *nowDate = [NSDate date];
//[[NSUserDefaults standardUserDefaults] setObject:nowDate forKey:#"LastLoaded"];
NSDate *lastLoaded = [[NSUserDefaults standardUserDefaults] objectForKey:#"LastLoaded"];
//NSDate *checkDate = [NSDate dateWithTimeIntervalSinceNow:-24*60*60];
if ([lastLoaded timeIntervalSinceNow] < -24*60*60 ){
//Now you can update the NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:#"LastLoaded"];
//if([lastLoaded compare:checkDate] == NSOrderedAscending) {
static int number = 1;
NSString *filePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%i",number++] ofType:#"txt"];
if (filePath) {
NSString *textFromFile = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
if (textFromFile) {
textView.text = textFromFile;
}
}
}
I just wonder there a way to display the files in document directory with the sequence of modified date.
Welcome any comment
Thanks
interdev
NSFileManager class provides access to file's attributes.
NSFileManager* manager = [NSFileManager defaultManager];
for (NSString *path in [manager contentsOfDirectoryAtPath: documentsDirectory error:nil]){
NSDictionary* modDate = [manager attributesOfItemAtPath:
[documentsDirectory stringByAppendingPathComponent:path] error:nil];
NSDate* dateModified = (NSDate*)[modDate objectForKey: NSFileModificationDate];
if (dateModified)
NSLog(#"%# .Date modified: %#", path, dateModified);
}
I was planning on writing some code whose logic was based upon testing the creation date of a particular file in my app's Documents folder. Turns out, when I call -[NSFileManager attributesOfItemAtPath:error:], NSFileCreationDate isn't one of the provided attributes.
Is there no way to discover a file's creation date?
Thanks.
The fileCreationDate is indeed part of the dictionary. Here's a method that gets passed a file URI and grabs some of the attributes from the file:
- (NSDictionary *) attributesForFile:(NSURL *)anURI {
// note: singleton is not thread-safe
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *aPath = [anURI path];
if (![fileManager fileExistsAtPath:aPath]) return nil;
NSError *attributesRetrievalError = nil;
NSDictionary *attributes = [fileManager attributesOfItemAtPath:aPath
error:&attributesRetrievalError];
if (!attributes) {
NSLog(#"Error for file at %#: %#", aPath, attributesRetrievalError);
return nil;
}
NSMutableDictionary *returnedDictionary =
[NSMutableDictionary dictionaryWithObjectsAndKeys:
[attributes fileType], #"fileType",
[attributes fileModificationDate], #"fileModificationDate",
[attributes fileCreationDate], #"fileCreationDate",
[NSNumber numberWithUnsignedLongLong:[attributes fileSize]], #"fileSize",
nil];
return returnedDictionary;
}
According to Apple's reference, NSFileCreationDate is available in 2.0+:
NSFileCreationDate The key in a file
attribute dictionary whose value
indicates the file's creation date.
The corresponding value is an NSDate
object.
Available in iPhone OS 2.0 and later.
Declared in NSFileManager.h.