In my application I want to implement a simple Alarm function. I know how to use UILocalNotifications, but I came across this source code with a like UI of the iPhone's native Clock app alarm area as well as it having a believe a type of data persistence. Two things I am not good at interface design and data persistence this source code has. But I downloaded it and started playing around with it to find the alarms are not persistent.
Download
Does anyone know how the source code can be adjusted so that it is persistent and the plist can be saved and read to and from? I am open to learning too, this area is somewhat unknown to me too. Thanks
I review your code and find issue that you not moved your "Alarms.plist" file form resource to document directory. we are not able to edit file which is in resource folder. so write following code in app delegate file.
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *theFileName = #"Alarms.plist"; //Change this appropriately
NSString *oldPath = [[NSBundle mainBundle] pathForResource:#"Alarms" ofType:#"plist"];//[NSString stringWithFormat:#"%#/Inbox/%#", documentsDirectory, theFileName];
NSString *newPath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, theFileName];
if (![[NSFileManager defaultManager] fileExistsAtPath:newPath])
[[NSFileManager defaultManager] moveItemAtPath:oldPath toPath:newPath error:nil];
Perform save operation on file which is in Document directory folder.
try this code... to save plist from bundle to Document Directory
Notice that you will have "Unable to read... " just at the first app launch
- (NSMutableArray *)displayedObjects
{
if (_displayedObjects == nil)
{
NSString *path = [[self class] pathForDocumentWithName:#"Alarms.plist"];
NSArray *alarmDicts = [NSMutableArray arrayWithContentsOfFile:path];
if (alarmDicts == nil)
{
NSLog(#"Unable to read plist file: %#", path);
NSLog(#"copy Alarms.plist to: %#", path);
NSString *pathToSetingbundle = [[NSBundle mainBundle] pathForResource:#"Alarms" ofType:#"plist"];
[[NSFileManager defaultManager]copyItemAtPath:pathToSetingbundle toPath:path error:nil];
}
_displayedObjects = [[NSMutableArray alloc]
initWithCapacity:[alarmDicts count]];
for (NSDictionary *currDict in alarmDicts)
{
Alarm *alarm = [[Alarm alloc] initWithDictionary:currDict];
[_displayedObjects addObject:alarm];
NSLog(#"#disply obj %#", alarm);
}
}
return _displayedObjects;
}
Related
Recently, I'm a senior in high school, and I'm interested in making apps for iPhone. Recently, one of my apps came out: NBlock. It's a puzzle app and it's very challenging. However, it has a few problems. The high scores are not saved. I've been told to use a plist. Any tips?
The URL based method for this:
// Get the URL for the document directory
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSURL *documentDirectoryURL = [[fileManager URLsForDocumentDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] objectAtIndex:0];
// Turn the filename into a string safe for use in a URL
NSString *safeString = [#"scores.plist" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// Create an array for the score
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:[NSNumber numberWithInt:score]];
// Write this array to a URL
NSURL *arrayURL = [NSURL URLWithString:safeString relativeToURL:documentDirectoryURL];
[array writeToURL:arrayURL atomically:YES];
I'd avoid using a plist. The easiest way to save simple data in an application, by far, is NSUserDefaults.
Check out this tutorial for a simple guide on how to use NSUserDefaults. Always be sure to synchronize NSUserDefaults when you're done writing to them.
If you're looking for a more powerful (but more complex) way to save data, check out Apple's guide to using Core Data.
Heres what you want:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"scores.plist"];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:[NSNumber numberWithInt:score]];
[array writeToFile:path atomically:YES];
And to add new scores do initWithContentsOfFile:#"scores.plist" instead of init in the declaration of array. You can optionally use NSUserDefaults.
Take a look into NSKeyedArchiver/Unarchiver. You can save pretty much anything you want; NSUserDefaults, in my experience, dumps your data if you kill your app from the tray. Core data is really used better if you're managing large amounts of data with databases such as sqlite.
I would say the below code will work and pretty straight forward unless custom object data types(Its a different story again) are used:
NSString* plistPath = nil;
NSFileManager* manager = [NSFileManager defaultManager];
if ((plistPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"PathTo.plist"]))
{
if ([manager isWritableFileAtPath:plistPath])
{
NSMutableDictionary* infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
[infoDict setObject:#"foo object" forKey:#"fookey"];
[infoDict writeToFile:plistPath atomically:NO];
[manager setAttributes:[NSDictionary dictionaryWithObject:[NSDate date] forKey:NSFileModificationDate] ofItemAtPath:[[NSBundle mainBundle] bundlePath] error:nil];
}
}
setting the date attribute might be helpful to check when is the last time score was updated.
In my iOS app I would like that user can download some jpg file via iTunes. So I've enabled UIFileSharingEnabled. But users are now able to put files in my app. I would like to block that. Is there a way to do that ?
Thanks !
Don't think you can block it, but you can just delete unwanted files when your app becomes active.
Put some code a bit like the sample below - filling in the test to avoid deleting the files you want to be available in iTunes.
Call this from within applicationDidBecomeActive: in your application delegate.
If you're more cautious you might want to check the user hasn't dropped a jpg file with the same name as the one you've parked there. You could test for sameness of date or some such or, if you've not got many files, just delete everything and write them again when the app becomes active.
- (void) removeUnwantedFiles;
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray* directoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:inboxPath error:NULL];
if (!directoryContents || [directoryContents count] == 0)
{
return;
}
for (NSString* fileName in directoryContents)
{
if ( /* some test of filename to see if it's one of my kosher files */ ) continue;
NSString* filePath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSError* error = nil;
BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
// NSLog(#"Deleting (%#): %#", success ? #"succeeded" : #"failed", [filePath lastPathComponent]);
if (!success)
{
NSLog(#"Error: %#", [error localizedDescription]);
}
}
}
As a practice, I am trying to write an app similar to the built-in notes app.
But I cannot figure out how to save the file and display it in a UITableView.
Right now, I have a UITextView that the user can type in. I also have a save button.
When the user taps the save button, I want to save it, and later have it displayed in a table view.
I am very lost so if you know of any relevant tutorials etc. it would be greatly appreciated.
As noted by the commenters in the real world, you're definitely going to want to look at Core Data or some other data persistence strategy. If you're dead set on pursuing this as a learning experience, something like this should solve your problem:
- (void)writeStringToFile:(NSString*)aString {
// Build the path, and create if needed.
NSString* filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* fileName = #"myTextFile.txt";
NSString* fileAtPath = [filePath stringByAppendingPathComponent:fileName];
if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
[[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];
}
// The main act...
[[aString dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileAtPath atomically:NO];
}
- (NSString*)readStringFromFile {
// Build the path...
NSString* filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* fileName = #"myTextFile.txt";
NSString* fileAtPath = [filePath stringByAppendingPathComponent:fileName];
// The main act...
return [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fileAtPath] encoding:NSUTF8StringEncoding] autorelease];
}
The easiest way to save text is using NSUserDefaults.
[[NSUserDefaults standardUserDefaults] setObject:theText forKey:#"SavedTextKey"];
or, if you want to have the user name each "file" or be able to have multiple files
NSMutableDictionary *saveTextDict = [[[[NSUserDefaults standardUserDefaults] objectForKey:#"SavedTextKey"] mutableCopy] autorelease];
if (saveTextDict == nil) {
saveTextDict = [NSMutableDictionary dictionary];
}
[saveTextDict setObject:theText forKey:fileName];
[[NSUserDefaults standardUserDefaults] setObject:saveTextDict forKey:#SavedTextKey"];
I am using the following code to open a file's contents and save it to another file.
when it runs the original file length is 793 but the saved file is 0. I have also tried just to copy the file. Nothing seems to work.
Is there some kind of permissions I'm missing on the documents directory?
NSError *error;
NSString *basePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* nGram = [basePath stringByAppendingPathComponent:#"contacts.gram"];
NSString *oGram = [basePath stringByAppendingPathComponent:#"/../vText.app/model/lm/TAR9230/contacts.gram"];
NSString *gramString = [[NSString alloc] initWithContentsOfFile:oGram encoding:NSUTF8StringEncoding error:&error];
BOOL ok = [gramString writeToFile:nGram atomically:NO encoding:NSUnicodeStringEncoding error:&error];
if(!ok) NSLog(#"Mayday!");
NSLog(#"%d",[gramString length]);
gramString = [[NSString alloc] initWithContentsOfFile:nGram encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%d",[gramString length]);
This entire block is unnecessary. All you need is:
NSString *fp=[[NSBundle mainBundle] pathForResource:#"contacts" ofType:#"gram"];
NSString *gramString = [[NSString alloc] initWithContentsOfFile:fp
encoding:NSUTF8StringEncoding
error:&error];
You certainly don't want to try to directly access a file in the app bundle using a hardcoded path because the file isn't guaranteed to be in the same exact place in every build.
In the code you do have, you want to use the same encoding constant for reading as you did for writing. You write with NSUnicodeStringEncoding but you read with NSUTF8StringEncoding. These should overlap but why take the chance if you know the exact coding used?
I'm writing an app that copies some contents of the bundle into the applications Document's directory, mainly images and media. I then access this media throughout the app from the Document's directory.
This works totally fine in the Simulator, but not on the device. The assets just come up as null. I've done NSLog's and the paths to the files look correct, and I've confirmed that the files exist in the directory by dumping a file listing in the console.
Any ideas? Thank you!
EDIT
Here's the code that copies to the Document's directory
NSString *pathToPublicationDirectory = [NSString stringWithFormat:#"install/%d",[[[manifest objectAtIndex:i] valueForKey:#"publicationID"] intValue]];
NSString *manifestPath = [[NSBundle mainBundle] pathForResource:#"content" ofType:#"xml" inDirectory:pathToPublicationDirectory];
[self parsePublicationAt:manifestPath];
// Get actual bundle path to publication folder
NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:pathToPublicationDirectory];
// Then build the destination path
NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%d", [[[manifest objectAtIndex:i] valueForKey:#"publicationID"] intValue]]];
NSError *error = nil;
// If it already exists in the documents directory, delete it
if ([fileManager fileExistsAtPath:destinationPath]) {
[fileManager removeItemAtPath:destinationPath error:&error];
}
// Copy publication folder to documents directory
[fileManager copyItemAtPath:bundlePath toPath:destinationPath error:&error];
I am figuring out the path to the docs directory with this method:
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
}
And here's an example of how I'm building a path to an image
path = [NSString stringWithFormat:#"%#/%d/%#", [self applicationDocumentsDirectory], [[thisItem valueForKey:#"publicationID"] intValue], [thisItem valueForKey:#"coverImage"]];
It turned out to be an issue where the bundle was not being updated on the device and apparently didn't have the same set of files that the Simulator had. This blog post helped a bit: http://majicjungle.com/blog/?p=123
Basically, I cleaned the build and delete the app and installed directly to the device first instead of the simulator. Interesting stuff.
I don't see where documentsDirectory is defined.
NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%d", [[[manifest objectAtIndex:i] valueForKey:#"publicationID"] intValue]]];
Perhaps the following will do the trick
NSString *destinationPath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:[NSString stringWithFormat:#"%d", [[[manifest objectAtIndex:i] valueForKey:#"publicationID"] intValue]]];
Your copy code looks fine, and you say you're getting no errors.
But I'm intrigued by "The assets just come up as null." Are you sure you're accessing the file name later with the exact same name?
Unlike the simulator, a real iPhone has a case sensitive file system.