I've created a UITableView which works as a setting viewcontroller. this means there are different values that i would like to save. I would like to avoid creating a save button and instead just automatically update to my database. I could update every time a value has changed, but that would be a lot of update calls, since it would update every time a char has changed. Is there a smoother way to do this?
i see a lot of different bigger apps which are not using a save button, where it just saves automatically.
create one dictionary and save your all settings into that:
- (void)viewDidLoad
{
NSMutableDictionary * settingsDictionary = [[NSMutableDictionary allo]init];
}
create one method to save settings into created dictionary
-(void)saveSettingValues:(NSString *)setting forKey:(NSString *)key
{
[settingsDictionary addObjectForKey:key];
}
call this method on every element status change.for example if textfield value is changed then by using textField delegate method send the value into dictionary
-(void)textFieldDidEndEditing:(UITextField *)textField
{
[self saveSettingValues:textField.text forKey:yorKey];
}
then send the dictionary where do you want to store the setting values on every call of saveSettingValues:forKey method
I'm not sure to understand well your problem but for me you could save data when the viewController will be remove of the screen (application in background or viewcontroller pop).
Related
I'm trying to change the title of a button after I call back from a notification but it doesn't respond at all. I checked it's not nil and checked the text Im' assigning and all is good. I made the property type strong instead of weak but no success.
- (void) setButtonTitleFromSelectedSearchResult:(NSNotification *)notif
{
[self popController];
self.sourceMapItem = [[notif userInfo] valueForKey:#"SelectedResult"];
NSLog(#"The Selected Result is: %#", self.sourceMapItem.name);
//Testing
NSLog(#"%#", self.fromButton); // check it's not nil
[self.fromButton setTitle:self.sourceMapItem.name];
}
With WatchKit, if a user interface element isn't currently visible, it cannot be updated. So, if you've presented another interface controller "on top", you can't update any of the presenting controller's interface elements until you've dismissed the presented controller. At that point, you can safely update the presenting controller in its willActivate method.
SushiGrass' method of passing blocks is certainly one valid approach. In my testing, however, I ended up having to manage multiple blocks, and many of the subsequent blocks reversed what earlier queued blocks had accomplished (for example, first changing a label's text to "foo", then "bar", then "foo" again. While this can work, it isn't optimal.
I'd suggest that anyone who is working on a WatchKit app takes a moment to consider how they want to account for off-screen (i.e. not-currently-visible) interface elements. willActivate is your friend, and coming up with a way to manage updates in that method is worthwhile if you're moving from controller to controller.
For what it's worth, I've encapsulated a lot of this logic in a JBInterfaceController subclass that handles a lot of this for you. By using this as a base class for your own interface controller, you can simply update your elements in the added didUpdateInterface method. Unfortunately, I haven't yet had the time to write proper documentation, but the header files and sample project should get you going: https://github.com/mikeswanson/JBInterfaceController
I'm using latest XCode 6.3 and below code working with me.
self.testBtn is bind with Storyboard and its WKInterfaceButton
I also have attached screenshot with affected result.
I'm setting initial text in - (void)willActivate
- (void)willActivate {
[super willActivate];
[self.testBtn setTitle:#"Test"];
[self performSelector:#selector(justDelayed) withObject:nil afterDelay:5.0]
}
-(void)justDelayed
{
[self.testBtn setTitle:#"Testing completed...!!"];
}
If you're using an IBOutlet for the property fromButton be sure that is connected to WKInteface on the storyboard, like below:
I solved this kind of issue by creating a model object that has a property that is a block of type () -> (Void) (in swift). I create the model object, set the action in the block that I'd like the pushing WKInterfaceController to do on completion, and finally pass that model object in the context to the pushed WKInterfaceController. The pushed WKInterfaceController holds a reference to the model object as a property and calls it's completion block when it's done with whatever it needs to do and after func popController().
This worked for me for patterns like what you are describing along with removing rows on detail controller deletion, network calls, location fetches and other tasks.
You can see what I'm talking about here: https://gist.github.com/jacobvanorder/9bf5ada8a7ce93317170
What's the difference between declaring a UIButton in Xcode like this:
- (IBAction)testButton;
and declaring a button like this:
- (IBAction)testButton:(id)sender;
I understand that in the .m file you would then implement the buttons accordingly, as shown below:
- (IBAction)testButton
{
// insert code here..
}
and setting it up like this:
- (IBAction)testButton:(id)sender
{
// insert code here..
}
Is there any additional things you can do by declaring the button with :(id)sender, is there some additional stability, or is there no difference?
With :(id)sender you are able to access the button itself through the sender variable. This is handy in many situations. For example, you can have many buttons and give each a tag. Then use the [sender tag] method to find which button was tapped if many buttons are using this IBAction.
- (IBAction)someMethod:(id)sender {
// do stuff
}
Using (id)sender, you have a reference to who sent the method call. Please note, this doesn't have to be limited to a UIButton.
If you're created this method via control-dragging from the storyboard an only hooking up a single button, then sender is basically useless (it will always be the same), and should probably be marked as unused:
#pragma unused (sender)
(The compiler can better optimize your code if you do this.)
However, there's nothing wrong with hooking up several UI elements to the same IBAction method. You can then distinguish the sender via:
[sender tag]
...which returns an int that was either set via the storyboard or programmatically.
Moreover, you can call this method elsewhere in your class. You can either pass nil as the sender, or you can pass it a particular UI element in order to force it into the results you've coded for objects of that tag.
Nonetheless, if you plan to call the method with a nil argument, you can always throw:
if(!sender)
... into the method in order to handle special logic for when the method has been invoked programmatically as opposed to via user interaction.
It allows you to know which button you are working with. I have posted a simple example for a card game below
- (IBAction)flipCard:(id)sender {
[self.game flipCardAtIndex:[self.cardButtons indexOfObject:sender]];
self.flipCount++;
[self updateUI];
}
This method is used for a card flipping game. There are multiple buttons on the screen representing different cards. When you hit the button, a card in the model must be flipped. We know which one by finding the index of the variable sender
Consider an Core Data entity with two properties: text and -for the sake of simplicity- textLength. textLength is a property that is calculated every time text changes. I have three requirements:
Update textLength every time text changes, ideally inside the NSManagedObject subclass.
textLength cannot be calculated on demand for performance reasons (the actual calculated property that I'm using is much more expensive to calculate).
Update the UI every time text changes.
My solution is almost there. I'm providing a custom accessor for setText:, like this:
- (void)setText:(NSString *)text
{
static NSString *key;
if (!key) key = NSStringFromSelector(#selector(text));
[self willChangeValueForKey:key];
[self setPrimitiveText:text];
self.textCount = text.count;
[self didChangeValueForKey:key];
}
And using KVO in the UI to observer text changes:
[someObject addObserver:self forKeyPath:NSStringFromSelector(#selector(text)) options:NSKeyValueObservingOptionNew context:someContext];
This works fine in most cases, except when I perform undo. I take that Core Data calls setPrimiteValue:forKey: directly, and this does not trigger my calculation logic. As a consequence, when the UI is notified of the change, the textLength value is outdated.
Short of calculating textLength on demand, where should the calculation logic be?
This is the purpose of the - (void)awakeFromSnapshotEvents:(NSSnapshotEventType)flags method. It tells you the reason for the snap shot change and allows you to update computed / derived data.
(when you update the derived value you should set it using the appropriate primitive method)
I have an ipad app that has a series of viewcontrollers each with a set of uitextfields. Basically what I want to be able to do is when navigating through the different viewcontrollers, I want the text to remain in each uitextfield that has been edited. What happens now is when I leave a certain viewcontroller and come back to it, each uitextfield is empty. To fix this would I call the viewWillDisappear or viewDidDisappear methods? And if so, how would I make it save the information within each textfield?
Are you just doing modal segues? When you want to return back to the previous view, just use the [self dismissViewControllerAnimated:YES completion:nil] and everything previously filled in will still remain. It's only if you segue back to the initial view that the text will not be there anymore. However, if you need to segue back to the initial view for some reason, you can just save the text to the NSUserDefaults, and then populate the field with the value saved on viewWillAppear. It's better practice to always dismiss viewControllers rather than doing circular segues though.
You could abuse the shouldChangeCharactersInRange method and save the characters typed in so far to an extra string and restore it after switching viewcontroller.
Update
For each textfield in a view you need set up a saveString and associate it, maybe make the tag value as array index, then you could to this:
add <UITextFieldDelegate> the class' interface definition
set the delegate for each textfield to self
add this method
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *s = [textField replaceCharactersInRange:range withString:string];
NSLog(#"current textfield value '%#'", s);
// save s somwhere, e.g. to userdefaults or a DB table
return YES;
}
Now after you've switched to back to a previous view, you can restore each textfield's previous contents. I've put in the NSLog() so you can see when this method is called.
I save value that user have been entered using NSUserDefaults. All works fine and data saves and retrieves. But how can I set a default value for that UITextField? When I use
- (void)viewDidLoad
{
textField.text = #"12345";
}
or put Text in nib file doesn't work, app start with empty field.
- (IBAction) saveBtnPresssed : (id) sender
{
myString1 = [[NSString alloc] initWithFormat:textField.text];
[textField setText:myString1];
NSUserDefaults *stringDefault = [NSUserDefaults standardUserDefaults];
[stringDefault setObject:myString1 forKey:#"stringKey"];
NSLog(#"%#",myString1);
}
I wouldn't set the values yourself, XCode provides a far easier way of doing this using bindings.
The way in which this works, would be you'd set your textfield a binding, and give it a name so that it can be identified, such as 'intialTextField'. The value is then automatically stored in NSUserDefaults, and updated on application close.
In XCode, click on the textField you want to bind, then open the Inspector. Then click the Tab second from the right. This is the 'bindings' tab.
Click the drop-down arrow on the 'Value' field and check the 'Bind to User Defaults...'
In the 'Model key path', set the name you want to identify your textfield with, this can be anything you want.
Then, whenever you enter something in your TextField, it will be saved on application exit. If you need this value to be saved straight away (only in rare cases is this necessary), you can enter the following code in your application:
[yourTextField synchronize];
On application startup you can then use NSUserDefaults to re-set the value of the textfield with the identifier you set earlier.
Hope this helps!
Double click on UITextField in your storyboard and write your default value.
This works in Xcode 5.1!