PDA

View Full Version : Methods (sub routines)




portreathbeach
Apr 5, 2011, 03:11 PM
I am writing an app where I need to update the contents of a UIPickerView (fuseTypePicker) from two different places, (when a switch is toggled and also when a different pickerView is changed). There is a lot of code, so obviously a common method is the best way.

I have tried:

void UpdateFuseValues () {

// My code is in here
}


I can call this method with:

UpdateFuseValues()


The only problem is that I cannot reference any of my UI controls in the method. I get the red error line saying "Use of undeclared identifier"

How can I get around the problem.



robbieduncan
Apr 5, 2011, 03:12 PM
Post all the relevant code.

portreathbeach
Apr 5, 2011, 03:34 PM
Well, basically here are a couple of line I want to put in the method:


void UpdateFuseValues () {

....a lot of switch, and if statements to build arrays depending on various things...

fuseRating = fusesMCB;
[fuseTypePicker reloadComponent:1];
}



fuseRating is an NSArray, so is fusesMCB. When [fuseTypePicker reloadCompnent:1] is called, the values held in the array fuseRating are loaded into component 1 of the pickerView.

If I enter these lines in viewDidLoad, they work fine, but when in the method 'void UpdateFuseValues ()' the line [fuseTypePicker reloadComponent:1]; has the "Use of undeclared identifier" error.

What's the problem

Cheers

robbieduncan
Apr 5, 2011, 03:35 PM
No good. I need to see what is in each and every .h and .m file. The real code.

portreathbeach
Apr 5, 2011, 03:41 PM
Ok, the .h file :

#import <UIKit/UIKit.h>

// this allows the RCSwitch (custom switch to be used)
#import "RCSwitchOnOff.h"


@interface CapableViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate> {

IBOutlet UIScrollView *theScroller;
IBOutlet UIPageControl *page;

IBOutlet UIPickerView *cableTypePicker;
IBOutlet UIPickerView *fuseTypePicker;

IBOutlet UISlider *ambientTempSlider;
IBOutlet UILabel *ambientTemp;

IBOutlet RCSwitchOnOff *finalCircuit;
}

@property (nonatomic, retain) UIScrollView *theScroller;
@property (nonatomic, retain) UIPageControl *page;

@property (nonatomic, retain) UIPickerView *cableTypePicker;
@property (nonatomic, retain) UIPickerView *fuseTypePicker;

@property (nonatomic, retain) UISlider *ambientTempSlider;
@property (nonatomic, retain) UILabel *ambientTemp;

@property (nonatomic, retain) IBOutlet RCSwitchOnOff *finalCircuit;

-(IBAction) ambientTempChanged: (id) sender;
-(IBAction) finalCircuitChanged;

@end


.m file:

#import "CapableViewController.h"

@implementation CapableViewController



NSArray *cableType;
NSArray *fuseType;
NSArray *fusesMCB; //holds values of MCBs
NSArray *fuses88_04; //holds values of BS88 fuses for 0.4 sec disconnection
NSArray *fuses88_5; //holds values of BS88 fuses for 5 sec disconnection
NSArray *fuses1361_04; //holds values of BS1361 fuses 0.4 sec
NSArray *fuses1361_5; //holds values of BS1361 fuses 5 sec
NSArray *fuses3036_04; //holds values of BS3036 fuses 0.4 sec
NSArray *fuses3036_5; //holds values of BS3036 fuses 5 sec

BOOL finalC; //holds yes or no depending on whether we want 0.4 sec disconnection time of not


NSArray *fuseRating; //holds the valuse of what type of fuse is chosen (fusesMCB, fuses88 etc.)



@synthesize theScroller;
@synthesize page;

@synthesize cableTypePicker;
@synthesize fuseTypePicker;

@synthesize ambientTempSlider;
@synthesize ambientTemp;

@synthesize finalCircuit;


// Removes the zeros from the end of an NSString that is passed in
NSString* removeZeros (NSString *ftotal)
{

// NSString *ftotal = [NSString stringWithFormat: @"%.2f", total];

while ([ftotal hasSuffix:@"0"]) {
ftotal = [ftotal substringToIndex: [ftotal length]-1];
}
if ([ftotal hasSuffix:@"."]) {
ftotal = [ftotal substringToIndex: [ftotal length]-1];
}


return ftotal;
}





// called when finalCircuit switch operated
-(IBAction) finalCircuitChanged
{


if ([finalCircuit isOn]) {
finalC = YES;
} else {
finalC = NO;
}


}


void UpdateFuseValues() {

fuseRating = fusesMCB;
[fuseTypePicker reloadComponent:1];


}


- (void)dealloc
{
[super dealloc];
}

- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle






// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{

// set the size of the scrolling part of the page
theScroller.contentSize = CGSizeMake(1000, 420);


// these lines stop the scroller from scrolling when using the pickers
[theScroller setDelaysContentTouches:NO];
[theScroller setCanCancelContentTouches:NO];

[super viewDidLoad];

}


@end





That's most of it

firewood
Apr 5, 2011, 03:46 PM
You are using an instance variable in what is, in essence, a class function (or a global function). You need to pass an object to this function, so it knows in what object to look for the instance variable.


void myFunction(objectType *myself, ...) {
[ myself.myButtonProperty hopUpAndDown ];
}


...
@implementation
...
- (void) someMethod {
...
myFunction(self, ...);
...
}



Methods actually work the same way, but the Objective C compiler and runtime pass this first "self" parameter in a sneaky hidden way behind your back to methods. Plain ANSI C functions, you have to do it yourself manually.

