How to set default text at UITextField in iOS - ios

Following is my code:
- (void)getAge:(NSString *)age getGender:(NSString *)gender getLocation:(NSString *)location getPrefAge1:(NSString *)age1 getPrefAge2:(NSString *)age2 getPrefGender:(NSString *)prefGender getPrefLocation:(NSString *)prefLocation getImage:(UIImage *)image
{
self.textFieldAge.text=age;
self.textFieldGender.text=gender;
self.textFieldLocation.text=location;
self.textFieldPrefGender.text=prefGender;
self.textFieldPrefAge1.text=age1;
self.textFieldPrefAge2.text=age2;
self.textFieldPrefLocation.text=prefLocation;
self.imageProfilePic.image=image;
}
I get these value from another viewController I want to set these textFields with the above values. Can anyone help?
I am new to iOS.
This the method where I am calling the above method :
-(IBAction)editpro:(id)sender
{
ProfileEditViewController *profileEdit= [[ProfileEditViewController alloc] initWithNibName:#"ProfileEditViewController" bundle:nil];
[profileEdit getAge:_labelAge.text getGender:_labelGender.text getLocation:_labelLocation.text getPrefAge1:_labelPrefAge1.text getPrefAge2:_labelPrefAge2.text getPrefGender:_labelPrefGender.text getPrefLocation:_labelPrefLocation.text getImage:self.profilepic.image ];
NSLog(#"Gender :%#",_labelGender.text);
[profileEdit.saveProfile setHidden:YES];
[self presentViewController:profileEdit animated:YES completion:nil];
}

Your code should work if:
Text fields are hooked up in Interface Builder or correctly initialized programmatically.
You set those properties in the main thread.

You should check the following things, your code will not work if one of these is the case or can be all too :
Text fields should be linked to their IBoutlets, that is self.textFieldAge should not be nil.
Also, the object or view controller you are calling this function of getAge, check if that object is not nil.

Related

iOS - hidden to Yes not working

I'm calling a method from another controller, but for some reason it does not work. The NSLog works fine but myButton is not showing up.
First controller .h:
-(void) buttonChange;
First controller .m
-(void)buttonChange {
myButton.hidden=NO; //this is not getting executed
NSLog(#"it's working");
}
- (void)viewDidLoad{
myButton.hidden=YES; //initially hidden
//....other codes
}
Second controller:
FirstController *theButtonInstance = [[FirstController alloc] init];
[theButtonInstance buttonChange]; //all works fine when I call this, but button is not showing up
Place this line myButton.hidden=YES; in init method of FirstController.
You're creating your instance of FirstController, but viewDidLoad hasn't run yet. Then immediately, you're setting hidden to NO. Later, viewDidLoad will be called, and it will set hidden back to YES before the view appears. You have to wait until viewDidLoad is called before you can correctly set hidden, and it won't get called right at the creation of the controller. You could do something like:
[self performSelector:#selector(buttonChange) withObject:nil afterDelay:3.0] ;
To see your button not appear then appear 3 seconds later.
If you want to create a new instance of your FirstController (what you currently do like Undo already mentioned) you don´t have to call [theButtonInstance buttonChange]; but set theButtonInstance.myButton.hidden = NO; after you created the new instance of FirstController
You can create a BOOL property in FirstViewController.h. And set that property to NO before pushing the controller. After that go to the viewDidLoad method in FirstViewController and write the if condition whether to hide or show the button based on that property. Hope that works for you. Let me know if you need code for this.

Executing code/triggering UI Elements between two viewcontrollers

I'm new to objective C and design patterns like MVC, protocols and so on but this is it:
I am trying to write an iOS app within two viewcontrollers: the first has a textview where the user can write into, and the second has a UISwitch that triggers on "Value changed" and saves a file.
If I toggle by hand the switch on the SecondViewController it will save the file and that's ok.
But I wish the file could be saved from the FirstView just when the user types a specific word, it auto-switches to the second view, and auto-activates the UIswitch and all the method already behind it.
I still can't get the two interfaces working this way. Thanks everybody in advance for helping. Cheers!
this is connected in SecondViewController.h in the storyboard
-(IBAction)toggleFileSave:(id)sender;
and it is implemented as usual...
#interface SecondViewController ()
#property (nonatomic,weak) IBOutlet UISwitch *mySaveFileSwitch;
#end
- (void) toggleFileSave:(id)sender {
// how do I execute this code when the user
// type a specific word in the first view??
}
Create a BOOL flag in your SecondViewController.
Set it when the specific word is typed and push the view controller.
In the viewDidLoad of SecondViewController check the flag condition.If it is set call the required method.
When the specific word is typed:
ViewController2 *viewController = [ViewController2 alloc]init];
viewController2.flag = YES;
[self.navigationController pushViewController:viewController2 animated:YES];
In your text field delegate (add one if it doesn't exist) add this method:
- (void)textFieldDidEndEditing:(UITextField *)textField {
/* at this point the user finished editing */
NSString *currentText = /* read text field value */
if ([currentText isEqualToString:/* the magic word */]) {
/* save the file, present a view controller, etc. */
}
}
Check UITextFieldDelegate to know the available methods, you may need more than one to get the desired behaviour.
If you want to load the second view controller in order to show the UI and the save the file you can do as サンディープ said in his or her answer:
SecondViewController *controller = [SecondViewController new]; /* init as usual */
controller.saveOnLoad = YES;
[self.navigationController pushViewController:controller animated:YES];
Then, in SecondViewController:
- (void)viewDidLoad {
if (self.saveOnLoad) {
/* save file in async block */
/* set switch on */
}
}
If you don't need to show the second view I'd move the saving functionality to its own class and use it from the first controller, showing just a confirmation message for instance.

Am I properly using delegation? If not, how should I be doing this?

So I have taken the plunge into Objective-C programming for iOS development. I have a little app that I am working on, nothing special, but something to help teach me the ropes. The problem I am having is as follows:
Currently, I have two classes. The first being
ViewController
and the second being one that I created myself called
UserDecision
The View controller shows what is on screen, and UserDecisions currently takes the information from buttons pressed on screen, and performs the proper logic on it while working with my model class. My issue is, that I have an update UI method in UserDecision which needs to update the button properties (text, visibility, etc.) in ViewController if certain events take place. Because of this, I can't user an instance of ViewController because I won't be able to access the buttons on screen. So for this I created a delegate system:
#protocol updateUIDelegate <NSObject>
-(void)hideAll;
-(void)makeBackVisible;
-(void)updateOutput:(NSString *)output;
-(void)updateChoices:(NSString *)choices;
-(void)updateTrueButton:(NSString *)trueString;
-(void)updateFalseButton:(NSString *)falseString;
-(void)removeChoiceFromArray;
#end
The above protocol is defined in UserDecision.h, and then I assigned my ViewController as my delegate:
#interface ViewController : UIViewController <updateUIDelegate>;
And then I flush out said methods in my ViewController.m:
#pragma - updateUIDelegates -
//Called when the last screen is displayed
-(void)hideAll{
[_trueButton setHidden:true];
[_falseButton setHidden:true];
[_choicesText setHidden:true];
[_backButton setHidden:true];
[_resetButton setHidden:false];
}
//Makes back button visible
-(void)makeBackVisible{
[_backButton setHidden:false];
}
//Updates the text on the false button
-(void)updateFalseButton:(NSString *)falseString{
[_falseButton setTitle:falseString forState:UIControlStateNormal];
}
//Updates the text on the true button
-(void)updateTrueButton:(NSString *)trueString{
[_trueButton setTitle:trueString forState:UIControlStateNormal];
}
//Updates the output text box
-(void)updateOutput:(NSString *)output{
[_outputText setText:output];
}
//Updates the choices textbox
-(void)updateChoices:(NSString *)choices{
if(!choicesArray){
choicesArray = [[NSMutableArray alloc] initWithCapacity:4];
}
//If this is the first button press, add string to array and display
if([_choicesText.text isEqualToString:#""]){
[choicesArray addObject:choices];
_choicesText.text = [NSString stringWithFormat:#"%#", choices];
}
//Otherwise, add the new string to the array, and print the array
//using a comma as a way to concatinate the string and get rid of
//the ugly look of printing out an array.
else{
[choicesArray addObject:choices];
[_choicesText setText:[NSString stringWithFormat:#"%#",[choicesArray componentsJoinedByString:#", "]]];
}
}
//Removes the last choice from the array
-(void)removeChoiceFromArray{
[choicesArray removeLastObject];
[_choicesText setText:[NSString stringWithFormat:#"%#", [choicesArray componentsJoinedByString:#","]]];
}
This allows me to call theses methods by sending them as a message to self.delegate in my UserDecision class when needed.
This is my current setup. My issue has become that I want to create a modal seque view that pops up at the end (after a user presses a button to bring up the view), and which can be dismissed afterward. The problem I have is that this view, from the reading and research I have done online, can only be dismissed through delegation, unless I want things to get nasty. Now, I tried to implement this information in my class, but then I read that a class can only be a delegate to one other class. And since my ViewController(which is my main window) is already a delegate of my UserDecision class, I can't make it a delegate of the new View I have created, and thus can't dismiss the view. So, I am here to ask for your help. How can I go about solving this issue?
Also, for more of my code, should you want to have a look, here is a link to my gitHub: https://github.com/Aghassi/Xcode/tree/master/Bubble%20Tea%20Choice/Bubble%20Tea%20Choice
I read that a class can only be a delegate to one other class. And
since my ViewController(which is my main window) is already a delegate
of my UserDecision class, I can't make it a delegate of the new View I
have created
I don't believe that's true. You can make ViewController implement many different protocols, therefore being delegates to different classes/objects.
For example: (UITableViewDelegate and UITextViewDelegate can both be implemented on the same ViewController for 2 separate objects (UITextView and UITableView).
As for using delegation to close modal windows, another option is to use blocks as well.
It is possible for a viewController to dismiss itself. Just hook up a dismiss button to a function that calls something like:
[self.presentingViewController dismissViewControllerAnimated:YES];
or
[self.navigationController popViewControllerAnimated:YES];
Dismissal can be done with a delegate pattern but it is not required for everything.
You viewController class can be a delegate of multiple objects so it should be able to dismiss the modal view. The only issue is if its a delegate of multiple objects of the same class you may need to check which object is calling it.
Look at the tableView delegate methods as an example, the tableView calls them passing itself as the first parameter.
To dismiss a custom modal view you would define a different protocol anyway so there would be no problem with calling the same method.
See example below:
#protocol OSImageViewControllerProtocol <NSObject>
- (void)dismissImageViewer;
#end
#implementation OSImageViewController
- (void)loadView
{ //LOG(#"loadView called");
scrollView = [[ImageScrollView alloc] init];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewDoubleTapped:)];
doubleTapRecognizer.numberOfTapsRequired = 2;
doubleTapRecognizer.numberOfTouchesRequired = 1;
[scrollView addGestureRecognizer:doubleTapRecognizer];
self.view = scrollView;
}
- (BOOL)prefersStatusBarHidden {
return NO;
}
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer {
//LOG(#"scrollViewDoubleTapped called");
[self.delegate dismissImageViewer];
}
#end
#implementation ViewController
-(void)browseImage:(UIImage*)image
{
OSImageViewController *_imageViewerController = [[OSImageViewController alloc] init];
UIImage *img = [[UIImage alloc] initWithData:UIImagePNGRepresentation(image)];
_imageViewerController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
_imageViewerController.modalPresentationStyle = UIModalPresentationFullScreen;
_imageViewerController.delegate = self;
[self presentViewController:_imageViewerController animated:YES completion:^(void){
[_imageViewerController setImage:img];
}];
}
- (void)dismissImageViewer {
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
I believe you want to display a modal view from your ViewController.
Let the the modal view be managed by say ViewController2. In ViewController2.h declare a protocol of ViewController2
#protocol viewController2Delegate
-(void)dismissViewController2;
#end
Now make ViewController implement this protocol
#interface ViewController : UIViewController <updateUIDelegate,viewController2Delegate>
Add the method to the ViewController.m
-(void)dismissViewController2
{
[self dismissViewControllerAnimated:YES completion:nil];
}
Now whenever you push a modal view(managed by ViewController2) from ViewController you set the delegate to self. Your ViewController.m code might look like this
ViewController2 *objViewController2 = [[ViewController2 alloc]init];
objViewController2.delegate = self;
[self presentViewController:objViewController2 animated:YES completion:nil];
Hope this solves your problem
COMMUNICATION PATTERNS
Delegation is one of the communication patterns that more or less loosely coupled objects use to communicate each other. iOS Framework provides the following patterns: KVO, Notification, Delegation, Block, Target-Action.
In general, there are cases where the choice comes down to a matter of taste. However, there are many cases that are pretty clear cut.
It's also important to note that the use of each of this patterns results in a certain level of coupling among objects involved into the communication process.
Let's focus now on Delegation, Block, Target-Action.
DELEGATION
Level of coupling (proportional to the level of mutual ignorance) : loose
It allows us to customize an object’s behaviour (decoration) and to be notified about certain events (callback). In this case, the coupling is pretty loose, because the sender only knows that its delegate conforms to a certain protocol.
Since a delegate protocol can define arbitrary methods, you can model the communication exactly to your needs. You can hand over payloads in the form of method arguments, and the delegate can even respond in terms of the delegate method’s return value. Delegation is a very flexible and straightforward way to establish some sort of blind communication between two object that should be loosely coupled for design reason. Let's think to the communication mechanism between a tableview and its dataSource delegate.
Conversely, if two objects are that tightly coupled to each other that one cannot function without the other, there’s no need to define a delegate protocol (use composition instead). In these cases, the objects can know of the other’s type and talk to each other directly. Two modern examples of this are UICollectionViewLayout and NSURLSessionConfiguration.
TARGET-ACTION
Level of coupling : very loose
Target-Action is the typical pattern used to send messages in response to user-interface events. Both UIControl on iOS and NSControl/NSCell on the Mac have support for this pattern. Target-Action establishes a very loose coupling between the sender and the recipient of the message. The recipient of the message doesn’t know about the sender, and even the sender doesn’t have to know up front what the recipient will be. In case the target is nil, the action will goes up the responder chain until it finds an object that responds to it. On iOS, each control can even be associated with multiple target-action pairs.
A limitation of target-action-based communication is that the messages sent cannot carry any custom payloads. On the Mac action methods always receive the sender as first argument. On iOS they optionally receive the sender and the event that triggered the action as arguments. But beyond that, there is no way to have a control send other objects with the action message.
BLOCK
Blocks are usually used to pass to an object a behaviour to be executed before its lifecycle end. Besides, they can also substitute delegates with a caveat relevant to the potential creation of retain cycle.
self.tableView.didSelectRowAtIndexPath = ^(NSIndexPath *indexPath) {
...
[self.tableView reloadData];
...
}
In this case the sender retain the table view whose selection block retain the sender so we'd better use delegation pattern.
An example in which block communication shines:
self.operationQueue = [[NSOperationQueue alloc] init]
Operation *operation = [[Operation alloc] init];
operation.completionBlock = ^{
[self finishedOperation]
}
[operationQueue addOperation:operation];
There's a retain cycle in the above code as well, but once the queue removes the operation, the retain cycle is broken.
Blocks are a very good fit if a message we call has to send back a one-off response that is specific to this method call, because then we can break potential retain cycles. Additionally, if it helps readability to have the code processing the message together with the message call, it’s hard to argue against the use of blocks. Along these lines, a very common use case of blocks are completion handlers, error handlers, and the like.
A CHART HELPING US TO MAKE THE RIGHT CHOICE
source: objc.io
In your specific case, I'd use the target-action communication pattern to dismiss the presented modal view controller.
For example,
ModalViewController *modalViewController = [[ModalViewController alloc] init];
[self presentViewController:modalViewController animated:YES completion:^{
[modalViewController.closeButton addTarget:self action:#selector(dismissModalViewControllerAnimated:)
forControlEvents:UIControlEventTouchUpInside];
}];

Where to set a property in UIViewController

A rather basic question I'm unsure about. I typically set up my UIViewController's view-related code in viewDidLoad. If the controller has some properties for labels, etc, this is where I would initialize them and add them to the view. These properties are usually declared in the .m so can be considered pseudo-private.
However - if the controller exposes one of these properties (let's say a UILabel) in its header file, I am finding that I can't rely on it existing when it comes time to set it up. For example:
CustomViewController *controller = [CustomViewController alloc] initWithNibName:nil bundle:nil];
controller.someLabel.text = #"label text goes here";
//then comes the presentation code
I find that I am setting the label's text too early - viewDidLoad has not fired yet so the label is nil.
Should I create this label in init and add it in viewDidLoad? Should I be doing all my set up in init? Or maybe all the initialization of view properties? Or judge it on a case by case basis?
Or maybe the root cause is that I shouldn't have a controller exposing a view (the label) and use some other pattern?
I'm looking for a consistent way to structure my code.
Yeah, you are pretty much right already. The thing is, all views components of your controller are not loaded until the view is actually presented. So you cannot set anything of your IBOutlets from outside the controller.
One approach for passing, for example, a text for an UILabel, it's create a new string property, let's say self.myString, assign it from outside, and in your viewDidLoad, set in the labels' text this property.
CustomViewController *controller = [CustomViewController alloc] initWithNibName:nil bundle:nil];
controller.myString = #"label text goes here";
And inside the CustomViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
(...)
self.label.text = self.myString;
}
I tend to do something like the following, which works for me if I only want to update the view on demand (if I want to update it more frequently then I would do so in viewWillAppear or via KVO or some other notification mechanism).
Have some private method that does my UI setup based on the property:
- (void)_updateUIForProperty {
// Handle UI update
}
Implement a setter for my public property that calls the _updateUIForProperty method if the view has been loaded already:
- (void)setProperty:(<#property type#>)property {
_property = property;
if(self.isViewLoaded) {
[self _updateUIForProperty];
}
}
And then to handle the case where the property was set prior to the view loading, we do something like this in viewDidLoad:
- (void)viewDidLoad {
// Other initialization
if(_property != nil) {
[self _updateUIForProperty];
}
}

UIActivity activityViewController not dismissing on iPad

I have a UIActivity subclass that creates its own activityViewController:
- (UIViewController *)activityViewController {
WSLInProgressViewController* progressView = [[[WSLInProgressViewController alloc] init] autorelease];
progressView.message = [NSString stringWithFormat:NSLocalizedString(#"Posting to %#...",#"Posting to..."),
self.activityType];
return progressView;
}
I've add a full repro on GitHub.
According to the documentation, you aren't supposed to dismiss this manually. Instead, the OS does that when you call activityDidFinish:. This works fine when ran on an iPhone.
When I say "works," this is the sequence of events that I'm expecting (and see on the iPhone):
Display the UIActivityViewController
User presses my custom activity
My view controller appears
I call activityDidFinish:
My custom view controller is dismissed
The UIActivityViewController is also dismissed
However, when I run this same code on the iPad Simulator -- the only difference being that I put the UIActivityViewController in a popup, as the documentation says you should -- the activityViewController never dismisses.
As I say, this is code wo/the popUP works on the iPhone and I have stepped through the code so I know that activityDidFinish: is getting called.
I found this Radar talking about the same problem in iOS6 beta 3, but it seems such fundamental functionality that I suspect a bug in my code rather than OS (also note that it works correctly with the Twitter and Facebook functionality!).
Am I missing something? Do I need to do something special in the activityViewController when it's run in a UIPopoverViewController? Is the "flow" supposed to be different on the iPad?
The automatic dismissal only appears to happen when your 'activity' controller is directly presented, not wrapped in anything. So just before showing the popup it's wrapped in, add a completion handler
activity.completionHandler = ^(NSString *activityType, BOOL completed){
[self.popup dismissPopoverAnimated:YES];
};
and you'll be good.
I see the question is quite old, but we've been debugging the same view-controller-not-dismissing issue here and I hope my answer will provide some additional details and a better solution than calling up -dismissPopoverAnimated: manually.
The documentation on the UIActivity is quite sparse and while it hints on the way an implementation should be structured, the question shows it's not so obvious as it could be.
The first thing you should notice is the documentation states you should not be dismissing the view controller manually in anyway. This actually holds true.
What the documentation doesn't say, and what comes as an observable thing when you come across debugging the non-dissmissing-view-controller issue, is iOS will call your -activityViewController method when it needs a reference to the subject view controller. As it turns out, probably only on iPad, iOS doesn't actually store the returned view controller instance anywhere in it's structures and then, when it wants to dismiss the view controller, it merely asks your -activityViewController for the object and then dismisses it. The view controller instantiated in the first call to the method (when it was shown) is thus never dismissed. Ouch. This is the cause of the issue.
How do we properly fix this?
Skimming the UIActivity docs further one may stumble accross the -prepareWithActivityItems: method. The particular hint lies along the following text:
If the implementation of your service requires displaying additional UI to the user, you can use this method to prepare your view controller object and make it available from the activityViewController method.
So, the idea is to instantiate your view controller in the -prepareWithActivityItems: method and tackle it into an instance variable. Then merely return the same instance from your -activityViewController method.
Given this, the view controller will be properly hidden after you call the -activityDidFinish: method w/o any further manual intervention.
Bingo.
NB! Digging this a bit further, the -prepareWithActivityItems: should not instantiate a new view controller each time it's called. If you have previously created one, you should merely re-use it. In our case it happily crashed if we didn't.
I hope this helps someone. :)
I had the same problem. It solved for me saving activityViewController as member and return stored controller. Activity return new object and dismiss invoked on new one.
- (UIViewController *)activityViewController {
if (!self.detaisController) {
// create detailsController
}
return self.detailsController;
}
I pass through the UIActivity to another view then call the following...
[myActivity activityDidFinish:YES];
This works on my device as well as in the simulator. Make sure you're not overriding the activityDidFinish method in your UIActivity .m file as I was doing previously. You can see the code i'm using here.
a workaround is to ask the calling ViewController to perform segue to your destination ViewController via - (void)performActivity although Apple does not recommend to do so.
For example:
- (void)performActivity
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
[self.delegate performSomething]; // (delegate is the calling VC)
[self activityDidFinish: YES];
}
}
- (UIViewController *)activityViewController
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
UIViewController* vc=XXX;
return vc;
}
else
{
return nil;
}
}
Do you use storyboards? Maybe in your iPad storyboard, the UIActivityIndicatorView doesn't have a check on "Hides When Stopped"?
Hope it helps!
So I had the same problem, I had a custom UIActivity with a custom activityViewController and when it was presented modally it would not dismiss not matter what I tried. The work around I choose to go with so that the experience remained the same to the user was to still use a custom UIActivity but give that activity a delegate. So in my UIActiviy subclass I have the following:
- (void)performActivity
{
if ([self.delegate respondsToSelector:#selector(showViewController)]) {
[self.delegate showViewController];
}
[self activityDidFinish:YES];
}
- (UIViewController *)activityViewController
{
return nil;
}
Then I make the view controller that shows the UIActivityViewController the delegate and it shows the view controller that you would otherwise show in activityViewController in the delegate method.
what about releasing at the end? Using non-arc project!
[progressView release];
Many Users have the same problem as u do! Another solution is:
UIActivityIndicatorView *progress= [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(125, 50, 30, 30)];
progress.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
[alert addSubview:progress];
[progress startAnimating];
If you are using storyboard be sure that when u click on the activityind. "Hides When Stopped" is clicked!
Hope that helped...

Resources