Objective-C - simple setting property example erroring with 'request for ___ in something not a structure or union' - iphone

I've been banging my head with this one this evening and am sure it's something very simple that I've missed
I've created a new project with the appdelegate and a view controller class as below. The view controller synthesises the property in the .m, and the app delegate header imports the view controller .h file. Code below:
View controller header:
#interface untitled : UIViewController {
NSString *string;
}
#property (nonatomic, retain) NSString *string;
App delegate:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
testViewController = [[untitled alloc] initWithNibName:#"untitled" bundle:nil];
testViewController.string = #"Testing String";
[window addSubview:testViewController.view];
[window makeKeyAndVisible];
}
Can someone please help and point out the obvious mistake as to why setting the string property fails here with the error mentioned? Is it because of being inside this method? I've never had issues setting properties in other methods before after initing a view controller.
Thanks.

The error is saying it does not understand that the class has that property. It means you have either the wrong class or that it knows nothing about the class.
So, you need to add:
#import "untitled.h"
in your application delegate - also, you need to have the variable be of type "untitled" (I am pretty sure you declared the type as UIViewController and not untitled):
untitled * testViewController = (untitled *)[[untitled alloc] initWithNibName:#"untitled" bundle:nil];
By the way, by convention you should always start class names in uppercase.

Related

How to access values from a different UIViewController

How can I access the value from an inputField located in a second viewController?
The class name of the second view controller is SettingsViewController and the outlet name for the inputField is setRateInput.
I tried this but it didn't work…
double taxRateFromInput = [[self.settings.setRateInput text]doubleValue];
when I NSLog it comes out as The value is: (null)
Any idea what I'm doing wrong?
Here is the implementation file for the main viewController:
#import "SettingsViewController.h"
#interface ViewController ()
#property (strong, nonatomic) SettingsViewController * settings;
#end
#implementation ViewController
// lazy instantiation
-( SettingsViewController *) settings
{
if (_settings == nil) {
_settings = [[SettingsViewController alloc]init];
}
return _settings;
}
- (IBAction)calculatePrice:(id)sender {
double taxRateFromInput = [[self.settings.setRateInput text]doubleValue];
#end
In theory, you could create a global. Create a new class, call it something like taxRate (.h and .m)
In taxRate.h, add the following code:
#import <Foundation/Foundation.h>
#class MyTaxRate;
#interface TaxRate : NSObject {
}
#property (nonatomic, retain) double * taxRateFromInput;
+(TaxRate*)getInstance;
#end
Then, in your controller, put a "#import taxRate.h" in there. In your .m file, add the following:
#import "TaxRate.h"
#implementation TaxRate
#synthesize taxRateFromInput;
static TaxRate *instance =nil;
+(TaxRate *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [TaxRate new];
}
}
return instance;
}
#end
Note: This is extremely similar in structure to what I'm purposing.
if you have the reference from the object view controller you can just access by the property from your attribute.
You instantiated a new SettingsViewController, but you didn't do anything to instantiate its textfield setRateInput. You can do it when you instantiate it:
_settings = [[SettingsViewController alloc]init];
_settings.setRateInput = [UITextField alloc] initWithFrame:someFrame]];
or, as a beter solution, instantiate the text field in -init of SettingsViewController
- init {
if (self = [super init] {
self.setRateInput = [UITextField alloc] initWithFrame:someFrame]];
}
return self;
}
If you use nib files, this would be a lot easier.
Note: setRateInput is a bad name for a property. Consider rateTextField instead.
Edit I forgot to add that you have to add the text field as a subview to its parent view.
So it will be like,
_settings = [[SettingsViewController alloc]init];
_settings.setRateInput = [[UITextField alloc] initWithFrame:someFrame] autorelease];
[_settings.view addSubView:_settings.setRateInput];
In this case, the setRateInput is retained by its super view. You're not using ARC, so you can call autorelease on your text field.
The better solution: Use - (void) loadView; inside SettingsViewController. Loading the view is the responsibility of the correspondent view controller.
- (void) loadView {
self.setRateInput = [[UITextField alloc] initWithFrame:someFrame] autorelease];
[self.view addSubView:_settings.setRateInput];
}
Edit: xib files and storyboards can help you out. Give these tutorials a try.
You are on the right track, also well done with your lazy instantiation (as
a demonstration that you grasped the concept, I mean).
But note, that outlets don't get connected until viewDidLoad is called. So if you
just alloc/init your viewController (lazily), the outlet to your textfield is pointing to nil.
The outlet doesnt get connected until your controller's view property is accessed, ie the view is displayed.
What you could do is give the settings viewController a handle to your calculating viewController and let it set a public property on the calculating viewController that represents the rate.
This is a common pattern - delegation - where one viewController (settingsViewcontroller) calls a method on its delegate (calculating viewController).
You wouldn't need the settingsViewcontroller property in your calculating viewController then, but just instantiate a new settings viewController every time you want it to be brought up, giving it a reference to your calculating viewController.
Another possibility - maybe even better - is to define a model object that does calculation and takes care of the rate it needs to calculate. Then you could give your settingsViewcontroller a reference to that model object (probably instantiated in your
other viewController), so that it can change the rate on it.
PS: also re think how you instantiate viewControllers generally. The designated initialiser is -initWithNibName:bundle: - so usually, you wouldn't just alloc/ -init them.
If you use storyboards (you probably should!), use storyboard's -instantiateViewControllerWithIdentifier: or use the above mentioned designated initialiser.