portreathbeach
Apr 5, 2011, 03:55 PM
Thanks very much, I just experimented with this in the .m file:


void UpdateFuseValues(UIPickerView *picker) {

[picker selectRow:3 inComponent:0 animated:YES];
}



// called when finalCircuit switch operated
-(IBAction) finalCircuitChanged
{

if ([finalCircuit isOn]) {
finalC = YES;
} else {
finalC = NO;
}

UpdateFuseValues(fuseTypePicker);

}


and it worked. When my switch is toggled, it calls -(IBAction) finalCircuitChanged, which then calls UpdateFuseValues and passes it the 'fuseTypePicker'.

I did notice that the method UpdateFuseValues(UIPickerView *picker) has to be coded in the file above a point at which it is called.

If I were to have a lot of methods, is it possible to put them in a different file as I think by the time my app is finished the .m file is going to be rather large.


Thanks again

robbieduncan
Apr 5, 2011, 04:01 PM
I did notice that the method UpdateFuseValues(UIPickerView *picker) has to be coded in the file above a point at which it is called.

If I were to have a lot of methods, is it possible to put them in a different file as I think by the time my app is finished the .m file is going to be rather large.

Or declared in the .h file. Depending on your code structure you can split out some methods into categories (look up the Objective-C documentation if you don't know what they are) or, if they are pure C functions instead of Objective-C methods into separate .c and .h files.

The advantage to the category approach is that you can keep a clean public interface to the object in the .h file and still have lots of extra internal methods with access to member variables. If your internal methods don't need access to the objects state you can make them pure C functions. The main advantage to that is speed: it's less expensive to call a C function than perform an Objective-C method call.

portreathbeach
Apr 6, 2011, 01:36 AM
OK, so I can reference my pickerView from within my method by passing it a picker view:

void UpdateFuseValues(UIPickerView *picker) {

but what if I want to be able to reference and change 2 or three UISwitches from inside the method, surely I wouldn't have to declare the method:

void UpdateFuseValues(UIPickerView *picker, UISwitch *one, UISwitch *two, UISwitch *three) {

would I?

Thanks in advance

dejo
Apr 6, 2011, 08:39 AM
OK, so I can reference my pickerView from within my method by passing it a picker view:

void UpdateFuseValues(UIPickerView *picker) {

but what if I want to be able to reference and change 2 or three UISwitches from inside the method, surely I wouldn't have to declare the method:

void UpdateFuseValues(UIPickerView *picker, UISwitch *one, UISwitch *two, UISwitch *three) {

would I?

Thanks in advance
If only there was some way to have variables for UI elements that are accessible throughout the instance and then connect them with their Interface Builder counterparts through some kind of outlet.

portreathbeach
Apr 6, 2011, 10:32 AM
Surely there must be an easy way. You shouldn't have to call a sub and pass four or five UI elements to it, just so the sub can access them.

robbieduncan
Apr 6, 2011, 11:08 AM
Surely there must be an easy way. You shouldn't have to call a sub and pass four or five UI elements to it, just so the sub can access them.

dejo, in his own way, has just told you the easy way. Read between the lines. Think in terms of objects. What defines an object? If you can't answer this in a pithy one sentence answer stop typing and start reading some sort of basic introduction to Object-Oriented programming.

balamw
Apr 6, 2011, 11:27 AM
Surely there must be an easy way. You shouldn't have to call a sub and pass four or five UI elements to it, just so the sub can access them.

To echo dejo and robbieduncan's posts. That statement, and even the thread title seem to imply you are not thinking objectively.

Banish subroutines from your mind when dealing with objects.

B

firewood
Apr 6, 2011, 11:49 AM
OK, so I can reference my pickerView from within my method by passing it a picker view:

void UpdateFuseValues(UIPickerView *picker) {

but what if I want to be able to reference and change 2 or three UISwitches from inside the method, ...



Then just have the object pass it itself as "self". From self you can access all the other instance variables in the object referenced by "self".

Now if the 3 switches are in 3 different objects, then you have a bigger encapsulation problem...

portreathbeach
Apr 6, 2011, 02:11 PM
Thanks for the help, but I'm not quite understanding how to pass self. I think I understand the logic of it, you pass 'self' to the method, so everything in self can be referenced in the method, but I can't work out the actual syntax to declare the method and to call it.

firewood
Apr 6, 2011, 02:51 PM
Thanks for the help, but I'm not quite understanding how to pass self. I think I understand the logic of it, you pass 'self' to the method, so everything in self can be referenced in the method, but I can't work out the actual syntax to declare the method and to call it.

Read the replies. Post #6.

portreathbeach
Apr 6, 2011, 03:35 PM
Thanks again for the help, but in post #6, it says:

void myFunction(objectType *myself, ...) {
[ myself.myButtonProperty hopUpAndDown ];
}


OK, so this method will be in my ViewController.m file and I am going to be calling the method from within my ViewController.m file. All of the things I want to reference (and change) are all in a scrollView in the View, controlled by ViewController..

So in - void myFunction(objectType *myself) , what do I put for the objectType?

In post #7 I showed how I passed the UIPicker to the method, which works well, but I want to be able to access lots of my objects in the View from within the method, and not have to pass them all to the method.

Thanks again

EDIT:

I've found a way to do what I want to do, and it seems fairly easy.

If I make a method this way:


-(IBAction) methodName {

lots of code with references to lots of different objects in my View

}


I can call this method using

[self methodName];


and everything works and I can reference everything I want from within the method.

Is this way of doing this OK? I know it works, but is this a preferred way of calling a method.