0

So I am trying to get a callback setup in Objective-C. I am use to C++ so I keep hitting this stuff the wrong way. I found this answer and have been trying to model my code in the same way.

How to perform Callbacks in Objective-C

However when in my 'LocationActivated' function the xCoord and yCoord seem to have the complete wrong values.

delegate.mm

- (void)Initialize {
    [mWorldObj RegisterActivateDelegate: self];
}

-(void) LocationActivated :(float)xCoord :(float)yCoord {

    int a;
    a++;
    pLocation.center = CGPointMake(xCoord, yCoord);
}

delegate.h

-(void) LocationActivated :(float)xCoord :(float)yCoord;

world.h

id mActivateDelegate;

Delegate call in world.mm

        float msgarr[2];
        msgarr[0] = (float)((camera.VideoWidth() * 0.5f) + projX) + curLoc->mPopOffsetX;
        msgarr[1] = (float)((camera.VideoHeight() * 0.5f) - projY) + curLoc->mPopOffsetY;
        if(mActivateDelegate != null) {

            [mActivateDelegate LocationActivated :msgarr[0] :msgarr[1]];
        }

When calling msgarg[0] and [1] are completely valid values, ~(200, 200). But when in the callback the values are now completely different. I dumped the memory on both sides and didn't see any commonalities so my best guess is I am doing the function call totally wrong.

I also get a warning on the [mActivateDelegate LocationActivated] line saying 'Location Activated may not repsond' which makes sense because as far as the compiler knows mActiveDelegate is of type 'id'.

Any idea what I am doing wrong? Better way to approach this?

Edit:

Adding Register function from delegate.mm

- (void)RegisterActivateDelegate :(id) delegate {

    mActivateDelegate = delegate;
}
Community
  • 1
  • 1
TurqMage
  • 3,321
  • 2
  • 31
  • 52
  • 1
    I realize this isn't an answer, but PAY ATTENTION TO THAT WARNING. It means something is wrong. You should be able to call any known method on an object of type id without warning. That warning could just mean that mActivateDelegate is not actually of type id, however, in which case it probably means nothing. – Steven Fisher Apr 06 '11 at 17:50

3 Answers3

1

You asked for a better way to do it. I typed this directly into the window, so I don't know if it compiles, but this is how to approach it. Name things using ObjC conventions. This is important and will break things if you don't. Methods start with a lower-case. Name your parameters.

World.h

@protocol WorldDelegate;
@interface World : NSObject
@property (nonatomic, readwrite, assign) id<WorldDelegate> delegate;
@end

@protocol WorldDelegate <NSObject>
- (void)world:(World*)world didActivateLocation:(CGPoint)aPoint;
@end

World.mm

@implementation World
@synthesize delegate = delegate_;

- (void)dealloc {
    delegate_ = nil;
    [super dealloc];
}

...

if ([self delegate] != nil) {
    CGFloat x = ((camera.VideoWidth() * 0.5f) + projX) + curLoc->mPopOffsetX;
    CGFloat y = ((camera.VideoHeight() * 0.5f) - projY) + curLoc->mPopOffsetY;
    [[self delegate] world:self didActivateLocation:CGPointMake(x, y)];
}

WorldDelegate.h

#import "World.h"
@interface WorldDelegate : NSObject <WorldDelegate>
@property (nonatomic, readwrite, assign) World *world;
- (id)initWithWorld:(World*)aWorld;
@end

WordDelegate.mm

@interface WorldDelegate
@synthesize world = world_;
- (id)initWithWorld:(World*)aWorld {
    self = [super init];
    [aWorld setDelegate:self];
    world_ = aWorld;
    return self;
}

- (void)dealloc {
    [world_ setDelegate:nil];
    world_ = nil;
    [super dealloc];
}

