What is the meaning of following syntax? (objective-c style method call) - iphone

I'm a noob in objective-c (from C#/Java background), and have difficulty understanding following objective-c syntax, which is used in Picker View control(and also other methods we need to implement for using Picker View):
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row
forComponent:(NSInteger)component
In order to understand, I tried to map it to the following syntax, but seems to be totally different.
-(NSString *)MethodName: (UIPickerView *)FirstParam and:(NSInteger)SecondParam
and:(NSInteger)ThirdParam
Could someone decompose the parts and give some explanation please?

It's a method named
pickerView:titleForRow:forComponent:
It returns a pointer to a NSString, and requires parameters of types UIPickerView*, NSInteger, and NSInteger.
A java-like method declaration might look like this:
NSString pickerViewTitleForRowForComponent(UIPickerView pickerView, NSInteger row, NSInteger component)

The difference is that in Objective-C the method name is composed of parts, and not a single string as in java.
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row ...
/* ^ ^ ^ ^ ^
| | | | |
Return Type | Argument Type | 2nd part of m. name etc....
| |
Part of method name Argument Name
*/

...erik aligner and bdares answers explain all
just one more thing:
the "-" minus letter at the beginning means that you can call this method with an instance of the class.
in this case the method is called by the pickerView itself (you don't call it, you just implement it in a class which adopts the UIPickerViewDelegate Protocol / meaning it use all methods required by that protocol )
but, in general, methods that start with minus sign should be called on instances.
for example, the method
- (void)addSubview:(UIView *)view
declared in UIViewClass, should be called this way:
[yourUIViewInstance addSubview:yourSubViewInstance];
while methods declared with a plus "+" sign mean that you need to call them not on instance (you may have not any instance allocated at all) but on the class itself
for example, for UIView method
+ (void)setAnimationDelay:(NSTimeInterval)delay
you should call it this way:
[UIView setAnimationDelay:1.0];

The method name (selector) is all three components: pickerView:titleForRow:forComponent:. Aside from that, you have it exactly right. (Yes, arguments and selector segments are mixed together in Objective-C. This is one of its strengths; it aids readability of long message expressions.)

Related

Why am I getting a "no visible #interface message for 'NSDecimalNumber' declares the selector" for my method?

I must be missing something simple here. Anyway, I started out by just making a regular function,
NSDecimalNumber* aa(NSMutableString *string)
{code}
which I would then call by pressing a button like so:
- (IBAction)parse:(id)sender {
string1=[NSMutableString stringWithFormat:#"%#", screen.text];
NSDecimalNumber *output=aa(string1);}
(screen.text is from a label) However, partway into it, I realized that the function can't use variables from the rest of my viewcontroller.m class (and vice-versa), so I decided to implement the function as a method instead. Here's what I did. First, I added this to viewcontroller.h,
+ (NSDecimalNumber*) aa:(NSMutableString*) string;
#property (nonatomic, strong) NSDecimalNumber *number; //the number I'm working with
synthesized my property, changed my function declaration to this,
+ (NSDecimalNumber*) aa:(NSMutableString*) string
and attempted to call it like this,
NSDecimalNumber *output=[[NSDecimalNumber alloc] aa:string1];
With that attempt, I got two errors -- "No visible #interface for 'NSDecimalNumber' declares the selector 'aa,'" and "instance variable 'number' accessed in class method."
So I tried again with an instance method. Changed the +'s to -'s and instead called the method with
NSDecimalNumber *output;
[output aa:string1];
That corrected the second error but not the first one. I can't figure out why it isn't recognizing the method in the #interface. Also, those weren't the only things I've tried changing -- I've been playing around with multiple ways to call the method, but nothing seems to work. Any ideas?
This function call:
NSDecimalNumber *output=[[NSDecimalNumber alloc] aa:string1];
..is attempting to call aa an instance of NSDecimalNumber. I don't think that's what you want, isn't your aa method a member of your class? Also, you're not calling a class initializer (although you don't need to, since your method is static so long as its definition starts with +):
// MyClass method definition
+ (NSDecimalNumber*) aa:(NSMutableString*) string
// Called with
NSDecimalNumber *output=[MyClass aa:string1];
--UPDATE--
To address the "instance variable" error, you need to make the method an instance method. Change + in definition to - and call it thusly:
// MyClass method definition
- (NSDecimalNumber*) aa:(NSMutableString*) string
// Call it like this _if calling from within MyClass only_ (hence, "self")
NSDecimalNumber *output = [self aa:string];
If you want to add methods to NSDecimalNumber, you need to use a category. Your code adds a method to your view controller subclass.

Incompatible pointer types sending 'NSString *' to parameter of type 'NSInteger *' (aka 'int *')

i have 2 file, data.h and data.m with connection db and method db.
When i implement a method i have a warning
*Incompatible pointer types sending 'NSString *' to parameter of type 'NSInteger *' (aka 'int ')
This is my code.
in data.h
- (id)initCity:(NSString *)pathDB: (NSInteger *)id_city: (NSString *)type;
- (void)getCity:(NSString *)dbPath:(NSInteger *)id_city;
in data.m
- (id)initCity:(NSString *)pathDB: (NSInteger *)id_city: (NSString *)type
{
[self getCity:pathDB: id_city: type];
return self;
}
- (void)getCity:(NSString *)dbPath : (NSInteger *)id_city : (NSString *)type { .......
......
}
and where i call my method
NSString *mystring = #"string";
dataCity = [[Data alloc] initCity: defaultDBPath: selectedItem :mystring];
NSMutableDictionary *dictionary = [dataCity objectAtIndex:0];
where wrong?
Thanks
frank
First of all NSInteger is an integer type, not an object, so you don't need a pointer.
Secondly, your method declarations are malformed. It should be something like this:
- (id)initCityWithPath:(NSString *)pathDB andId:(NSInteger)id_city andType:(NSString *)type;
- (void)getCityWithPath:(NSString *)dbPath andId:(NSInteger)id_city;
- (id)initCity:(NSString *)pathDB: (NSInteger *)id_city: (NSString *)type;
The name of this method is initCity::: which takes three parameters, pathDB, id_city and type. This is probably not what you want and probably not what anybody who has to look at your code wants. Objective-C gives you the ability to name the parameters of methods, and any method that does not name its parameters will always be suspicious1. For most Objective-C developers, initCity::: is not a good name for a method.
Secondly, initialiser methods should always start by invoking [super init] and assigning the result to self. There is seldom a reason not to do this (for example, when you are creating your own root class).
Third, your initialiser calls getCity::: (another poor name) which returns void and takes two input parameters and possibly one in/out or output parameter, this does not look like it will initialise your object properly. It is rare to see a method start with get unless it has an output parameter (e.g. getBytes:length:). In your case I think you may be using the wrong type, NSInteger is an alias for a 32-bit integer on 32-bit platforms and a 64-bit integer on 64-bit platforms. NSInteger * is therefore a pointer to such an integer. It's confusing, but this is different from NSNumber which is a class that encapsulates things like NSInteger.
No offence intended here, but from the code you provided above it seems that you lack some understanding of fundamental aspects of Objective-C. I would recommend reading a good book, following some reputable tutorials and having a look at some of Apple's example code before progressing.
1: For older runtimes, the root Object class declared in objc/Object.h had two methods called forward:: and performv:: which both contained an unnamed parameter, and these were used for message forwarding.

Creating a class whose methods can be called without an instance of an object (static class)

I'm new to objective c and i want to create a class containing certain methods that can be called in any of my other classes, mostly helper methods. im still learning the syntax and i dont know how to declare it properly
kind of like in java Integer.parseInt( );
Thanks!
Static methods in objective-c are called 'class methods' and can be declared with '+' symbol (while instance methods with '-'), e.g.:
- (void) instanceMethod;
+ (void) classMethod;
To call class method use class name:
[MyClass classMethod];
Those are called (unsurprisingly) class methods. You can declare one by using + instead of - in the method signature, e.g.
#interface MyInteger : NSObject
+ (MyInteger *)parseInt:(NSString *)str;
#end
This method is then called on the class itself, e.g. [MyInteger parseInt:#"12"].
Of course, since this is C, if your class method doesn't actually have much relation to any particular class, you could just define it as a C function instead.
NSInteger myParseInt(NSString *str);
When you see a - sign in front of a method, it's an instance method. That means you can only call that method on an instance of a class.
If you want to create a class method, all you need to do is change that - to a +.
they are called class methods. they are declared and used like this:
#interface MONClass : NSObject
+ (NSString *)convertString:(NSString *)string;
#end
in use:
NSString * converted = [MONClass convertString:string];

for loops - Object type disregarded?

I sometimes like to organize IB elements into NSArrays primarily to help me organize my elements. Most often, different classes of objects make it into the same array with each other. While this is a convenient way of organization, I can't seem to wrap my head around why if I have an array like this:
NSArray *array = [NSArray arrayWithObjects:((UITextField *)textField), ((UISegmentedController *)segmentedController), nil];
Why I get "Does not respond to selector" messages when I put a for loop like this:
for (UITextField *text in array) {
[text setText:#""];
}
The for loop seems to be passed objects that are not of class UITextField.
What is the point of declaring the object's class if all objects in the specified array are passed through the loop?
EDIT Just for reference, this is how I'm handling it as of now:
for (id *object in array) {
if ([object isMemberOfClass:[UITextField class]]) {
foo();
} else if ([object isMemberOfClass:[UISegmentedController class]) {
bar();
}
}
When you do
for (UITextField *text in...
the object pointers from the array are cast to UITextField* type - so if the object isn't actually a UITextField, all sorts of weird things may happen if you try to call UITextField methods.
So instead use the id type (no * needed, btw):
for (id obj in array)
Then check the type as you do and call the appropriate methods. Or, filter the array to get only objects of a certain type, then go though that type only:
for (UITextField* text in [array filteredArrayUsingPredicate:...])
Edit: here's how to build class filter predicates:
Is it possible to filter an NSArray by class?
What is the point of declaring the object's class if all objects in the specified array are passed through the loop?
The class name is just there to let the compiler know what it should expect to find. This allows it to try to figure out what methods it should expect you to call and how you might treat the object. It's the same idea as passing in an int to a method that takes float. The method will not ignore ints - it's assuming you're passing the correct type. You're just giving this construct a little more credit than it's due:
for (UITextField *text in array)
It just doesn't have that functionality. How you're handling it now is the correct way.
Are you sure you don't get an error when you run that code? The "does not respond to selector" message is a runtime error, not a compile time error. The compiler has no idea whether the objects in the array implement -setText:, but you should certainly get an error when you actually send that message to an instance of UISegmentedControl.
Another possibility is that you've got a class called UISegmentedController that does have a -setText: method. The name of the class that implements the multi-part bar-graph-looking user interface widget is UISegmentedControl. So either the code you're showing isn't real, tested code, or you've got a class that we don't know about.

How to know the type of a variable in Objective C on Iphone?

For example if I have a function sort() like so:
+ (void) sort: (id) a {
if(typeof(a) == 'NSArray')
{ ... }
}
So is there anything in Objective C for Iphone which can go in place of typeof() so that I can detect beforehand what kind of variable am I dealing with?
[a isKindOfClass:[NSArray class]]
Springs to mind.
I do want to point out though that in your case it makes more sense to simply type the method argument, rather than taking id and checking it's type, i.e.
+ (void)sort:(NSArray *)a
The NSObject Protocol has comparison methods that you will be interested in.