Passing argument makes pointer from integer without a cast - iphone

I wrote a function that looks like this:
- (void)changeText:(NSUInteger)arrayIndex;
Let's just say that's a method in the class Label. Let's say I have an array of Label objects. I call the function like this:
[[labels objectAtIndex:0] changeText:1];
or like this:
NSUInteger index = 1;
[[labels objectAtIndex:0] changeText:index];
Why does it give me the warning: Passing argument 1 of 'changeText:' makes pointer from integer without a cast? The code executes fine.
*EDIT*
Calling the function these ways does not give a warning:
[[labels objectAtIndex:0] changeText:0]; //arrayIndex is 0
Label *object = [labels objectAtIndex:0];
[object changeText:1];

More likely than not, you aren't #importing the header file containing the definition of changeText: into whatever .m file is calling it and, thus, the compiler hasn't seen the method declaration and doesn't know what the argumentation is supposed to be.
Or you have a changeText: method defined that does take an object reference as an argument and the compiler is seeing that before compiling the call site.

Somehow it thinks that changeText: takes a pointer as an argument. Probably because objectAtIndex: returns an NSObject and Objective-C doesn't know, a priori, what class's signature to apply to it.
Why don't you assign the result of objectAtIndex: to a Label*, then apply changeText: to it?
Like so:
Label* label = (Label *)[labels objectAtIndex:0];
[label changeText:1];

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.

Accessing value from array of objects

I am having two arrays, Namely
NMutableArray* first;
NMutableArray* second;
Now I am copying first object to the second array like
for (int i=0;i<first.count; i++)
{
[second addObject:[first objectAtIndex:i];
}
This is ok. I don't know how to access the value of the First Array. I tried like this ,
[second addObject:[[first objectAtIndex:i]name]];
I want to get the name value which is in the first object of first array. I tried using the above line, it is showing some warning. Please help me
Assuming you started with an array like this:
NSArray *array1 = #[#{#name : #"Fred"},
#{#name : #"Bill"}];
You could create a second array that contains the value of a given property of each element of the first array as follows:
NSArray *array2 = [array1 valueForKey:#"name"];
If you then logged the second array...
NSLog(#"%#", array2);
...the resulting output would be
2012-04-18 16:26:11.226 ExampleRunner[23320:707] (
Fred,
Bill
)
EDIT
Note that this will work regardless of whether the objects in the first array are instances of NSDictionary as shown in the example above, or instances of a class or classes that have a name property or instance variable (or an _name instance variable, for that matter). For more information on how and why this works, see the documentation for the NSKeyValueCoding informal protocol:
http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Reference/Foundation/Protocols/NSKeyValueCoding_Protocol/Reference/Reference.html
The brackets are currently in the wrong place:
[second addObject:[[first objectAtIndex:i] name]];
Updated Answer:
Again, I think you should split stuff out into easy to parse lines of code:
for (id theObject in first)
{
// without an actual type, I still think the compiler might
// throw a warning on this next line of code;
// but maybe RJR III is correct and it won't warn.
// I didn't check.
NSString * nameOfObject = [theObject name];
if(nameOfObject)
{
[second addObject:nameOfObject];
}
}
Notice that I do some error checking in here as well (i.e. making sure the name is not nil).
Original Answer:
You're getting a warning because the compiler doesn't know what kind of custom object is being fetched from your call to "[first objectAtIndex: i]". In other words, it doesn't know what kind of object you're trying to get the "name" of.
Cast it to the right type and you'll get rid of the warning.
Or even better, split that one line of multiple things happening at once into two or three lines of code and make your code more readable in the process.

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.

Why is this pointer type incompatible

This is the code
Dest.h
#import <UIKit/UIKit.h>
#import <CoreGraphics/CGPDFArray.h>
#class Model;
// snip
#interface Dest : NSObject
{
CGPDFArrayRef destArray;
DestKind kind;
}
+ (id)destWithObject:(CGPDFObjectRef)obj inModel:(Model*)model;
- (id)initWithArray:(CGPDFArrayRef)array;
Dest.m
#implementation Dest
+ (id)destWithObject:(CGPDFObjectRef)obj inModel:(PDFModel*)model
{
CGPDFArrayRef array = NULL;
Dest* dest = nil;
// stuff to create array
if (array)
{
dest = [[[Dest alloc] initWithArray:array] autorelease];
<path>/Dest.m:63: warning: passing argument 1 of 'initWithArray:' from incompatible pointer type
}
return dest;
}
Clearly the compiler thinks that array is incompatible with initWithArray: declared in Dest.h. But as far as I can see, the type is exactly right. I even copied the declaration from Dest.h and pasted it in Dest.m. initWithArray: compiles fine. Adding/removing the CGPDFArray.h header file in Dest.h doesn't make any difference, the compiler doesn't think it is an int in Dest.h.
I have a feeling you're leaving out another warning that's relevant — "warning: multiple methods named 'initWithArray:' found". If I'm right, this is what you're running into:
There are two method signatures that go with that selector. NSArray's takes an NSArray* and yours takes a CGPDFArrayRef.
alloc returns id. This means that the compiler has no idea what class it returns (yes, the compiler is that thick).
You then send initWithArray: to this mystery object. The compiler says, "Gosh, I don't know what kind of object this is, so I can't decide which method signature is correct. I'll spin around really fast and whichever one I'm facing is the one I'll pick." It chooses NSArray's signature. Then it looks at the argument and says, "Hey, that's not an NSArray! Error!"
The quick-and-easy solution is to change it to [[(Dest*)[Dest alloc] initWithArray:array] autorelease]. The better solution is to choose a distinct selector for your method.
Oh don't do that. Only CFArrayRefs are 'toll-free bridged' to NSArray. The CGPDFArrayRef however is completely different and incompatible. You can not use those as NSArrays.
The PDF API sure looks like a standard Core Foundation compatible one, but it really is not.
From Apple's documentation,
CGPDFArray header file defines an
opaque type that encapsulates a PDF
array
so it cannot be used as a NSArray.