Accessing viewController properties from the app delegate

I am quite new to iOS programming so please be nice :) I am trying to google out this for hours now with no success. I have setup an iOS master detail project.
What i need to do. is to change a label in the detailViewController when the app calls applicationDidEnterBackground
This is my faulty code in the appdelegate applicationDidEnterBackground method
UIViewController *temp = [self.navigationController visibleViewController];
NSLog(#"%#",[temp nibName]);
if ([temp nibName] == #"DetailViewController") {
temp._lblBrewingTime = #"";
}
This doesnt work. semantic issue: lblbrewingtime not found on object of type UIViewController.
If I add a breakpoint and check the structure of the temp pointer. I can see the _lblBrewingTime type.
Can you please point me how to get the properties of whatever view is currently loaded in the app delegate?
thank you very much,
Greets,
Nick
You have to explicitly cast it to DetailViewController, once you are sure that the visibleViewController is DetailViewController actually.
So here's the fix:-
UIViewController *temp = [self.navigationController visibleViewController];
NSLog(#"%#",[temp nibName]);
if ([temp nibName] == #"DetailViewController") {
DetailViewController* tempDVCObj = (DetailViewController*)temp;
//temp._lblBrewingTime = #"";
tempDVCObj._lblBrewingTime = #"";
}
And it says absolutely correct that your property _lblBrewingTime is not the property of UIViewController, it's the property of DetailViewController i.e. a subclass of UIViewController.
Some things here:
You should keep a reference to your main controller in the AppDelegate and access the view through this reference - the visible view controller in the navigation controller may not be your view controller class, e.g. because you navigated to another view.
You access the view controller via the UIViewController interface. The UIViewController class does not know about your child view controller's properties, so it cannot access the _lblBrewingType. You have to use your view controller's class name to access its properties, e.g. MyViewController * myVc = (MyViewController*)viewController.
_lblBrewingType looks like an internal variable of your view controller. To access it from the outside, you must provide it as a property:
// MyViewController.h
#interface MyViewController : UIViewController
{
UILabel* _lblBrewingType;
}
#property (strong, nonatomic) IBOutlet UILabel *lblBrewingType;
And the implementation:
// MyViewController.m
#implementation MyViewController
#synthesize lblBrewingType;
#end

Assigning RootViewController to UIViewController gives warning - why?

I want to access the RootViewController of my App in one of its classes in order to present a modal view controller. I do this by getting the ApplicationDelegate and asking it for the RootViewController and store it in a UIViewController
AppDelegate *appDelegate = (AppDelegate *) [UIApplication sharedApplication].delegate;
UIViewController* presentingViewController = appDelegate.viewController;
In my opinion this should work without a warning as RootViewController inherits from UIViewController. However I receive this warning:
Incompatible pointer types initializing 'UIViewController *__strong' with an expression of type 'RootViewController *'
Can someone explain to me why I see this warning?
If it helps - this is the AppDelegate where I define the RootViewController:
#interface AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
RootViewController *viewController;
}
#property (strong) RootViewController *viewController;
I defined my RootViewController like this:
#interface RootViewController : UIViewController {
}
You can assign an object to a variable declared as its superclass. That is no problem and is very useful when you only want to use superclass methods over a set of your own subclasses, especially common with view controllers in a navigation stack when the specific type of next view controller is unknown.
Also think about it. Methods like
[self presentModalViewController:customController animated:YES];
wouldn't work without being able to do this. This method is declared as taking a UIViewController * but you pass in a custom UIViewController subclass with no complaints. Finally
[rootViewController isKindOfClass:[UIViewController class]];
will return YES. QED.
Have you forward declared your class RootViewController in the header for your app delegate?
i.e.
#class RootViewController;
#interface AppDelegate : NSObject <UIApplicationDelegate> {
....
Did you spell it correctly? This is a common area to mistype as xCode doesn't autocomplete forward declarations. It will then autocomplete your typo in the rest of the header file.
Did you remember to import the header file for your RootViewController into the .m file for the AppDelegate? You will still need to do that so the compiler knows about the inheretance.
Your code looks correct at the moment but we don't have all of it.
The problem is that RootViewController is not the same class as UIViewController.
In the AppDelegate, you declare viewController to be of type RootViewController. Then, in these lines:
AppDelegate *appDelegate = (AppDelegate *) [UIApplication sharedApplication].delegate;
UIViewController* presentingViewController = appDelegate.viewController;
You are creating presentingViewController, which is of type UIViewController, and setting it to an instance of RootViewController. This is the source of the error.
Fix this by using a consistent type.
Read What's the difference between the RootViewController, AppDelegate and the View Controller classes that I may create? for a nice explanation of the difference between these two types.

