Is there a way to pass a float "byref" to a method in objective C? Here's an overview of what I've got:
method signature:
- (void) MyMethod: (float*) min max:(float*) max;
method:
- (void) MyMethod: (float*) min max:(float*) max
{
}
trying to invoke it:
float min1 = 0; float max1 = 0;
[self MyMethod: min:&min1 max:&max1];
I get the following warning, and the code abends when trying to invoke MyMethod:
warning: 'MyClass' may not respond to '+MyMethod:min:max:'
The signature for your method is declared as
- (void) MyMethod: (float*) min max:(float*) max
but you are calling it as
- MyMethod:min:max:
... which includes an extra 'min:' that's not in the declaration.
Try changing your calling code to
float min1 = 0; float max1 = 0;
[self MyMethod:&min1 max:&max1];
and see if that improves things.
However, I see that your error message complains about the signature '+ MyMethod:min:max:', which also suggests you're trying to send the message to the class rather than an instance of the class; you will have to rectify that.
Finally, method selectors in Objective-C code usually start with a lower-case letter; you might want to read up on common Objective-C naming conventions.
Related
How do you do pointers to pointers in Swift? In Objective-C I had a function which I would call recursively so that I could keep track of the number of recursions, but I'm stumped as to how to achieve this in Swift.
NSNumber *recursionCount = [NSNumber numberWithInteger:-1];
[self doRecursion:&recursionCount];
- (void)doRecursion:(NSNumber **)recursionCount {
// I'm sure this is a terrible way to increment, but I have limited Objective-C experience
// and this worked, so I moved on after failing to find a decent var++ equivalent :-(
int addThis = (int)i + 1;
*recursionCount = [NSNumber numberWithInt:[*recursionCount intValue] + addThis];
[self doRecursion:recursionCount];
}
In the process of cutting this sample down for this post, I've ended up creating a never-ending loop, but you get the idea on how I'm remembering the value with each recursion.
Does anybody know how to do this in Swift? Thanks.
Usage of pointers in swift is highly discouraged.
To change a variable passed as argument to a function, you have to pass it by reference (similar to passing its pointer) using the inout modifier. I've changed the logic of your function to stop after 10 iterations:
func doRecursion(inout recursionCount: Int) -> Int {
if (recursionCount < 10) {
++recursionCount
doRecursion(&recursionCount)
}
return recursionCount
}
Then you can call using:
var counter: Int = -1
let x = doRecursion(&counter) // Prints 10 in playground
Suggested reading: In-Out Parameters
I have a struct Position, like this:
typedef struct Position { int x, y; } Position;
How may I pass it in NSObject performSelector:withObject:afterDelay:? Like this:
Position pos;
pos.x = pos.y = 1;
[self performSelector:#selector(foo:)
withObject:pos // ERROR
afterDelay:5.0f];
EDIT: changed code to fix typo
Uhm.. use a CGPoint and something like
[self performSelector:#selector(foo:)
withObject:[NSValue valueWithCGPoint:CGPointMake(pos.x, pos.y)]
afterDelay:5.0f];
And read it again as
NSValue v;
CGPoint point = [v CGPointValue];
or leave the Position class away completely, CGPoint does the same
You could wrap your custom type using NSValue class. The error is that you didn't provide an object reference to the method.
Try using NSValue's +(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type; class method. On the other side you can retrieve the value using -(void)getValue:(void *)buffer;.
preformSelector:withObject: accepts only objects as parameters, hence you'll have to implement your foo: method to accept an object. There are two ways to pass the struct as an object:
create a struct-like object or
wrap it into NSValue and unwrap it in the method.
Full answer, based on user756245's (which doesn't tell you how to use it, not a great deal of help). Also, Apple suggests you use a slightly different method these days, IIRC:
typedef myStruct { int a; } myStruct;
myStruct aLocalPointer = ... assign to it
[self performSelector:#selector(myOtherMethod:) withObject:[NSValue value:&aLocalPointer withObjCType:#encode(myStruct)] afterDelay:0.25];
This is most likely asking for trouble, but you can pass CGPoint as id by bridging it in this way:
withObject:(__bridge id)((void *)(&point))
This will lead to a crash if point goes out of scope and your selector tries to read it, though.
I have got a Matrix-Class from which a Vector-Class is derived from and for extra functionality and better usage I've got a Vector3-Class which is derived from the Vector class. My problem is now that the Vector-class implements a function for instance +normalizeVector: which returns a new allocated Vector-instance. The subclass Vector3 should inherit these two functions but an inheritance leads to the function-prototypes that return a Vector-instance and not a Vector3-instance. This is just how inheritance works but is there a good practice how to solve that problem? A naive solution is to create Vector3 als a new class which subclasses NSObject but I want that Vector- and Vector3-instances can interact easily.
Here an code-example:
#interface Vector : NSObject {
....
}
+(Vector*) normalizeVector:(Vector*)v; //returns a new allocated Vector-instance
-(Vector*) normalize; //normalizes itself and returns itself
-(Vector*) otherFunction;
#end
#interface Vector3 : Vector {
}
-(Vector3*) specialFunction;
#end
usage of that code:
Vector3 *v3 = ...;
[[v3 normalize] specialFunction]; //Compiler gives me a warning because Vector has no specialFunction. Cast would help
[[Vector3 normalizeVector:v3] specialFunction]; //Compiler gives me a warning and during runtime it will crash because a `Vector` doesn't implement specialFunction
a cast to Vector3 would help but is not nice to work with and that also fails with the static function +normalizeVector: because in that static function a Vector-instance is allocated and a pointer-cast doesn't help.
any ideas? or other approaches / other modeling ?
edit: Code for my static function normalizeVector which gets inherited by Vector3:
#implementation Vector
...
+(Vector*) normalizeVector:(Vector *)v
{
unsigned int dim = vector_max(v.cols, v.rows);
Vector *res = [[[Vector alloc]initAsColumnVectorWithDim:dim] autorelease];
[Vector normalizeVector:v destination:res]; // this does only the logic: calc length and divide each component by the len and store at the vector passed to destination
return res;
}
#end
You will notice that -init methods always return type id -(id)init {..} exactly becauase of this.
Also, instead of [Vector alloc] - as you have noticed you don't actually know what Class you are in at runtime (it could be a subclass), so instead just use [self alloc] where self is the current Class because you are in a Class method. So, if you do [Vector3 normalizeVector:v] self is Vector3 and if you do [Vector normalizeVector:v] self is Vector.
Try adjusting your +normailzeVector: method to
+ (id)normalizeVector:(Vector *)v {
unsigned int dim = vector_max(v.cols, v.rows);
id res = [[[self alloc] initAsColumnVectorWithDim:dim] autorelease];
[self normalizeVector:v destination:res];
return res;
}
Just a note, + (id)normalizeVector: is not a function and definitely not a static function. It is a class method, it just helps to get the terms right.
In this case I would make normaliseVector an instance method. So instead of
Vector *newV = [Vector normalizeVector:v];
call
Vector *newV = [v normalizeVector];
Then you can produce a different normalizeVector for Vector and Vector3
EDIT:
For [[v3 normalize] specialFunction]; there is a problem in that normalize can sometimes return an object that specialFunction does not work on - ie it only works if v3 is a Vector3. So in this case there is extra information you have so a cast would be needed or that Vector3 normailze differs from Vector's. In this case I would produce a cover method on Vector3 to call normalize] specialFunction] so that the cast is in Vector3 specific code.
I have a random number generator (RNG) function.
-(double) generateRandomNumber
{
... do some stuff
return randomNumber;
}
I have a function that calls this random number generator function to do a task - something along the lines of
-(double) GenerateSellPrice {
double randomNumber;
randomNumber = [self generateRandomNumber];
return value*randomNumber;
}
I want to modify this so that the random number generator function is actually passed into the GenerateSellPrice function, so that I can swap in and out different RNGs for different purposes (i.e. unit testing, different ranges, etc).
How do I declare the RNG function so that it is in a form that I can pass it around (I'm assuming as a function pointer)? How do I declare the GenerateSellPrice to accept the function as a parameter? And how do I then invoke the function?
You could declare your PRNGs as Objective-C blocks and pass them around like any other object. http://www.mikeash.com/pyblog/friday-qa-2008-12-26.html has some info on the subject.
The classic Objective-C pattern would be to take a selector (SEL) and object (id) argument argument:
-(double) GenerateSellPriceWithRNG:(id)rngObject selector:(SEL)rngSelector
double randomNumber;
randomNumber = [rngObject performSelector:rngSelector];
return value*randomNumber;
}
and call it with
[self GenerateSellPrinceWithRNG:self selector:#selector(generateRandomNumber)];
Modern practice would probably take a block (double (^)()) parameter. The syntax for a block is slightly uglier, but the power it brings is useful in this scenario. You get better type-checking from the compiler and you can easily generate a block inline where convenient rather than having to write an entire class & method.
In this case you could declare
-(double) GenerateSellPriceWithRNG:(double (^)())rngBlock {
double randomNumber;
randomNumber = rngBlock();
return value*randomNumber;
}
and call it with
[self GenerateSellPriceWithRNG:^{ return [self generateRandomNumber]; }];
or with any other block that returns a double.
The easiest way to do that is to use the "selector" object. You can declare a selector by doing the following
#selector(generateRandomNumber)
Once you have a selector object, you use
SEL randomNumberFunction; // Most likely passed in as a parameter
NSObject *generatorObject;
[generatorObject performSelector:randomNumberFunction];
Worked it out using blocks. For those who want to know how I did it, I declared my RNG in my calling class (classA) as a class variable
double(^generateRandomNumber)(void) = ^{
...do stuff;
return randomNumber;
};
Then declared my function in my called class (classB)
-(double) generateSellPriceWithGenerator:(double(^)(void))generator {
double randomNumber;
randomNumber = generator();
return value*randomNumber;
}
And then simply called the function from classA like so
double (^func)(void) = generateRandomNumber;
double value = [classB generateSellPriceWithGenerator:func];
I am trying to do my own custom classes and learn C and Objective C. I'm recieving the error that there is an incompatible type for argument 1. I've defined a struct and class like this:
typedef enum {
kRedColor,
kGreenColor,
kBlueColor
} ShapeColor;
typedef struct {
int x, y, width, height;
} ShapeRect;
#interface Shape : NSObject
{
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
#end // Shape
Then I import the Shape.h file(code above) and try and create a shape like this:
id shapes[4]; // I'm different!
ShapeRect rect0 = { 0, 0, 10, 30 };
shapes[0] = [Shape new];
[shapes[0] setBounds: rect0];
I get the error that setBounds is incompatible. For some reason it isn't looking at the Shape.h class for the setBounds method and it is instead looking at the default setBounds method? Is there something I'm doing wrong? Thanks!
If there is another method called setBounds: then using type id will usually result in the compiler picking the first encountered setBounds: (for determining return types and argument types), and since yours probably not the first, it is giving the error. You either need to tell the compiler that you want to use your setBounds: by changing the type from id to Shape *, but you can also cast your id to a Shape * and it should work also:
[(Shape *)shapes[0] setBounds:rect0];
With your code, shapes[0] is just an id, for which the compile does not know there is setBounds:.
Instead, you should declare shapes as
Shape* shapes[4];
By the way, if you had an error, please post exactly what error was spit out by the compiler, not just saying '... was incompatible', because there are many ways in which a thing can be incompatible! Writing it down explicitly would help people here answering your question, because that way we don't have to guess exactly what has happened. Eventually, you yourself would become able to understand from the error message what is going wrong.