Saving Automatically in NSStrings - ios

I have three text fields: first name, last name, and age, also a photo. What can I do so that the information saves automatically, so that i dont have to click a button?
This is my ViewController.h:
#import <UIKit/UIKit.h>
#interface ContactViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate> {
IBOutlet UIImageView *contactImageView;
IBOutlet UITextField *firstNameTextField;
IBOutlet UITextField *lastNameTextField;
IBOutlet UITextField *ageTextField;
}
- (IBAction)save:(id)sender;
- (IBAction)chooseImage:(id)sender;
#end
This is my ViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *frontName = [defaults objectForKey:#"firstname"];
NSString *lastName = [defaults objectForKey:#"lastname"];
int age = [defaults integerForKey:#"age"];
NSString *ageString = [NSString stringWithFormat:#"%i",age];
NSData *imageData = [defaults dataForKey:#"image"];
UIImage *contactImage = [UIImage imageWithData:imageData];
firstNameTextField.text = frontName;
lastNameTextField.text = lastName;
ageTextField.text = ageString;
contactImageView.image = contactImage;
}
- (void)viewDidUnload {
[contactImageView release];
contactImageView = nil;
[firstNameTextField release];
firstNameTextField = nil;
[lastNameTextField release];
lastNameTextField = nil;
[ageTextField release];
ageTextField = nil;
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)save:(id)sender {
[firstNameTextField resignFirstResponder];
[lastNameTextField resignFirstResponder];
[ageTextField resignFirstResponder];
// Create strings and integer to store the text info
NSString *frontName = [firstNameTextField text];
NSString *lastName = [lastNameTextField text];
int age = [[ageTextField text] integerValue];
UIImage *contactImage = contactImageView.image;
NSData *imageData = UIImageJPEGRepresentation(contactImage, 100);
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:frontName forKey:#"firstname"];
[defaults setObject:lastName forKey:#"lastname"];
[defaults setInteger:age forKey:#"age"];
[defaults setObject:imageData forKey:#"image"];
[defaults synchronize];
NSLog(#"Data saved");
}
- (IBAction)chooseImage:(id)sender {
UIImagePickerController *picker = [[[UIImagePickerController alloc] init] autorelease];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:picker animated:YES];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
contactImageView.image = image;
[picker dismissModalViewControllerAnimated:YES];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[picker dismissModalViewControllerAnimated:YES];
}

you will have to work with the <UITextFieldDelegate> protocol
Reference: UITextFieldDelegate Protocol
you will have to set
textField.delegate = yourViewController
and can then work with the protocol functions, that handle input and character changing of your textview.
for example you cound use
- (BOOL)textFieldShouldReturn:(UITextField *)textField
to save the textfield content when the user presses the return button =)
EDIT: probably this method is better suited for your needs - i was a bit tired yesterday when writing the post =)
- (void)textFieldDidEndEditing:(UITextField *)textField {
//save your textfied.text string here :)
}

You need to set the delegate of the UITextfield to the view controller in your viewDidLoad method like
firstNameTextField.delegate = self;
lastNameTextField.delegate = self;
ageTextField.delegate = self;
Your view controller needs to implement the UITextFieldDelegate Protocol method:
- (void)textFieldDidEndEditing:(UITextField *)textField {
//Do save Operations here
}
This will save only after the text is done editing. If you want to save as the user is typing, use
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *stringToSave=[textField.text stringByReplacingCharactersInRange:range withString:string];
//Identify text field by comparing textField with you text fields and do save operations
return YES;
}

Related

Why wont my UITextField save?

When my UITextView places a line of text into my first UITextField i cant save the text it holds.
Heres my code, this is to move the information from a textview
-(IBAction)print:(id)sender {
NSLog(#"text = %#",[textView text] );
NSArray *textArray = [[textView text] componentsSeparatedByString:#"\n"];
if (textArray.count > 0) {
NSString *line1 = textArray[0];
[myTextField setText:line1];
if (textArray.count > 1) {
NSString *line2 = textArray[1];
[myTextField1 setText:line2];
}
}
[textView setText:#""];
[textView resignFirstResponder];
}
Heres how i am currently trying to save and load the information.
- (void)viewDidLoad {
[super viewDidLoad];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[myTextField setText:[defaults valueForKey:#"textfield_text"]];
[myTextField setDelegate:self];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *defaultsKeyForTextField;
if ([textField isEqual:myTextField]) {
defaultsKeyForTextField = #"textfield_text";
}
[defaults setValue:textField.text forKey:defaultsKeyForTextField];
[defaults synchronize];
}
What seems to happen is that the text only saves when i enter in text manually.
As user TangZijian pointed out, textFieldDidEndEditing will be called when the textfield resigns first responder.
None of your code in print function do this.
Since set textfield as first responder and immediately resign it seems like a bad idea, you can move the code in textFieldDidEndEditing to print.
-(IBAction)print:(id)sender {
NSLog(#"text = %#",[textView text] );
NSArray *textArray = [[textView text] componentsSeparatedByString:#"\n"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *defaultsKeyForTextField;
if (textArray.count > 0) {
NSString *line1 = textArray[0];
[myTextField setText:line1];
defaultsKeyForTextField = #"textfield_text";
[defaults setValue:textField.text forKey:defaultsKeyForTextField];
[defaults synchronize];
if (textArray.count > 1) {
NSString *line2 = textArray[1];
[myTextField1 setText:line2];
}
}
[textView setText:#""];
[textView resignFirstResponder];
}
I think you should be using a the Editing Changed event to detect changes to your text fields value. Put this in your viewDidLoad method.
[myTextField addTarget:self
action:#selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
Then change your code to:
- (void)textFieldDidChange:(UITextField *)textField {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *defaultsKeyForTextField;
if ([textField isEqual:myTextField]) {
defaultsKeyForTextField = #"textfield_text";
}
[defaults setValue:textField.text forKey:defaultsKeyForTextField];
[defaults synchronize];
}

Saving data with NSUserDetaults and load after phone restart wont work

I managed to save an NSMutableArray in NSUserDefaults by first converting it to NSData - I dont deal with a lot of data and just want the data to be there after I switch off & on my phone - but the data does not show up in my table where I would display it. I write the NSUserDefaults back to my array upon loading. Maybe one of you has a hint...? Below the button action where I write to NSUserDefaults and the method viewDidLoad where I write NSUserDefaults to my original array (toDoitems)
- (IBAction)unwindToList:(UIStoryboardSegue *)segue
{
XYZAddToDoItemViewController *source = [segue sourceViewController];
XYZToDoItem *item = source.toDoItem;
if (item !=nil) {
[self.toDoitems addObject:item];
NSString *error;
NSData *data = [NSPropertyListSerialization dataFromPropertyList:self.toDoitems format:NSPropertyListBinaryFormat_v1_0 errorDescription:&error];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"itemArray"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self.tableView reloadData];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.toDoitems = [[NSMutableArray alloc] init];
self.toDoitems = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"itemArray"]];
}
Heres one way to do this
Add encoder decoder functions to your XYZToDoItem class
Something like this if say you had 2 strings in this class string1 and string2 :
(i havent compiled this code but you get the idea)
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.string1 forKey:#"string1"];
[aCoder encodeObject:self.string2 forKey:#"string2"];
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self)
{
self.string1 = [aDecoder decodeObjectForKey:#"string1"];
self.string2 = [aDecoder decodeObjectForKey:#"string2"];
}
return self;
}
Then when you are ready to save do the following
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.myDataArray];
[userDefaults setObject:data forKey:#"storageName"];
// To load the data from NSUserDefaults
NSData *myData = [[NSUserDefaults standardUserDefaults] objectForKey:#"storageName"];
NSArray *temp = (NSMutableArray*)[NSKeyedUnarchiver unarchiveObjectWithData:myData];
self.myDataArray = (NSMutableArray*)[temp mutableCopy];

how to load int value to the textfield and display on label on another collection view controller

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.item > 0 )
{
myNumber = indexPath.item;
NSLog(#"Item is %i", myNumber);
NSString *myNewString = [#(myNumber) stringValue];
[txt setText:myNewString];
self.datastring=txt.text;
WeddingViewController *wed=[[WeddingViewController alloc]init];
[self presentViewController:wed animated:YES completion:nil];
}
}
and in the viewDidLoad of second collection view.....
- (void)viewDidLoad
{
[super viewDidLoad];
self.lbl.text =self.datastring;
}
You could create a custom constructor (init) method for your WeddingViewController like this along with a property to hold that value:
Inside your WeddingViewController.h file, create the constructor method:
#property (nonatomic, assign) int storedIntValue;
-(id)initWithValue:(int)intValue;
Then in your implementation file, you can go:
-(id)initWithValue:(int)intValue
{
self = [super init];
if(self)
{
self.storedIntValue = intValue;
}
return self;
}
-(void)viewDidLoad
{
....
self.lbl.text = [[NSString alloc] initWithFormat:#"%d", self.storedIntValue];
}
Finally, where you push the WeddingViewController, you can go:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.item > 0 )
{
myNumber = indexPath.item;
NSLog(#"Item is %i", myNumber);
NSString *myNewString = [#(myNumber) stringValue];
[txt setText:myNewString];
self.datastring=txt.text;
// ----------------------------------------------------
// Notice use of the "initWithIntValue:" method
//
// note: is myNumber meant to be indexPath row ?
// ----------------------------------------------------
WeddingViewController *wed=[[WeddingViewController alloc] initWithValue:myNumber];
[self presentViewController:wed animated:YES completion:nil];
}
}
Otherwise, the alternative is to store that int value somewhere in your application that can be accessed globally, such as a singleton, or if it's a user defaults thing, you can use:
// save value into NSUserDefaults if it's appropriate
[[NSUserDefaults standardDefaults] setValue:[NSNumber numberWithInt:3] forKey:#"myIntValue"];
[NSUserDefaults synchronize];
// get value from NSUserDefaults
int myIntValue = [[[NSUserDefaults standardDefaults] valueForKey:#"myIntValue"] integerValue];
Does that help?
you have to do this way,you can make string property in WeddingViewController.h and acccess it in viewDidLoad direct ,
#property (nonatomic, assign) NSString dataString;
and in viewWillAppear
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.lbl.text = dataString;
}
and when make WeddingViewController object give property like this,
WeddingViewController *wed=[[WeddingViewController alloc]init];
wed.dataString = dataString;
[self presentViewController:wed animated:YES completion:nil];

Object initialized in "init" cannot be accessed in "viewDidLoad"

I have a strange issue: I load object data in "init" method. When I try to access it in the "viewDidLoad" my app crashes. Here is the code:
#interface UploadCenterViewController () {
NSMutableArray *videos;
}
#end
#implementation UploadCenterViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
if (![self loadVideos]) {
[self saveVideos];
}
}
return self;
}
-(void)saveVideos {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:videos];
[defaults setObject:encodedData forKey:#"VIDEOS"];
[defaults synchronize];
}
-(bool)loadVideos {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *encodedData = [defaults objectForKey:#"VIDEOS"];
if (encodedData) {
videos = (NSMutableArray *)[NSKeyedUnarchiver unarchiveObjectWithData:encodedData];
NSLog(#"array size: %d", [videos count]);
return true;
} else {
videos = [[NSMutableArray alloc] init];
return false;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%d", [videos count]);
}
When loading the data, the "videos" array contains an object. When accessing it in the "viewDidLoad" the entire app crashes.
Does anyone has an idea?
Declare videos as an #property and use it as self.videos everywhere. The crash is due to the fact that videos is getting released once you assign a value to it. The scope of videos is only inside that method and it can crash due to this. Since you want to use this outside that method, you need to retain it and you can use #property for this as mentioned below.
for eg:-
#interface UploadCenterViewController () {}
#property(nonatomic, strong) NSMutableArray *videos;
#end
-(void)saveVideos {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:self.videos];
[defaults setObject:encodedData forKey:#"VIDEOS"];
[defaults synchronize];
}
-(bool)loadVideos {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *encodedData = [defaults objectForKey:#"VIDEOS"];
if (encodedData) {
self.videos = (NSMutableArray *)[NSKeyedUnarchiver unarchiveObjectWithData:encodedData];
NSLog(#"array size: %d", [self.videos count]);
return true;
} else {
self.videos = [[NSMutableArray alloc] init];
return false;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%d", [self.videos count]);
}
You might want to retain the result of [NSKeyedUnarchiver unarchiveObjectWithData:encodedData].
Read the memory management rules.

How can I put data from UITextField to IBAction string

I have UITextField named textField where user can save phone number with NSUserDefaults. Then I have IBAction to call that number. How can I put to that action a number what user have been saved to UITextField?
-(IBAction)callPhone:(id)sender {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"tel:123456"]];
}
UPDATE
- (IBAction) saveBtnPresssed : (id) sender
{
myString1 = [[NSString alloc] initWithFormat:textField.text];
[textField setText:myString1];
NSUserDefaults *stringDefault = [NSUserDefaults standardUserDefaults];
[stringDefault setObject:myString1 forKey:#"stringKey"];
}
- (void)viewDidLoad
{
[textField setText:[[NSUserDefaults standardUserDefaults] objectForKey:#"stringKey"]];
[super viewDidLoad];
}
The string you are looking for is returned by:
[textField text];
If you saved that to user defaults then you can just:
-(IBAction)callPhone:(id)sender {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *phoneNumberString = [defaults objectForKey:#"key_you_saved_the_number_with"];
//... do what you need with that number here
}
EDIT:
[NSURL URLWithString:[NSString stringWithFormat:#"tel:%#"], [defaults objectForKey:#"stringKey"]];
so the resulting string should be "tel:" + the actual number from the text field instead of "tel:123456"
In your code setting the textfiled with the same string is not required.
Simply use:
(IBAction) saveBtnPresssed : (id) sender
{
myString1 = [[NSString alloc] initWithFormat:textField.text];
NSUserDefaults *stringDefault = [[NSUserDefaults standardUserDefaults] setObject:myString1 forKey:#"YOUR_KEY"];
}
This would set the string to your defaults and you can fetch the data as
NSString *pString = [defaults objectForKey:#"YOUR_KEY"];

Resources