- (void)world:(World*)aWorld didActivateLocation:(CGPoint)aPoint {
    int a;    // What is all this?
    a++;
    pLocation.center = aPoint;
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thanks Rob, this worked. After some poking around I found the root was my array of floats. Passing :msgarr[0] :msgarr[1] would fail, while passing a Point worked just fine. Also passing just :xFloat :yFloat also appears to work. Perhaps nesting the []'s made it unhappy. On a side note, thanks for the example of a formal protocol, I had been using an informal protocol but it seemed dangerous. – TurqMage Apr 06 '11 at 19:10
0

Edit Well, it turns out I don't actually know the answer. I thought Objective-C methods required named parameters, but in fact your method signature is valid. However, you should make your method names as descriptive as possible.

You should give your parameters names. For example, your delegate method should look like this:

- (void)locationActivatedWithX:(float)xCoord andY:(float)yCoord;

Although it's not 100% crucial, it's good style.

Cameron Spickert
  • 5,190
  • 1
  • 27
  • 34
  • 1
    I didn't downvote this, but this is not actually true. Objective-C will take anonymous parameters. However, it's VERY good advice to name them; TurqMage is fighting the flow of the language here, and that will lead to pain. This may not be THAT pain, however. – Steven Fisher Apr 06 '11 at 17:46
  • I have been trying to figure out what those names were for. So if I do function:(float)param second:(float)secondParam. The point of 'second' is to name the secondParam? If so why doesn't 'param' get name? And what is the point of the 'param' 'secondParam' name is 'second' is the name? – TurqMage Apr 06 '11 at 18:07
  • @TurqMage to be honest (and as evidenced by my uninformed response) I'm not sure why this is. I guess we'll both have to do some more reading ;) – Cameron Spickert Apr 06 '11 at 18:11
0

One issue - DON'T CHECK for == NULL. Check for == nil. Objective-C objects must be checked against "nil" meaning that yes they're a valid object but they don't reference anything. Your delegate object exists, and as an objective-c type object it has some information (like retain counts, isa pointer, etc) so it won't necessarily be NULL, but could still be nil as in not actually referencing a real object.

Also, if things are right, you won't get that warning message "'Location Activated may not repsond' ".. the compiler is smart enough to suppress those warnings on an id type, IF the method declaration does exist in an interface that you're including. Since you get the warning, that sounds fishy - like it either isn't seeing your interface declaration or what you have in that .h isn't quite right.

What does your RegisterActiveDelegate method look like? You say you did a memory dump, so the method you want truly is being called it sounds like.

Nektarios
  • 10,173
  • 8
  • 63
  • 93
  • Both `NULL` and `nil` will check for null references. – FreeAsInBeer Apr 06 '11 at 18:02
  • It is good to check against nil for type-correctness, but nil is 0, just like NULL. It isn't an empty object. If you try to dereference a pointer that does not point to a real object, you will crash. Pointers to objC objects are still just pointers. – Rob Napier Apr 06 '11 at 18:06
  • @Rob: I thought messages sent to `NULL` were ignored, meaning that no crash would result from `dealloc`'ing a null reference. – FreeAsInBeer Apr 06 '11 at 18:08
  • Yea that is a bad habit, I am writing this Objective C on top of an engine which #defines 'NULL' as 'null'. When reading the linked post earlier closer I found I needed to add "@interface NSObject(LocationActivateDelegateMethods)" block in the world.h header and that warning went away. The correct method is being called, but the parameters are the complete wrong values. – TurqMage Apr 06 '11 at 18:09
  • @FreeAsInBeer. You are correct (though you should say messages to nil, not NULL, but that's just pedantic type-correctness). It is safe to send messages to nil. What I'm talking about is Nektarios's claim about sending messages to things that aren't a real object. If you send a message to a pointer that points to deallocated memory, you will crash. It won't magically become nil for you. nil and NULL are effectively the same here; they're just different types, and it's a good idea to use the right one for clarity. – Rob Napier Apr 06 '11 at 18:15
  • @Rob: In MacTypes.h: `#ifndef NULL #define NULL 0 #endif #ifndef nil #define nil 0 #endif` – FreeAsInBeer Apr 06 '11 at 18:15
  • @Rob: Hmm... I come from a C# background, and tend to always use NULL. So far I've never noticed any issues resulting from this habituality. Is this a bad practice? – FreeAsInBeer Apr 06 '11 at 18:22
  • @FreeAsInBeer NULL means a void* pointing to 0. nil means an id pointing to 0. Mixing them obscures your meaning even if it compiles. Correct naming in ObjC is critical to avoiding bugs. Be in the habit of using names correctly because the compiler won't help you. ObjC is a language of conventions, many of them critical but unenforced, and it's often more important to understand what something really means than how it is implemented in the headers. http://stackoverflow.com/questions/557582/null-vs-nil-in-objective-c – Rob Napier Apr 06 '11 at 18:50