Update of UITextField using 'self.' Only Working on viewDidLoad - objective-c

I have an UITextField on the MainStoryboard.
It is set and linked in ViewController.h :
#property (retain, nonatomic) IBOutlet UITextField *finalTextField;
In ViewController.m I have #synthesize finalTextField; after the #implementation ViewController
In the -viewDidLoad area I can successfully update that UITextField by using the code:
self.finalTextField.text = #"99";
That works just fine.
But if I use that same code to update that same TextField anywhere else in ViewController.m I continue to get the error:
"Use of undeclared identifier 'self' "
Any ideas?

void decode(NSString* textToDecode) { ... }
is not a method, it is a "c" function and thus not a part of the class and this has no access to instance variables. Make it a method such as:
- (void)decodeText:(NSString *)text { ... }
#David Brunow's comment suggests the same thing.

Related

Unit Testing in XCode (Obj C) With MVVM

I'm testing out some MVVM pattern stuff and seem to have gotten myself confused. Hoping someone here can clarify things for me.
So, what I did was set up a project and added a class that is a subclass of NSObject and called it RootViewModel.
Gave it one method:
- (void) rootTest {
NSLog(#"Booyeah!");
}
In ViewController I imported RootViewModel and made an IBOutlet for it.
#import "ViewController.h"
#import "RootViewModel.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIButton *btnRunModel;
#property IBOutlet RootViewModel* myModel;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.myModel rootTest];
}
#end
Then in Storyboard I dragged an Object into the ViewController scene, named it RootModel and connected it to the myModel property in ViewController.
Run the app and it works as expected, Booyeah gets logged.
So now here's where I got messed up. I wanted to set up a unit test. So working in the default unit test file I imported ViewController and made it a property and instantiated it in the set up.
#import <XCTest/XCTest.h>
#import "ViewController.h"
#interface ObjectiveVMMVTests : XCTestCase
#property (nonatomic, strong) ViewController* myViewController;
#end
#implementation ObjectiveVMMVTests
- (void)setUp {
[super setUp];
self.myViewController = [[ViewController alloc] init];
}
Then I tried to create a test where I call the rootTest method.
- (void) testRootModel {
[self.myViewController.myModel rootTest];
}
But I get a compiler error saying myViewController has no property myModel. I assumed it would be there, not sure where I messed this up.
In your unit test, you are saying:
#import "ViewController.h"
That's great. So now the unit test knows that this is a class. But that is not where the myModel property is declared. It is declared in ViewController.m, making this a private property.
Move the property declaration into ViewController.h to make it public so the unit test can see it.
Like #matt said, the IBOutlet is not part of the public interface of ViewController. It's private, hidden in the implementation (.m) file.
You have at least two viable options:
Add #property IBOutlet RootViewModel* myModel; to the ViewController.h file to make it part of the public interface;
Add an interface definition to the ObjectiveVMMVTests unit test file that'll satisfy the compiler:
#interface ViewController ()
#property IBOutlet RootViewModel* myModel;
#end
The implementation of the -(RootViewModel*)myModel getter is there anyway, the compiler just needs to know that ViewController does respond to the message. (You could use performSelector if you weren't interested in the returned object.)

Objective c pass slider value to another class

I have a simple question in which i've spent a lot of time trying to resolve.
I have a viewcontroller with slider:
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UISlider *slider;
#property (nonatomic) float a;
#end
#implementation ViewController
#synthesize slider,a;
- (IBAction)valueChanged:(id)sender
{
[self setA:self.slider.value];
}
And I have another class where I want to get "A" value, which is value of slider
ViewController *vc = [[ViewController alloc]init];
NSLog(#"%f", [vc a]); //return zero
What im doing wrong?
Thanks
You're instantiating a new view controller which means it's not linking to the current VC you have running with the slider that has a changing value. You have to get a reference to the VC that has the slider and then you can get the "A" property off of it just by using dot syntax NSLog(#"%f", activeVC.a);

Change NSTextView content outside an IBAction Method

I'm trying to modify the string contents of an NSTextView object. So far I've been able to make it work with the following code.
.h file
#import "AppDelegate.h"
#interface InterfaceManager : AppDelegate {
IBOutlet NSTextView *content;
}
-(IBAction)displayOutput:(id)sender;
#property (assign) IBOutlet NSWindow *window;
#end
.m file
#import "InterfaceManager.h"
#implementation InterfaceManager
-(IBAction)displayOutput:(id)sender {
[content setString:#"This is a string"];
}
#end
which all works perfectly fine and does exactly what I want.
However I need to be able to do the same thing in a void method. Here's what I've tried.
.h file
#import "AppDelegate.h"
#interface InterfaceManager : AppDelegate {
IBOutlet NSTextView *content;
}
-(void)displayOutput:(NSString *)string;
#property (assign) IBOutlet NSWindow *window;
#end
.m file
#import "InterfaceManager.h"
#implementation InterfaceManager
-(void)displayOutput:(NSString *)string {
[content setString:string];
}
#end
and it doesn't seem to work.
What am I doing wrong and how to I fix it to make it work?
Thanks in advance! :)
If I understand you correctly, you set the text when a button is pushed, but you also want to set the text without the user pushing a button. If that it the case then you don’t need a "void method", you can use any method to do it. For example, I set the client name in my options screen when I first enter the screen using this code.
- (void)viewDidLoad {
// All games allow a client and rewards
if (self.currentClient) {
self.clientInput.text = self.currentClient;
}
}
If you want to have a separate method to set the string, I think you can use something like this:
-(void)myContentSettingMethod {
[self.content setString:#"This is a string"];
}
and then call it whenever you want to set the content.

passing data from parent to child

In my app I'm trying to pass data from the parent view to the child view. However, when I run the app the delegate method isn't being called.
Here is the code on how I implemented the custom delegate:
parent.h
#protocol SLBWallViewControllerDelegate <NSObject>
- (void) pictureToBeUploaded:(id)picture;
#end
#interface SLBWallViewController : UIViewController <UIActionSheetDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
- (IBAction)createPotButtonPressed:(id)sender;
#property (weak, nonatomic) id <SLBWallViewControllerDelegate> delegate;
#end
parent.m
[self.delegate pictureToBeUploaded:info[UIImagePickerControllerEditedImage]];//i'm taking the pic from a uiimagepicker
child.h
#interface SLBPostViewController : UIViewController <SLBWallViewControllerDelegate>
#property (weak, nonatomic) IBOutlet UIImageView *picture;
#end
child.m
#pragma mark - Wall View Controller Delegate
- (void)pictureToBeUploaded:(id)picture{
self.picture.image = picture;
}
Is there anything wrong or missing?
Well, the problem probably (edit: confirmed in the comments) is that self.delegate is nil at that point. So you send a message to nil and nothing happens of course. What you have to do is make sure that you assign a Child instance to delegate property before trying to send the message. Something like this for example:
//...
self.delegate = //.. a 'Child' instance
//...
[self.delegate pictureToBeUploaded:info[UIImagePickerControllerEditedImage]];
//(1) In Child in .h file create one property
#property (nonatomic,strong) UIImage * someImage;
//(2) In Child in .m file override the property
-(void)setSomeImage:(UIImage *)someImage{
_someImage=someImage;
self.picture.image = self.someImage;
}
//(3) In Parent in .m file set image to child's 'someImage' property
childsObject.someImage= UIImagePickerControllerEditedImage;

Delegate does not get called

I have a UIPageViewController which I setup in the viewDidLoad method of the RootViewController as follows:
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
The delegate pageViewControllerspineLocationForInterfaceOrientation is called successfully and I can set the spine accordingly.
However, I want to setup the PageViewController on a button click so I moved the code to the event handler of the button pressed event. Now the delegate is not called.
Any ideas how I can fix it?
It is some what complicated but can be achieved through the code below :
Step 1: Add below code to .h file of rootViewController.
#property (strong, nonatomic) IBOutlet UIButton *previousClick;
#property (strong, nonatomic) IBOutlet UIButton *nextClick;
Step 2: Connect them to the xib or storyboard which ever you use.
Step 3: Add two IBAction methods to .m file.
#pragma mark - IBAction Methods
- (IBAction)previousClick:(id)sender
{
[_modelController pageViewController:self.pageViewController viewControllerBeforeViewController:_dataViewController];
}
- (IBAction)nextClick:(id)sender
{
[_modelController pageViewController:self.pageViewController viewControllerAfterViewController:_dataViewController];
}
Step 4: You also need to put below lines too to .m file
#interface RootViewController ()
#property (readonly, strong, nonatomic) ModelController *modelController;
#property (readonly, strong, nonatomic) DataViewController *dataViewController;
#end
And synthesize them as below
#synthesize modelController = _modelController;
#synthesize dataViewController = _dataViewController;
Step 5: Last and final add below line to - (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation method.
_dataViewController = currentViewController;
after the currentViewController's alloc init call.
If you find that the added buttons are hidden by the pageViewController just bring them to the front using the code below in side the -viewDidLoad method
[self.view bringSubviewToFront:self.previousClick];
[self.view bringSubviewToFront:self.nextClick];