access a property in UIView in Viewcontroller?

I have been given a project to edit. I think this is a simple question but want to explain it in detail.I usually set up iPhone projects with interface builder and then have a view controller h and m file.
However this has been set up in a different way I am new to, the view has been coded.
The h file is a simple viewcontroller class like this:
#interface MainViewController : UIViewController
{
}
- (id)init;
#end
And then the m file has this:
#interface MainView : UIView
{
NSUinterger firstinterger;
}
- (id)initWithImages:(NSArray *)inImages;
#end
And then it has the #implementation MainView just after that with lots more code.
Further down however is where I need to add my code just after
#end
#implementation MainViewController
But I need to access the NSUinterger named first integer and I am unable to. I have tried a few ways of synthesizing etc. but I think I am doing it wrong. How I would get the value of it? I can access it in the code before the #implementation MainViewController but not after which is where I need it.
Synthesize the variable in MainView. Have an instance of the MainView in MainViewController and then you can access it by
MainView *mv = [[MainView alloc] init];
mv.firstInteger // gives you the variable.
NSUinterger firstinterger in your code shows no ';' at the end of that line, do you get compilation errors or is it just a typo in your question?

Pass variable to another view

I'm trying to set a variable in another view.
I'm in a view which I have named ProgramViewController and from here I would like to set a variable named bands in MyViewController.
I thought it would be as simple as
MyViewController *myViewController = [[MyViewController alloc] init];
myViewController.bands = #"hello world";
[myViewController release];
And in the header of MyViewController:
#interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
NSString *bands;
}
#property (nonatomic, retain) NSString *bands;
That does not work, though.
Can anyone please tell me what I am doing wrong?
EDIT:
I synthesize bands in MyViewController:
#synthesize pageNumberLabel, tableProgram, bands;
But when trying to print it with NSLog in the viewDidLoad of MyViewController I get (null)
NSLog(#"%#", bands);
You need to synthesize the bands variable in MyViewController.m
#synthesize bands;
A variable needs to be synthesize in order to use it as a public property outsize of a class in Objective-C
I solved this in another way. I managed to load the data in MyViewController instead. I was dealing with a page controller and had to populate a UITableView but had troubles loading the data.
This is solved in a completely other way now.